Commit a1059015 authored by littledan's avatar littledan Committed by Commit bot

Add %TypedArray% to proto chain

According to the ES6 spec, the main methods and getters shouldn't
be properties of the individual TypedArray objects and prototypes
but instead on %TypedArray% and %TypedArray%.prototype. This
difference is observable through introspection. This patch moves
some methods and getters to the proper place, with the exception
of %TypedArray%.prototype.subarray and harmony methods. These will
be moved in follow-on patches.

BUG=v8:4085
LOG=Y
R=adamk

Review URL: https://codereview.chromium.org/1186733002

Cr-Commit-Position: refs/heads/master@{#29057}
parent bc847230
...@@ -11,25 +11,21 @@ ...@@ -11,25 +11,21 @@
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Imports // Imports
macro TYPED_ARRAYS(FUNCTION)
// arrayIds below should be synchronized with Runtime_TypedArrayInitialize.
FUNCTION(Uint8Array)
FUNCTION(Int8Array)
FUNCTION(Uint16Array)
FUNCTION(Int16Array)
FUNCTION(Uint32Array)
FUNCTION(Int32Array)
FUNCTION(Float32Array)
FUNCTION(Float64Array)
FUNCTION(Uint8ClampedArray)
endmacro
macro DECLARE_GLOBALS(NAME) macro DECLARE_GLOBALS(NAME)
var GlobalNAME = global.NAME; var GlobalNAME = global.NAME;
endmacro endmacro
TYPED_ARRAYS(DECLARE_GLOBALS)
DECLARE_GLOBALS(Array) DECLARE_GLOBALS(Array)
DECLARE_GLOBALS(Uint8Array)
DECLARE_GLOBALS(Int8Array)
DECLARE_GLOBALS(Uint16Array)
DECLARE_GLOBALS(Int16Array)
DECLARE_GLOBALS(Uint32Array)
DECLARE_GLOBALS(Int32Array)
DECLARE_GLOBALS(Float32Array)
DECLARE_GLOBALS(Float64Array)
DECLARE_GLOBALS(Uint8ClampedArray)
var ArrayFrom; var ArrayFrom;
var ArrayToString; var ArrayToString;
...@@ -51,6 +47,8 @@ var InnerArrayToLocaleString; ...@@ -51,6 +47,8 @@ var InnerArrayToLocaleString;
var IsNaN; var IsNaN;
var MathMax; var MathMax;
var MathMin; var MathMin;
var TypedArray = GlobalUint8Array.__proto__;
var TypedArrayPrototype = GlobalUint8Array.prototype.__proto__;
utils.Import(function(from) { utils.Import(function(from) {
ArrayFrom = from.ArrayFrom; ArrayFrom = from.ArrayFrom;
...@@ -376,38 +374,33 @@ function TypedArrayFrom(source, mapfn, thisArg) { ...@@ -376,38 +374,33 @@ function TypedArrayFrom(source, mapfn, thisArg) {
} }
%FunctionSetLength(TypedArrayFrom, 1); %FunctionSetLength(TypedArrayFrom, 1);
// TODO(littledan): Fix the TypedArray proto chain (bug v8:4085).
macro EXTEND_TYPED_ARRAY(NAME)
// Set up non-enumerable functions on the object. // Set up non-enumerable functions on the object.
utils.InstallFunctions(GlobalNAME, DONT_ENUM | DONT_DELETE | READ_ONLY, [ utils.InstallFunctions(TypedArray, DONT_ENUM | DONT_DELETE | READ_ONLY, [
"from", TypedArrayFrom, "from", TypedArrayFrom,
"of", TypedArrayOf "of", TypedArrayOf
]); ]);
// Set up non-enumerable functions on the prototype object. // Set up non-enumerable functions on the prototype object.
utils.InstallFunctions(GlobalNAME.prototype, DONT_ENUM, [ utils.InstallFunctions(TypedArrayPrototype, DONT_ENUM, [
"copyWithin", TypedArrayCopyWithin, "copyWithin", TypedArrayCopyWithin,
"every", TypedArrayEvery, "every", TypedArrayEvery,
"fill", TypedArrayFill, "fill", TypedArrayFill,
"filter", TypedArrayFilter, "filter", TypedArrayFilter,
"find", TypedArrayFind, "find", TypedArrayFind,
"findIndex", TypedArrayFindIndex, "findIndex", TypedArrayFindIndex,
"indexOf", TypedArrayIndexOf, "indexOf", TypedArrayIndexOf,
"join", TypedArrayJoin, "join", TypedArrayJoin,
"lastIndexOf", TypedArrayLastIndexOf, "lastIndexOf", TypedArrayLastIndexOf,
"forEach", TypedArrayForEach, "forEach", TypedArrayForEach,
"map", TypedArrayMap, "map", TypedArrayMap,
"reduce", TypedArrayReduce, "reduce", TypedArrayReduce,
"reduceRight", TypedArrayReduceRight, "reduceRight", TypedArrayReduceRight,
"reverse", TypedArrayReverse, "reverse", TypedArrayReverse,
"slice", TypedArraySlice, "slice", TypedArraySlice,
"some", TypedArraySome, "some", TypedArraySome,
"sort", TypedArraySort, "sort", TypedArraySort,
"toString", TypedArrayToString, "toString", TypedArrayToString,
"toLocaleString", TypedArrayToLocaleString "toLocaleString", TypedArrayToLocaleString
]); ]);
endmacro
TYPED_ARRAYS(EXTEND_TYPED_ARRAY)
}) })
...@@ -171,6 +171,7 @@ RUNTIME_FUNCTION(Runtime_FunctionSetLength) { ...@@ -171,6 +171,7 @@ RUNTIME_FUNCTION(Runtime_FunctionSetLength) {
} }
// Set the "prototype" property of a constructor Function.
RUNTIME_FUNCTION(Runtime_FunctionSetPrototype) { RUNTIME_FUNCTION(Runtime_FunctionSetPrototype) {
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK(args.length() == 2); DCHECK(args.length() == 2);
......
...@@ -148,6 +148,7 @@ RUNTIME_FUNCTION(Runtime_GetPrototype) { ...@@ -148,6 +148,7 @@ RUNTIME_FUNCTION(Runtime_GetPrototype) {
} }
// Set the [[Prototype]] internal slot of an object.
RUNTIME_FUNCTION(Runtime_InternalSetPrototype) { RUNTIME_FUNCTION(Runtime_InternalSetPrototype) {
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK(args.length() == 2); DCHECK(args.length() == 2);
......
...@@ -47,6 +47,44 @@ var InternalArray = utils.InternalArray; ...@@ -47,6 +47,44 @@ var InternalArray = utils.InternalArray;
// --------------- Typed Arrays --------------------- // --------------- Typed Arrays ---------------------
function TypedArray() {
if (!%_IsConstructCall()) {
throw MakeTypeError(kConstructorNotFunction, "TypedArray")
}
// TODO(littledan): When the TypedArrays code is refactored to provide
// a common constructor entrypoint for v8:4182, call that here.
}
function TypedArray_GetBuffer() {
if (!%_IsTypedArray(this)) {
throw MakeTypeError(kIncompatibleMethodReceiver, "TypedArray.buffer", this);
}
return %TypedArrayGetBuffer(this);
}
function TypedArray_GetByteLength() {
if (!%_IsTypedArray(this)) {
throw MakeTypeError(kIncompatibleMethodReceiver, "TypedArray.byteLength",
this);
}
return %_ArrayBufferViewGetByteLength(this);
}
function TypedArray_GetByteOffset() {
if (!%_IsTypedArray(this)) {
throw MakeTypeError(kIncompatibleMethodReceiver, "TypedArray.byteOffset",
this);
}
return %_ArrayBufferViewGetByteOffset(this);
}
function TypedArray_GetLength() {
if (!%_IsTypedArray(this)) {
throw MakeTypeError(kIncompatibleMethodReceiver, "TypedArray.length", this);
}
return %_TypedArrayGetLength(this);
}
macro TYPED_ARRAY_CONSTRUCTOR(ARRAY_ID, NAME, ELEMENT_SIZE) macro TYPED_ARRAY_CONSTRUCTOR(ARRAY_ID, NAME, ELEMENT_SIZE)
function NAMEConstructByArrayBuffer(obj, buffer, byteOffset, length) { function NAMEConstructByArrayBuffer(obj, buffer, byteOffset, length) {
if (!IS_UNDEFINED(byteOffset)) { if (!IS_UNDEFINED(byteOffset)) {
...@@ -172,34 +210,6 @@ function NAMEConstructor(arg1, arg2, arg3) { ...@@ -172,34 +210,6 @@ function NAMEConstructor(arg1, arg2, arg3) {
} }
} }
function NAME_GetBuffer() {
if (!(%_ClassOf(this) === 'NAME')) {
throw MakeTypeError(kIncompatibleMethodReceiver, "NAME.buffer", this);
}
return %TypedArrayGetBuffer(this);
}
function NAME_GetByteLength() {
if (!(%_ClassOf(this) === 'NAME')) {
throw MakeTypeError(kIncompatibleMethodReceiver, "NAME.byteLength", this);
}
return %_ArrayBufferViewGetByteLength(this);
}
function NAME_GetByteOffset() {
if (!(%_ClassOf(this) === 'NAME')) {
throw MakeTypeError(kIncompatibleMethodReceiver, "NAME.byteOffset", this);
}
return %_ArrayBufferViewGetByteOffset(this);
}
function NAME_GetLength() {
if (!(%_ClassOf(this) === 'NAME')) {
throw MakeTypeError(kIncompatibleMethodReceiver, "NAME.length", this);
}
return %_TypedArrayGetLength(this);
}
function NAMESubArray(begin, end) { function NAMESubArray(begin, end) {
if (!(%_ClassOf(this) === 'NAME')) { if (!(%_ClassOf(this) === 'NAME')) {
throw MakeTypeError(kIncompatibleMethodReceiver, "NAME.subarray", this); throw MakeTypeError(kIncompatibleMethodReceiver, "NAME.subarray", this);
...@@ -347,29 +357,33 @@ function TypedArrayGetToStringTag() { ...@@ -347,29 +357,33 @@ function TypedArrayGetToStringTag() {
// ------------------------------------------------------------------- // -------------------------------------------------------------------
utils.InstallGetter(TypedArray.prototype, "buffer", TypedArray_GetBuffer);
utils.InstallGetter(TypedArray.prototype, "byteOffset",
TypedArray_GetByteOffset, DONT_ENUM);
utils.InstallGetter(TypedArray.prototype, "byteLength",
TypedArray_GetByteLength, DONT_ENUM);
utils.InstallGetter(TypedArray.prototype, "length", TypedArray_GetLength,
DONT_ENUM);
utils.InstallGetter(TypedArray.prototype, symbolToStringTag,
TypedArrayGetToStringTag, DONT_ENUM);
utils.InstallFunctions(TypedArray.prototype, DONT_ENUM, [
"set", TypedArraySet
]);
macro SETUP_TYPED_ARRAY(ARRAY_ID, NAME, ELEMENT_SIZE) macro SETUP_TYPED_ARRAY(ARRAY_ID, NAME, ELEMENT_SIZE)
%SetCode(GlobalNAME, NAMEConstructor); %SetCode(GlobalNAME, NAMEConstructor);
%FunctionSetPrototype(GlobalNAME, new GlobalObject()); %InternalSetPrototype(GlobalNAME, TypedArray);
%FunctionSetPrototype(GlobalNAME, new TypedArray());
%AddNamedProperty(GlobalNAME.prototype,
"BYTES_PER_ELEMENT", ELEMENT_SIZE,
READ_ONLY | DONT_ENUM | DONT_DELETE);
%AddNamedProperty(GlobalNAME, "BYTES_PER_ELEMENT", ELEMENT_SIZE, %AddNamedProperty(GlobalNAME, "BYTES_PER_ELEMENT", ELEMENT_SIZE,
READ_ONLY | DONT_ENUM | DONT_DELETE); READ_ONLY | DONT_ENUM | DONT_DELETE);
%AddNamedProperty(GlobalNAME.prototype, %AddNamedProperty(GlobalNAME.prototype,
"constructor", global.NAME, DONT_ENUM); "constructor", global.NAME, DONT_ENUM);
%AddNamedProperty(GlobalNAME.prototype,
"BYTES_PER_ELEMENT", ELEMENT_SIZE,
READ_ONLY | DONT_ENUM | DONT_DELETE);
utils.InstallGetter(GlobalNAME.prototype, "buffer", NAME_GetBuffer);
utils.InstallGetter(GlobalNAME.prototype, "byteOffset", NAME_GetByteOffset,
DONT_ENUM | DONT_DELETE);
utils.InstallGetter(GlobalNAME.prototype, "byteLength", NAME_GetByteLength,
DONT_ENUM | DONT_DELETE);
utils.InstallGetter(GlobalNAME.prototype, "length", NAME_GetLength,
DONT_ENUM | DONT_DELETE);
utils.InstallGetter(GlobalNAME.prototype, symbolToStringTag,
TypedArrayGetToStringTag);
utils.InstallFunctions(GlobalNAME.prototype, DONT_ENUM, [ utils.InstallFunctions(GlobalNAME.prototype, DONT_ENUM, [
"subarray", NAMESubArray, "subarray", NAMESubArray
"set", TypedArraySet
]); ]);
endmacro endmacro
......
...@@ -6,14 +6,22 @@ ...@@ -6,14 +6,22 @@
'use strict'; 'use strict';
function assertGetterName(expected, object, name) { function getPropertyDescriptor(object, field, expectedDepth) {
var descr = Object.getOwnPropertyDescriptor(object, name); for (var depth = 0; depth < expectedDepth; depth++) {
assertFalse(Object.hasOwnProperty(object, field));
object = object.__proto__;
}
return Object.getOwnPropertyDescriptor(object, field);
}
function assertGetterName(expected, object, name, expectedDepth) {
var descr = getPropertyDescriptor(object, name, expectedDepth);
assertSame(expected, descr.get.name); assertSame(expected, descr.get.name);
} }
function assertSetterName(expected, object, name) { function assertSetterName(expected, object, name, indirect) {
var descr = Object.getOwnPropertyDescriptor(object, name); var descr = getPropertyDescriptor(object, name);
assertSame(expected, descr.set.name); assertSame(expected, descr.set.name);
} }
...@@ -36,11 +44,11 @@ let typedArrays = [ ...@@ -36,11 +44,11 @@ let typedArrays = [
]; ];
for (let f of typedArrays) { for (let f of typedArrays) {
assertGetterName('get buffer', f.prototype, 'buffer'); assertGetterName('get buffer', f.prototype, 'buffer', 1);
assertGetterName('get byteOffset', f.prototype, 'byteOffset'); assertGetterName('get byteOffset', f.prototype, 'byteOffset', 1);
assertGetterName('get byteLength', f.prototype, 'byteLength'); assertGetterName('get byteLength', f.prototype, 'byteLength', 1);
assertGetterName('get length', f.prototype, 'length'); assertGetterName('get length', f.prototype, 'length', 1);
assertGetterName('get [Symbol.toStringTag]', f.prototype, Symbol.toStringTag); assertGetterName('get [Symbol.toStringTag]', f.prototype, Symbol.toStringTag, 1);
} }
......
...@@ -82,12 +82,7 @@ var functions = [ ...@@ -82,12 +82,7 @@ var functions = [
// DataView, // DataView,
Date, Date,
Error, Error,
Float32Array,
Float64Array,
Function, Function,
Int16Array,
Int32Array,
Int8Array,
Map, Map,
Number, Number,
Object, Object,
...@@ -96,10 +91,6 @@ var functions = [ ...@@ -96,10 +91,6 @@ var functions = [
Set, Set,
String, String,
// Symbol, not constructible // Symbol, not constructible
Uint16Array,
Uint32Array,
Uint8Array,
Uint8ClampedArray,
WeakMap, WeakMap,
WeakSet, WeakSet,
]; ];
...@@ -109,6 +100,23 @@ for (var f of functions) { ...@@ -109,6 +100,23 @@ for (var f of functions) {
assertPrototypeOf(new f(), f.prototype); assertPrototypeOf(new f(), f.prototype);
} }
var typedArrayConstructors = [
Float32Array,
Float64Array,
Int16Array,
Int32Array,
Int8Array,
Uint16Array,
Uint32Array,
Uint8Array,
Uint8ClampedArray,
];
for (var t of typedArrayConstructors) {
assertPrototypeOf(t, Uint8Array.__proto__);
assertPrototypeOf(new t(), t.prototype);
}
var p = new Promise(function() {}); var p = new Promise(function() {});
assertPrototypeOf(p, Promise.prototype); assertPrototypeOf(p, Promise.prototype);
......
...@@ -87,6 +87,14 @@ function MakeSharedTypedArray(constr, numElements) { ...@@ -87,6 +87,14 @@ function MakeSharedTypedArray(constr, numElements) {
return new constr(sab); return new constr(sab);
} }
function getPropertyDescriptor(object, field, expectedDepth) {
for (var depth = 0; depth < expectedDepth; depth++) {
assertFalse(Object.hasOwnProperty(object, field));
object = object.__proto__;
}
return Object.getOwnPropertyDescriptor(object, field);
}
function TestTypedArray(constr, elementSize, typicalElement) { function TestTypedArray(constr, elementSize, typicalElement) {
assertSame(elementSize, constr.BYTES_PER_ELEMENT); assertSame(elementSize, constr.BYTES_PER_ELEMENT);
...@@ -203,8 +211,7 @@ function TestTypedArray(constr, elementSize, typicalElement) { ...@@ -203,8 +211,7 @@ function TestTypedArray(constr, elementSize, typicalElement) {
var a = new constr(sab, 64*elementSize, 128); var a = new constr(sab, 64*elementSize, 128);
assertEquals("[object " + constr.name + "]", assertEquals("[object " + constr.name + "]",
Object.prototype.toString.call(a)); Object.prototype.toString.call(a));
var desc = Object.getOwnPropertyDescriptor( var desc = getPropertyDescriptor(constr.prototype, Symbol.toStringTag, 1);
constr.prototype, Symbol.toStringTag);
assertTrue(desc.configurable); assertTrue(desc.configurable);
assertFalse(desc.enumerable); assertFalse(desc.enumerable);
assertFalse(!!desc.writable); assertFalse(!!desc.writable);
...@@ -310,17 +317,13 @@ var typedArrayConstructors = [ ...@@ -310,17 +317,13 @@ var typedArrayConstructors = [
function TestPropertyTypeChecks(constructor) { function TestPropertyTypeChecks(constructor) {
function CheckProperty(name) { function CheckProperty(name) {
var d = Object.getOwnPropertyDescriptor(constructor.prototype, name); var d = getPropertyDescriptor(constructor.prototype, name, 1);
var o = {}; var o = {};
assertThrows(function() {d.get.call(o);}, TypeError); assertThrows(function() {d.get.call(o);}, TypeError);
for (var i = 0; i < typedArrayConstructors.length; i++) { for (var i = 0; i < typedArrayConstructors.length; i++) {
var ctor = typedArrayConstructors[i]; var ctor = typedArrayConstructors[i];
var a = MakeSharedTypedArray(ctor, 10); var a = MakeSharedTypedArray(ctor, 10);
if (ctor === constructor) { d.get.call(a); // shouldn't throw on any type
d.get.call(a); // shouldn't throw
} else {
assertThrows(function() {d.get.call(a);}, TypeError);
}
} }
} }
......
...@@ -15,8 +15,16 @@ var typedArrayConstructors = [ ...@@ -15,8 +15,16 @@ var typedArrayConstructors = [
Int32Array, Int32Array,
Uint8ClampedArray, Uint8ClampedArray,
Float32Array, Float32Array,
Float64Array]; Float64Array
];
function getPropertyDescriptor(object, field, expectedDepth) {
for (var depth = 0; depth < expectedDepth; depth++) {
assertFalse(Object.hasOwnProperty(object, field));
object = object.__proto__;
}
return Object.getOwnPropertyDescriptor(object, field);
}
function TestTypedArrayOf(constructor) { function TestTypedArrayOf(constructor) {
// %TypedArray%.of basics. // %TypedArray%.of basics.
...@@ -111,7 +119,7 @@ function TestTypedArrayOf(constructor) { ...@@ -111,7 +119,7 @@ function TestTypedArrayOf(constructor) {
assertEquals("pass", status); assertEquals("pass", status);
// Check superficial features of %TypedArray%.of. // Check superficial features of %TypedArray%.of.
var desc = Object.getOwnPropertyDescriptor(constructor, "of"); var desc = getPropertyDescriptor(constructor, "of", 1);
assertEquals(desc.configurable, false); assertEquals(desc.configurable, false);
assertEquals(desc.enumerable, false); assertEquals(desc.enumerable, false);
......
...@@ -121,6 +121,14 @@ TestArrayBufferSlice(); ...@@ -121,6 +121,14 @@ TestArrayBufferSlice();
// Typed arrays // Typed arrays
function getPropertyDescriptor(object, field, expectedDepth) {
for (var depth = 0; depth < expectedDepth; depth++) {
assertFalse(Object.hasOwnProperty(object, field));
object = object.__proto__;
}
return Object.getOwnPropertyDescriptor(object, field);
}
function TestTypedArray(constr, elementSize, typicalElement) { function TestTypedArray(constr, elementSize, typicalElement) {
assertSame(elementSize, constr.BYTES_PER_ELEMENT); assertSame(elementSize, constr.BYTES_PER_ELEMENT);
...@@ -269,8 +277,7 @@ function TestTypedArray(constr, elementSize, typicalElement) { ...@@ -269,8 +277,7 @@ function TestTypedArray(constr, elementSize, typicalElement) {
var a = new constr(ab, 64*elementSize, 128); var a = new constr(ab, 64*elementSize, 128);
assertEquals("[object " + constr.name + "]", assertEquals("[object " + constr.name + "]",
Object.prototype.toString.call(a)); Object.prototype.toString.call(a));
var desc = Object.getOwnPropertyDescriptor( var desc = getPropertyDescriptor(constr.prototype, Symbol.toStringTag, 1);
constr.prototype, Symbol.toStringTag);
assertTrue(desc.configurable); assertTrue(desc.configurable);
assertFalse(desc.enumerable); assertFalse(desc.enumerable);
assertFalse(!!desc.writable); assertFalse(!!desc.writable);
...@@ -417,17 +424,13 @@ var typedArrayConstructors = [ ...@@ -417,17 +424,13 @@ var typedArrayConstructors = [
function TestPropertyTypeChecks(constructor) { function TestPropertyTypeChecks(constructor) {
function CheckProperty(name) { function CheckProperty(name) {
var d = Object.getOwnPropertyDescriptor(constructor.prototype, name); var d = getPropertyDescriptor(constructor.prototype, name, 1);
var o = {}; var o = {};
assertThrows(function() {d.get.call(o);}, TypeError); assertThrows(function() {d.get.call(o);}, TypeError);
for (var i = 0; i < typedArrayConstructors.length; i++) { for (var i = 0; i < typedArrayConstructors.length; i++) {
var ctor = typedArrayConstructors[i]; var ctor = typedArrayConstructors[i];
var a = new ctor(10); var a = new ctor(10);
if (ctor === constructor) { d.get.call(a); // shouldn't throw, even from a different type
d.get.call(a); // shouldn't throw
} else {
assertThrows(function() {d.get.call(a);}, TypeError);
}
} }
} }
......
...@@ -71,14 +71,6 @@ assertEquals(undefined, get(a)); ...@@ -71,14 +71,6 @@ assertEquals(undefined, get(a));
assertEquals(undefined, get(a)); assertEquals(undefined, get(a));
})(); })();
// Ensure we cannot delete length, byteOffset, byteLength.
assertTrue(Int32Array.prototype.hasOwnProperty("length"));
assertTrue(Int32Array.prototype.hasOwnProperty("byteOffset"));
assertTrue(Int32Array.prototype.hasOwnProperty("byteLength"));
assertFalse(delete Int32Array.prototype.length);
assertFalse(delete Int32Array.prototype.byteOffset);
assertFalse(delete Int32Array.prototype.byteLength);
a = new Int32Array(100); a = new Int32Array(100);
get = function(a) { get = function(a) {
...@@ -110,3 +102,13 @@ assertEquals(0, get(a)); ...@@ -110,3 +102,13 @@ assertEquals(0, get(a));
assertEquals(0, get(a)); assertEquals(0, get(a));
%OptimizeFunctionOnNextCall(get); %OptimizeFunctionOnNextCall(get);
assertEquals(0, get(a)); assertEquals(0, get(a));
// Ensure we can delete length, byteOffset, byteLength.
for (var name of ['length', 'byteOffset', 'byteLength', 'buffer']) {
var property = Object.getOwnPropertyDescriptor(
Int32Array.prototype.__proto__, name);
assertEquals("object", typeof property);
assertEquals(true, property.configurable);
assertEquals(false, property.enumerable);
assertEquals("function", typeof property.get);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment