diff --git a/src/accessors.cc b/src/accessors.cc index 9850cd388e4..e77dedbaeb8 100644 --- a/src/accessors.cc +++ b/src/accessors.cc @@ -100,22 +100,37 @@ bool Accessors::IsJSArrayBufferViewFieldAccessor(Handle map, Isolate* isolate = name->GetIsolate(); switch (map->instance_type()) { - case JS_TYPED_ARRAY_TYPE: - // %TypedArray%.prototype is non-configurable, and so are the following - // named properties on %TypedArray%.prototype, so we can directly inline - // the field-load for typed array maps that still use their - // %TypedArray%.prototype. - if (JSFunction::cast(map->GetConstructor())->prototype() != - map->prototype()) { + case JS_TYPED_ARRAY_TYPE: { + if (!CheckForName(name, isolate->factory()->length_string(), + JSTypedArray::kLengthOffset, object_offset) && + !CheckForName(name, isolate->factory()->byte_length_string(), + JSTypedArray::kByteLengthOffset, object_offset) && + !CheckForName(name, isolate->factory()->byte_offset_string(), + JSTypedArray::kByteOffsetOffset, object_offset)) { return false; } - return CheckForName(name, isolate->factory()->length_string(), - JSTypedArray::kLengthOffset, object_offset) || - CheckForName(name, isolate->factory()->byte_length_string(), - JSTypedArray::kByteLengthOffset, object_offset) || - CheckForName(name, isolate->factory()->byte_offset_string(), - JSTypedArray::kByteOffsetOffset, object_offset); + if (map->is_dictionary_map()) return false; + + // Check if the property is overridden on the instance. + DescriptorArray* descriptors = map->instance_descriptors(); + int descriptor = descriptors->SearchWithCache(*name, *map); + if (descriptor != DescriptorArray::kNotFound) return false; + + Handle proto = Handle(map->prototype(), isolate); + if (!proto->IsJSReceiver()) return false; + + // Check if the property is defined in the prototype chain. + LookupIterator it(proto, name); + if (!it.IsFound()) return false; + + Object* original_proto = + JSFunction::cast(map->GetConstructor())->prototype(); + + // Property is not configurable. It is enough to verify that + // the holder is the same. + return *it.GetHolder() == original_proto; + } case JS_DATA_VIEW_TYPE: return CheckForName(name, isolate->factory()->byte_length_string(), JSDataView::kByteLengthOffset, object_offset) || diff --git a/test/mjsunit/regress/regress-typedarray-length.js b/test/mjsunit/regress/regress-typedarray-length.js index cae55731f92..ee853647355 100644 --- a/test/mjsunit/regress/regress-typedarray-length.js +++ b/test/mjsunit/regress/regress-typedarray-length.js @@ -71,6 +71,43 @@ assertEquals(undefined, get(a)); assertEquals(undefined, get(a)); })(); +(function() { + "use strict"; + + class MyTypedArray extends Int32Array { + constructor(length) { + super(length); + } + } + + a = new MyTypedArray(1024); + + get = function(a) { + return a.length; + } + + assertEquals(1024, get(a)); + assertEquals(1024, get(a)); + assertEquals(1024, get(a)); + %OptimizeFunctionOnNextCall(get); + assertEquals(1024, get(a)); +})(); + +(function() { + "use strict"; + var a = new Uint8Array(4); + Object.defineProperty(a, "length", {get: function() { return "blah"; }}); + get = function(a) { + return a.length; + } + + assertEquals("blah", get(a)); + assertEquals("blah", get(a)); + assertEquals("blah", get(a)); + %OptimizeFunctionOnNextCall(get); + assertEquals("blah", get(a)); +})(); + // Ensure we cannot delete length, byteOffset, byteLength. assertTrue(Int32Array.prototype.hasOwnProperty("length")); assertTrue(Int32Array.prototype.hasOwnProperty("byteOffset"));