Skip to content

Commit 6da51b4

Browse files
indutnyCommit bot
authored andcommitted
TypedArray accessor detection: consider entire prototype chain
When looking up a special accessor for known TypedArray fields ("length", "byteLength", "byteOffset"), consider the entire prototype chain, not only the direct prototype. This allows subclasses of TypedArrays to benefit from fast specialized accesses. Review URL: https://codereview.chromium.org/1313493005 Cr-Commit-Position: refs/heads/master@{#30678}
1 parent ebd16fd commit 6da51b4

File tree

2 files changed

+65
-13
lines changed

2 files changed

+65
-13
lines changed

src/accessors.cc

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -99,22 +99,37 @@ bool Accessors::IsJSArrayBufferViewFieldAccessor(Handle<Map> map,
9999
Isolate* isolate = name->GetIsolate();
100100

101101
switch (map->instance_type()) {
102-
case JS_TYPED_ARRAY_TYPE:
103-
// %TypedArray%.prototype is non-configurable, and so are the following
104-
// named properties on %TypedArray%.prototype, so we can directly inline
105-
// the field-load for typed array maps that still use their
106-
// %TypedArray%.prototype.
107-
if (JSFunction::cast(map->GetConstructor())->prototype() !=
108-
map->prototype()) {
102+
case JS_TYPED_ARRAY_TYPE: {
103+
if (!CheckForName(name, isolate->factory()->length_string(),
104+
JSTypedArray::kLengthOffset, object_offset) &&
105+
!CheckForName(name, isolate->factory()->byte_length_string(),
106+
JSTypedArray::kByteLengthOffset, object_offset) &&
107+
!CheckForName(name, isolate->factory()->byte_offset_string(),
108+
JSTypedArray::kByteOffsetOffset, object_offset)) {
109109
return false;
110110
}
111-
return CheckForName(name, isolate->factory()->length_string(),
112-
JSTypedArray::kLengthOffset, object_offset) ||
113-
CheckForName(name, isolate->factory()->byte_length_string(),
114-
JSTypedArray::kByteLengthOffset, object_offset) ||
115-
CheckForName(name, isolate->factory()->byte_offset_string(),
116-
JSTypedArray::kByteOffsetOffset, object_offset);
117111

112+
if (map->is_dictionary_map()) return false;
113+
114+
// Check if the property is overridden on the instance.
115+
DescriptorArray* descriptors = map->instance_descriptors();
116+
int descriptor = descriptors->SearchWithCache(*name, *map);
117+
if (descriptor != DescriptorArray::kNotFound) return false;
118+
119+
Handle<Object> proto = Handle<Object>(map->prototype(), isolate);
120+
if (!proto->IsJSReceiver()) return false;
121+
122+
// Check if the property is defined in the prototype chain.
123+
LookupIterator it(proto, name);
124+
if (!it.IsFound()) return false;
125+
126+
Object* original_proto =
127+
JSFunction::cast(map->GetConstructor())->prototype();
128+
129+
// Property is not configurable. It is enough to verify that
130+
// the holder is the same.
131+
return *it.GetHolder<Object>() == original_proto;
132+
}
118133
case JS_DATA_VIEW_TYPE:
119134
return CheckForName(name, isolate->factory()->byte_length_string(),
120135
JSDataView::kByteLengthOffset, object_offset) ||

test/mjsunit/regress/regress-typedarray-length.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,43 @@ assertEquals(undefined, get(a));
7171
assertEquals(undefined, get(a));
7272
})();
7373

74+
(function() {
75+
"use strict";
76+
77+
class MyTypedArray extends Int32Array {
78+
constructor(length) {
79+
super(length);
80+
}
81+
}
82+
83+
a = new MyTypedArray(1024);
84+
85+
get = function(a) {
86+
return a.length;
87+
}
88+
89+
assertEquals(1024, get(a));
90+
assertEquals(1024, get(a));
91+
assertEquals(1024, get(a));
92+
%OptimizeFunctionOnNextCall(get);
93+
assertEquals(1024, get(a));
94+
})();
95+
96+
(function() {
97+
"use strict";
98+
var a = new Uint8Array(4);
99+
Object.defineProperty(a, "length", {get: function() { return "blah"; }});
100+
get = function(a) {
101+
return a.length;
102+
}
103+
104+
assertEquals("blah", get(a));
105+
assertEquals("blah", get(a));
106+
assertEquals("blah", get(a));
107+
%OptimizeFunctionOnNextCall(get);
108+
assertEquals("blah", get(a));
109+
})();
110+
74111
// Ensure we cannot delete length, byteOffset, byteLength.
75112
assertTrue(Int32Array.prototype.hasOwnProperty("length"));
76113
assertTrue(Int32Array.prototype.hasOwnProperty("byteOffset"));

0 commit comments

Comments
 (0)