[inspector] remove iterators and for...of loops from injected-script-source

BUG=chromium:686003

Review-Url: https://codereview.chromium.org/2705533002
Cr-Commit-Position: refs/heads/master@{#43595}
This commit is contained in:
luoe 2017-03-03 11:30:40 -08:00 committed by Commit bot
parent 9ef1e35bc6
commit 3a20c322bb
8 changed files with 1035 additions and 137 deletions

View File

@ -335,12 +335,10 @@ InjectedScript.prototype = {
object = object.object;
}
var descriptors = [];
var iter = this._propertyDescriptors(object, ownProperties, accessorPropertiesOnly, undefined);
// Go over properties, wrap object values.
for (var descriptor of iter) {
if (subtype === "internal#scopeList" && descriptor.name === "length")
continue;
var descriptors = this._propertyDescriptors(object, addPropertyIfNeeded, ownProperties, accessorPropertiesOnly);
for (var i = 0; i < descriptors.length; ++i) {
var descriptor = descriptors[i];
if ("get" in descriptor)
descriptor.get = this._wrapObject(descriptor.get, objectGroupName);
if ("set" in descriptor)
@ -353,9 +351,18 @@ InjectedScript.prototype = {
descriptor.enumerable = false;
if ("symbol" in descriptor)
descriptor.symbol = this._wrapObject(descriptor.symbol, objectGroupName);
push(descriptors, descriptor);
}
return descriptors;
/**
* @param {!Array<!Object>} descriptors
* @param {!Object} descriptor
* @return {boolean}
*/
function addPropertyIfNeeded(descriptors, descriptor) {
push(descriptors, descriptor);
return true;
}
},
/**
@ -375,62 +382,72 @@ InjectedScript.prototype = {
/**
* @param {!Object} object
* @param {!function(!Array<!Object>, !Object)} addPropertyIfNeeded
* @param {boolean=} ownProperties
* @param {boolean=} accessorPropertiesOnly
* @param {?Array.<string>=} propertyNamesOnly
* @param {?Array<string>=} propertyNamesOnly
* @return {!Array<!Object>}
*/
_propertyDescriptors: function*(object, ownProperties, accessorPropertiesOnly, propertyNamesOnly)
_propertyDescriptors: function(object, addPropertyIfNeeded, ownProperties, accessorPropertiesOnly, propertyNamesOnly)
{
var descriptors = [];
descriptors.__proto__ = null;
var propertyProcessed = { __proto__: null };
var subtype = InjectedScriptHost.subtype(object);
/**
* @param {?Object} o
* @param {!Iterable<string|symbol|number>|!Array<string|number|symbol>} properties
* @param {!Object} o
* @param {!Array<string|number|symbol>=} properties
* @param {number=} objectLength
* @return {boolean}
*/
function* process(o, properties)
function process(o, properties, objectLength)
{
for (var property of properties) {
// When properties is not provided, iterate over the object's indices.
var length = properties ? properties.length : objectLength;
for (var i = 0; i < length; ++i) {
var property = properties ? properties[i] : ("" + i);
if (propertyProcessed[property])
continue;
propertyProcessed[property] = true;
var name;
if (isSymbol(property))
name = /** @type {string} */ (injectedScript._describe(property));
else
name = typeof property === "number" ? ("" + property) : /** @type {string} */(property);
if (propertyProcessed[property])
if (subtype === "internal#scopeList" && name === "length")
continue;
var descriptor;
try {
propertyProcessed[property] = true;
var descriptor = nullifyObjectProto(Object.getOwnPropertyDescriptor(o, property));
if (descriptor) {
if (accessorPropertiesOnly && !("get" in descriptor || "set" in descriptor))
continue;
if ("get" in descriptor && "set" in descriptor && name != "__proto__" && InjectedScriptHost.formatAccessorsAsProperties(object, descriptor.get) && !doesAttributeHaveObservableSideEffectOnGet(object, name)) {
descriptor.value = object[property];
descriptor.isOwn = true;
delete descriptor.get;
delete descriptor.set;
}
} else {
// Not all bindings provide proper descriptors. Fall back to the writable, configurable property.
if (accessorPropertiesOnly)
continue;
try {
descriptor = { name: name, value: o[property], writable: false, configurable: false, enumerable: false, __proto__: null };
if (o === object)
descriptor.isOwn = true;
yield descriptor;
} catch (e) {
// Silent catch.
}
descriptor = Object.getOwnPropertyDescriptor(o, property);
var isAccessorProperty = descriptor && ("get" in descriptor || "set" in descriptor);
if (accessorPropertiesOnly && !isAccessorProperty)
continue;
if (descriptor && "get" in descriptor && "set" in descriptor && name !== "__proto__" &&
InjectedScriptHost.formatAccessorsAsProperties(object, descriptor.get) &&
!doesAttributeHaveObservableSideEffectOnGet(object, name)) {
descriptor.value = object[property];
descriptor.isOwn = true;
delete descriptor.get;
delete descriptor.set;
}
} catch (e) {
if (accessorPropertiesOnly)
continue;
var descriptor = { __proto__: null };
descriptor.value = e;
descriptor.wasThrown = true;
descriptor = { value: e, wasThrown: true };
}
// Not all bindings provide proper descriptors. Fall back to the non-configurable, non-enumerable,
// non-writable property.
if (!descriptor) {
try {
descriptor = { value: o[property], writable: false };
} catch (e) {
// Silent catch.
continue;
}
}
descriptor.name = name;
@ -438,66 +455,72 @@ InjectedScript.prototype = {
descriptor.isOwn = true;
if (isSymbol(property))
descriptor.symbol = property;
yield descriptor;
descriptor = nullifyObjectProto(descriptor);
if (!addPropertyIfNeeded(descriptors, descriptor))
return false;
}
return true;
}
if (propertyNamesOnly) {
for (var i = 0; i < propertyNamesOnly.length; ++i) {
var name = propertyNamesOnly[i];
for (var o = object; this._isDefined(o); o = this._objectPrototype(o)) {
for (var o = object; this._isDefined(o); o = this._objectPrototype(/** @type {!Object} */ (o))) {
o = /** @type {!Object} */ (o);
if (InjectedScriptHost.objectHasOwnProperty(o, name)) {
for (var descriptor of process(o, [name]))
yield descriptor;
if (!process(o, [name]))
return descriptors;
break;
}
if (ownProperties)
break;
}
}
return;
}
/**
* @param {number} length
*/
function* arrayIndexNames(length)
{
for (var i = 0; i < length; ++i)
yield "" + i;
return descriptors;
}
var skipGetOwnPropertyNames;
try {
skipGetOwnPropertyNames = InjectedScriptHost.subtype(object) === "typedarray" && object.length > 500000;
skipGetOwnPropertyNames = subtype === "typedarray" && object.length > 500000;
} catch (e) {
}
for (var o = object; this._isDefined(o); o = this._objectPrototype(o)) {
for (var o = object; this._isDefined(o); o = this._objectPrototype(/** @type {!Object} */ (o))) {
o = /** @type {!Object} */ (o);
if (InjectedScriptHost.subtype(o) === "proxy")
continue;
if (skipGetOwnPropertyNames && o === object) {
// Avoid OOM crashes from getting all own property names of a large TypedArray.
for (var descriptor of process(o, arrayIndexNames(o.length)))
yield descriptor;
} else {
// First call Object.keys() to enforce ordering of the property descriptors.
for (var descriptor of process(o, Object.keys(/** @type {!Object} */ (o))))
yield descriptor;
for (var descriptor of process(o, Object.getOwnPropertyNames(/** @type {!Object} */ (o))))
yield descriptor;
try {
if (skipGetOwnPropertyNames && o === object) {
if (!process(o, undefined, o.length))
return descriptors;
} else {
// First call Object.keys() to enforce ordering of the property descriptors.
if (!process(o, Object.keys(o)))
return descriptors;
if (!process(o, Object.getOwnPropertyNames(o)))
return descriptors;
}
if (Object.getOwnPropertySymbols) {
if (!process(o, Object.getOwnPropertySymbols(o)))
return descriptors;
}
if (ownProperties) {
var proto = this._objectPrototype(o);
if (proto && !accessorPropertiesOnly) {
var descriptor = { name: "__proto__", value: proto, writable: true, configurable: true, enumerable: false, isOwn: true, __proto__: null };
if (!addPropertyIfNeeded(descriptors, descriptor))
return descriptors;
}
}
} catch (e) {
}
if (Object.getOwnPropertySymbols) {
for (var descriptor of process(o, Object.getOwnPropertySymbols(/** @type {!Object} */ (o))))
yield descriptor;
}
if (ownProperties) {
var proto = this._objectPrototype(o);
if (proto && !accessorPropertiesOnly)
yield { name: "__proto__", value: proto, writable: true, configurable: true, enumerable: false, isOwn: true, __proto__: null };
if (ownProperties)
break;
}
}
return descriptors;
},
/**
@ -863,19 +886,15 @@ InjectedScript.RemoteObject.prototype = {
{
var preview = this._createEmptyPreview();
var firstLevelKeysCount = firstLevelKeys ? firstLevelKeys.length : 0;
var propertiesThreshold = {
properties: isTable ? 1000 : max(5, firstLevelKeysCount),
indexes: isTable ? 1000 : max(100, firstLevelKeysCount),
__proto__: null
};
var subtype = this.subtype;
try {
var descriptors = injectedScript._propertyDescriptors(object, undefined, undefined, firstLevelKeys);
this._appendPropertyDescriptors(preview, descriptors, propertiesThreshold, secondLevelKeys, isTable);
if (propertiesThreshold.indexes < 0 || propertiesThreshold.properties < 0)
return preview;
var descriptors = injectedScript._propertyDescriptors(object, addPropertyIfNeeded, false /* ownProperties */, undefined /* accessorPropertiesOnly */, firstLevelKeys);
// Add internal properties to preview.
var rawInternalProperties = InjectedScriptHost.getInternalProperties(object) || [];
@ -886,64 +905,80 @@ InjectedScript.RemoteObject.prototype = {
entries = /** @type {!Array<*>} */(rawInternalProperties[i + 1]);
continue;
}
push(internalProperties, {
var internalPropertyDescriptor = {
name: rawInternalProperties[i],
value: rawInternalProperties[i + 1],
isOwn: true,
enumerable: true,
__proto__: null
});
};
if (!addPropertyIfNeeded(descriptors, internalPropertyDescriptor))
break;
}
this._appendPropertyDescriptors(preview, internalProperties, propertiesThreshold, secondLevelKeys, isTable);
this._appendPropertyPreviewDescriptors(preview, descriptors, secondLevelKeys, isTable);
if (this.subtype === "map" || this.subtype === "set" || this.subtype === "iterator")
if (subtype === "map" || subtype === "set" || subtype === "iterator")
this._appendEntriesPreview(entries, preview, skipEntriesPreview);
} catch (e) {}
return preview;
/**
* @param {!Array<!Object>} descriptors
* @param {!Object} descriptor
* @return {boolean}
*/
function addPropertyIfNeeded(descriptors, descriptor) {
if (descriptor.wasThrown)
return true;
// Ignore __proto__ property.
if (descriptor.name === "__proto__")
return true;
// Ignore length property of array.
if ((subtype === "array" || subtype === "typedarray") && descriptor.name === "length")
return true;
// Ignore size property of map, set.
if ((subtype === "map" || subtype === "set") && descriptor.name === "size")
return true;
// Never preview prototype properties.
if (!descriptor.isOwn)
return true;
// Ignore computed properties unless they have getters.
if (!("value" in descriptor) && !descriptor.get)
return true;
if (toString(descriptor.name >>> 0) === descriptor.name)
propertiesThreshold.indexes--;
else
propertiesThreshold.properties--;
var canContinue = propertiesThreshold.indexes >= 0 && propertiesThreshold.properties >= 0;
if (!canContinue) {
preview.overflow = true;
return false;
}
push(descriptors, descriptor);
return true;
}
},
/**
* @param {!RuntimeAgent.ObjectPreview} preview
* @param {!Array.<*>|!Iterable.<*>} descriptors
* @param {!Object} propertiesThreshold
* @param {?Array.<string>=} secondLevelKeys
* @param {boolean=} isTable
*/
_appendPropertyDescriptors: function(preview, descriptors, propertiesThreshold, secondLevelKeys, isTable)
_appendPropertyPreviewDescriptors: function(preview, descriptors, secondLevelKeys, isTable)
{
for (var descriptor of descriptors) {
if (propertiesThreshold.indexes < 0 || propertiesThreshold.properties < 0)
break;
if (!descriptor || descriptor.wasThrown)
continue;
for (var i = 0; i < descriptors.length; ++i) {
var descriptor = descriptors[i];
var name = descriptor.name;
// Ignore __proto__ property.
if (name === "__proto__")
continue;
// Ignore length property of array.
if ((this.subtype === "array" || this.subtype === "typedarray") && name === "length")
continue;
// Ignore size property of map, set.
if ((this.subtype === "map" || this.subtype === "set") && name === "size")
continue;
// Never preview prototype properties.
if (!descriptor.isOwn)
continue;
// Ignore computed properties unless they have getters.
if (!("value" in descriptor)) {
if (descriptor.get)
this._appendPropertyPreview(preview, { name: name, type: "accessor", __proto__: null }, propertiesThreshold);
continue;
}
var value = descriptor.value;
var type = typeof value;
@ -951,9 +986,15 @@ InjectedScript.RemoteObject.prototype = {
if (type === "undefined" && injectedScript._isHTMLAllCollection(value))
type = "object";
// Ignore computed properties unless they have getters.
if (descriptor.get && !("value" in descriptor)) {
push(preview.properties, { name: name, type: "accessor", __proto__: null });
continue;
}
// Render own properties.
if (value === null) {
this._appendPropertyPreview(preview, { name: name, type: "object", subtype: "null", value: "null", __proto__: null }, propertiesThreshold);
push(preview.properties, { name: name, type: "object", subtype: "null", value: "null", __proto__: null });
continue;
}
@ -961,7 +1002,7 @@ InjectedScript.RemoteObject.prototype = {
if (InjectedScript.primitiveTypes[type]) {
if (type === "string" && value.length > maxLength)
value = this._abbreviateString(value, maxLength, true);
this._appendPropertyPreview(preview, { name: name, type: type, value: toStringDescription(value), __proto__: null }, propertiesThreshold);
push(preview.properties, { name: name, type: type, value: toStringDescription(value), __proto__: null });
continue;
}
@ -981,24 +1022,6 @@ InjectedScript.RemoteObject.prototype = {
description = this._abbreviateString(/** @type {string} */ (injectedScript._describe(value)), maxLength, subtype === "regexp");
property.value = description;
}
this._appendPropertyPreview(preview, property, propertiesThreshold);
}
},
/**
* @param {!RuntimeAgent.ObjectPreview} preview
* @param {!Object} property
* @param {!Object} propertiesThreshold
*/
_appendPropertyPreview: function(preview, property, propertiesThreshold)
{
if (toString(property.name >>> 0) === property.name)
propertiesThreshold.indexes--;
else
propertiesThreshold.properties--;
if (propertiesThreshold.indexes < 0 || propertiesThreshold.properties < 0) {
preview.overflow = true;
} else {
push(preview.properties, property);
}
},

View File

@ -162,6 +162,20 @@ void InspectorClientImpl::disconnect() {
session_.reset();
}
bool InspectorClientImpl::formatAccessorsAsProperties(
v8::Local<v8::Value> object) {
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Local<v8::Context> context = isolate->GetCurrentContext();
v8::Local<v8::Private> shouldFormatAccessorsPrivate = v8::Private::ForApi(
isolate, v8::String::NewFromUtf8(isolate, "allowAccessorFormatting",
v8::NewStringType::kNormal)
.ToLocalChecked());
CHECK(object->IsObject());
return object.As<v8::Object>()
->HasPrivate(context, shouldFormatAccessorsPrivate)
.FromMaybe(false);
}
v8::Local<v8::Context> InspectorClientImpl::ensureDefaultContextInGroup(int) {
CHECK(isolate_);
return context_.Get(isolate_);

View File

@ -38,6 +38,7 @@ class InspectorClientImpl : public v8_inspector::V8InspectorClient {
private:
// V8InspectorClient implementation.
bool formatAccessorsAsProperties(v8::Local<v8::Value>) override;
v8::Local<v8::Context> ensureDefaultContextInGroup(
int context_group_id) override;
double currentTimeMS() override;

View File

@ -382,7 +382,8 @@ class InspectorExtension : public v8::Extension {
"native function setMaxAsyncTaskStacks();"
"native function breakProgram();"
"native function createObjectWithStrictCheck();"
"native function callWithScheduledBreak();") {}
"native function callWithScheduledBreak();"
"native function allowAccessorFormatting();") {}
virtual v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate(
v8::Isolate* isolate, v8::Local<v8::String> name) {
@ -427,6 +428,13 @@ class InspectorExtension : public v8::Extension {
.FromJust()) {
return v8::FunctionTemplate::New(
isolate, InspectorExtension::CallWithScheduledBreak);
} else if (name->Equals(context, v8::String::NewFromUtf8(
isolate, "allowAccessorFormatting",
v8::NewStringType::kNormal)
.ToLocalChecked())
.FromJust()) {
return v8::FunctionTemplate::New(
isolate, InspectorExtension::AllowAccessorFormatting);
}
return v8::Local<v8::FunctionTemplate>();
}
@ -525,6 +533,24 @@ class InspectorExtension : public v8::Extension {
nullptr);
session->cancelPauseOnNextStatement();
}
static void AllowAccessorFormatting(
const v8::FunctionCallbackInfo<v8::Value>& args) {
if (args.Length() != 1 || !args[0]->IsObject()) {
fprintf(stderr, "Internal error: allowAccessorFormatting('object').");
Exit();
}
v8::Local<v8::Object> object = args[0].As<v8::Object>();
v8::Isolate* isolate = args.GetIsolate();
v8::Local<v8::Private> shouldFormatAccessorsPrivate = v8::Private::ForApi(
isolate, v8::String::NewFromUtf8(isolate, "allowAccessorFormatting",
v8::NewStringType::kNormal)
.ToLocalChecked());
object
->SetPrivate(isolate->GetCurrentContext(), shouldFormatAccessorsPrivate,
v8::Null(isolate))
.ToChecked();
}
};
v8::Local<v8::String> ToString(v8::Isolate* isolate,

View File

@ -100,3 +100,730 @@ Running test: testInheritingArrayPropertiesPreview
subtype : array
type : object
}
Running test: testShortTypedArrayPropertiesPreview
{
description : Uint8Array(3)
overflow : false
properties : [
[0] : {
name : 0
type : number
value : 0
}
[1] : {
name : 1
type : number
value : 0
}
[2] : {
name : 2
type : number
value : 0
}
]
subtype : typedarray
type : object
}
Running test: testLongTypedArrayPropertiesPreview
{
description : Uint8Array(500001)
overflow : true
properties : [
[0] : {
name : 0
type : number
value : 0
}
[1] : {
name : 1
type : number
value : 0
}
[2] : {
name : 2
type : number
value : 0
}
[3] : {
name : 3
type : number
value : 0
}
[4] : {
name : 4
type : number
value : 0
}
[5] : {
name : 5
type : number
value : 0
}
[6] : {
name : 6
type : number
value : 0
}
[7] : {
name : 7
type : number
value : 0
}
[8] : {
name : 8
type : number
value : 0
}
[9] : {
name : 9
type : number
value : 0
}
[10] : {
name : 10
type : number
value : 0
}
[11] : {
name : 11
type : number
value : 0
}
[12] : {
name : 12
type : number
value : 0
}
[13] : {
name : 13
type : number
value : 0
}
[14] : {
name : 14
type : number
value : 0
}
[15] : {
name : 15
type : number
value : 0
}
[16] : {
name : 16
type : number
value : 0
}
[17] : {
name : 17
type : number
value : 0
}
[18] : {
name : 18
type : number
value : 0
}
[19] : {
name : 19
type : number
value : 0
}
[20] : {
name : 20
type : number
value : 0
}
[21] : {
name : 21
type : number
value : 0
}
[22] : {
name : 22
type : number
value : 0
}
[23] : {
name : 23
type : number
value : 0
}
[24] : {
name : 24
type : number
value : 0
}
[25] : {
name : 25
type : number
value : 0
}
[26] : {
name : 26
type : number
value : 0
}
[27] : {
name : 27
type : number
value : 0
}
[28] : {
name : 28
type : number
value : 0
}
[29] : {
name : 29
type : number
value : 0
}
[30] : {
name : 30
type : number
value : 0
}
[31] : {
name : 31
type : number
value : 0
}
[32] : {
name : 32
type : number
value : 0
}
[33] : {
name : 33
type : number
value : 0
}
[34] : {
name : 34
type : number
value : 0
}
[35] : {
name : 35
type : number
value : 0
}
[36] : {
name : 36
type : number
value : 0
}
[37] : {
name : 37
type : number
value : 0
}
[38] : {
name : 38
type : number
value : 0
}
[39] : {
name : 39
type : number
value : 0
}
[40] : {
name : 40
type : number
value : 0
}
[41] : {
name : 41
type : number
value : 0
}
[42] : {
name : 42
type : number
value : 0
}
[43] : {
name : 43
type : number
value : 0
}
[44] : {
name : 44
type : number
value : 0
}
[45] : {
name : 45
type : number
value : 0
}
[46] : {
name : 46
type : number
value : 0
}
[47] : {
name : 47
type : number
value : 0
}
[48] : {
name : 48
type : number
value : 0
}
[49] : {
name : 49
type : number
value : 0
}
[50] : {
name : 50
type : number
value : 0
}
[51] : {
name : 51
type : number
value : 0
}
[52] : {
name : 52
type : number
value : 0
}
[53] : {
name : 53
type : number
value : 0
}
[54] : {
name : 54
type : number
value : 0
}
[55] : {
name : 55
type : number
value : 0
}
[56] : {
name : 56
type : number
value : 0
}
[57] : {
name : 57
type : number
value : 0
}
[58] : {
name : 58
type : number
value : 0
}
[59] : {
name : 59
type : number
value : 0
}
[60] : {
name : 60
type : number
value : 0
}
[61] : {
name : 61
type : number
value : 0
}
[62] : {
name : 62
type : number
value : 0
}
[63] : {
name : 63
type : number
value : 0
}
[64] : {
name : 64
type : number
value : 0
}
[65] : {
name : 65
type : number
value : 0
}
[66] : {
name : 66
type : number
value : 0
}
[67] : {
name : 67
type : number
value : 0
}
[68] : {
name : 68
type : number
value : 0
}
[69] : {
name : 69
type : number
value : 0
}
[70] : {
name : 70
type : number
value : 0
}
[71] : {
name : 71
type : number
value : 0
}
[72] : {
name : 72
type : number
value : 0
}
[73] : {
name : 73
type : number
value : 0
}
[74] : {
name : 74
type : number
value : 0
}
[75] : {
name : 75
type : number
value : 0
}
[76] : {
name : 76
type : number
value : 0
}
[77] : {
name : 77
type : number
value : 0
}
[78] : {
name : 78
type : number
value : 0
}
[79] : {
name : 79
type : number
value : 0
}
[80] : {
name : 80
type : number
value : 0
}
[81] : {
name : 81
type : number
value : 0
}
[82] : {
name : 82
type : number
value : 0
}
[83] : {
name : 83
type : number
value : 0
}
[84] : {
name : 84
type : number
value : 0
}
[85] : {
name : 85
type : number
value : 0
}
[86] : {
name : 86
type : number
value : 0
}
[87] : {
name : 87
type : number
value : 0
}
[88] : {
name : 88
type : number
value : 0
}
[89] : {
name : 89
type : number
value : 0
}
[90] : {
name : 90
type : number
value : 0
}
[91] : {
name : 91
type : number
value : 0
}
[92] : {
name : 92
type : number
value : 0
}
[93] : {
name : 93
type : number
value : 0
}
[94] : {
name : 94
type : number
value : 0
}
[95] : {
name : 95
type : number
value : 0
}
[96] : {
name : 96
type : number
value : 0
}
[97] : {
name : 97
type : number
value : 0
}
[98] : {
name : 98
type : number
value : 0
}
[99] : {
name : 99
type : number
value : 0
}
]
subtype : typedarray
type : object
}
Running test: testSetPropertiesPreview
{
description : Set(3)
entries : [
[0] : {
value : {
description : 1
overflow : false
properties : [
]
type : number
}
}
[1] : {
value : {
description : 2
overflow : false
properties : [
]
type : number
}
}
[2] : {
value : {
description : 3
overflow : false
properties : [
]
type : number
}
}
]
overflow : false
properties : [
]
subtype : set
type : object
}
Running test: testBigSetPropertiesPreview
{
description : Set(10)
entries : [
[0] : {
value : {
description : 0
overflow : false
properties : [
]
type : number
}
}
[1] : {
value : {
description : 1
overflow : false
properties : [
]
type : number
}
}
[2] : {
value : {
description : 2
overflow : false
properties : [
]
type : number
}
}
[3] : {
value : {
description : 3
overflow : false
properties : [
]
type : number
}
}
[4] : {
value : {
description : 4
overflow : false
properties : [
]
type : number
}
}
]
overflow : true
properties : [
]
subtype : set
type : object
}
Running test: testMixedSetPropertiesPreview
{
description : Set(10)
entries : [
[0] : {
value : {
description : 0
overflow : false
properties : [
]
type : number
}
}
[1] : {
value : {
description : 1
overflow : false
properties : [
]
type : number
}
}
[2] : {
value : {
description : 2
overflow : false
properties : [
]
type : number
}
}
[3] : {
value : {
description : 3
overflow : false
properties : [
]
type : number
}
}
[4] : {
value : {
description : 4
overflow : false
properties : [
]
type : number
}
}
]
overflow : true
properties : [
[0] : {
name : _prop_0
type : number
value : 1
}
[1] : {
name : _prop_1
type : number
value : 1
}
[2] : {
name : _prop_2
type : number
value : 1
}
[3] : {
name : _prop_3
type : number
value : 1
}
[4] : {
name : _prop_4
type : number
value : 1
}
]
subtype : set
type : object
}
Running test: testObjInheritsGetterProperty
{
description : Object
overflow : false
properties : [
[0] : {
name : propNotNamedProto
type : number
value : NaN
}
]
type : object
}

View File

@ -43,6 +43,26 @@ var inheritingObj = {};
var inheritingArr = [];
inheritingObj.prototype = obj;
inheritingArr.prototype = arr;
var shortTypedArray = new Uint8Array(3);
var longTypedArray = new Uint8Array(500001);
var set = new Set([1, 2, 3]);
var bigSet = new Set();
var mixedSet = new Set();
for (var i = 0; i < 10; i++) {
bigSet.add(i);
mixedSet["_prop_" + i] = 1;
mixedSet.add(i);
}
var deterministicNativeFunction = Math.log;
var parentObj = {};
Object.defineProperty(parentObj, 'propNotNamedProto', {
get: deterministicNativeFunction,
set: function() {}
});
var objInheritsGetterProperty = {__proto__: parentObj};
allowAccessorFormatting(objInheritsGetterProperty);
`);
InspectorTest.runTestSuite([
@ -72,5 +92,47 @@ InspectorTest.runTestSuite([
Protocol.Runtime.evaluate({ "expression": "inheritingArr", "generatePreview": true })
.then(result => InspectorTest.logMessage(result.result.result.preview))
.then(next);
},
function testShortTypedArrayPropertiesPreview(next)
{
Protocol.Runtime.evaluate({ "expression": "shortTypedArray", "generatePreview": true })
.then(result => InspectorTest.logMessage(result.result.result.preview))
.then(next);
},
function testLongTypedArrayPropertiesPreview(next)
{
Protocol.Runtime.evaluate({ "expression": "longTypedArray", "generatePreview": true })
.then(result => InspectorTest.logMessage(result.result.result.preview))
.then(next);
},
function testSetPropertiesPreview(next)
{
Protocol.Runtime.evaluate({ "expression": "set", "generatePreview": true })
.then(result => InspectorTest.logMessage(result.result.result.preview))
.then(next);
},
function testBigSetPropertiesPreview(next)
{
Protocol.Runtime.evaluate({ "expression": "bigSet", "generatePreview": true })
.then(result => InspectorTest.logMessage(result.result.result.preview))
.then(next);
},
function testMixedSetPropertiesPreview(next)
{
Protocol.Runtime.evaluate({ "expression": "mixedSet", "generatePreview": true })
.then(result => InspectorTest.logMessage(result.result.result.preview))
.then(next);
},
function testObjInheritsGetterProperty(next)
{
Protocol.Runtime.evaluate({ "expression": "objInheritsGetterProperty", "generatePreview": true })
.then(result => InspectorTest.logMessage(result.result.result.preview))
.then(next);
}
]);

View File

@ -37,3 +37,8 @@ Internal properties
[[BoundArgs]] object undefined
[[BoundThis]] object undefined
[[TargetFunction]] function undefined
Properties of Object that throws on length access
__proto__ own object undefined
length own no value, getter
Properties of TypedArray without length
__proto__ own object undefined

View File

@ -176,6 +176,46 @@ function callbackEvalBound(result)
function callbackPropertiesBound(result)
{
logGetPropertiesResult("Bound function", result);
return { callback: callbackStartObjectThrowsLength };
}
// Object throws on length access
function callbackStartObjectThrowsLength() {
var expression = "({get length() { throw 'Length called'; }})";
return { command: "Runtime.evaluate", params: {expression: expression}, callback: callbackEvalObjectThrowsLength };
}
function callbackEvalObjectThrowsLength(result) {
var id = result.result.objectId;
if (id === undefined)
throw new Error("objectId is expected");
return {
command: "Runtime.getProperties", params: {objectId: id, ownProperties: true}, callback: callbackPropertiesObjectThrowsLength
};
}
function callbackPropertiesObjectThrowsLength(result) {
logGetPropertiesResult("Object that throws on length access", result);
return { callback: callbackStartTypedArrayWithoutLength };
}
// Typed array without length
function callbackStartTypedArrayWithoutLength() {
var expression = "({__proto__: Uint8Array.prototype})";
return { command: "Runtime.evaluate", params: {expression: expression}, callback: callbackEvalTypedArrayWithoutLength };
}
function callbackEvalTypedArrayWithoutLength(result) {
var id = result.result.objectId;
if (id === undefined)
throw new Error("objectId is expected");
return {
command: "Runtime.getProperties", params: {objectId: id, ownProperties: true}, callback: callbackPropertiesTypedArrayWithoutLength
};
}
function callbackPropertiesTypedArrayWithoutLength(result) {
logGetPropertiesResult("TypedArray without length", result);
return; // End of test
}