Browse Source

deps: cherry-pick 6da51b4 from v8's upstream

Original commit message:

    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}

Benchmark results:

   buffers/buffer-iterate.js size=16386 type=slow method=for n=1000:
   ./node: 71607 node: 8702.3 ............ 722.85%

Improvement depends on the code, but generally brings us back to the
performance that we had before the v8 update (if not making it
faster).

Fixes: https://github.com/nodejs/node/issues/2463
PR-URL: https://github.com/nodejs/node/pull/2801
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
v4.x
Fedor Indutny 9 years ago
committed by Rod Vagg
parent
commit
6098504685
  1. 41
      deps/v8/src/accessors.cc
  2. 37
      deps/v8/test/mjsunit/regress/regress-typedarray-length.js

41
deps/v8/src/accessors.cc

@ -100,22 +100,37 @@ bool Accessors::IsJSArrayBufferViewFieldAccessor(Handle<Map> map,
Isolate* isolate = name->GetIsolate(); Isolate* isolate = name->GetIsolate();
switch (map->instance_type()) { switch (map->instance_type()) {
case JS_TYPED_ARRAY_TYPE: case JS_TYPED_ARRAY_TYPE: {
// %TypedArray%.prototype is non-configurable, and so are the following if (!CheckForName(name, isolate->factory()->length_string(),
// named properties on %TypedArray%.prototype, so we can directly inline JSTypedArray::kLengthOffset, object_offset) &&
// the field-load for typed array maps that still use their !CheckForName(name, isolate->factory()->byte_length_string(),
// %TypedArray%.prototype. JSTypedArray::kByteLengthOffset, object_offset) &&
if (JSFunction::cast(map->GetConstructor())->prototype() != !CheckForName(name, isolate->factory()->byte_offset_string(),
map->prototype()) { JSTypedArray::kByteOffsetOffset, object_offset)) {
return false; 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<Object> proto = Handle<Object>(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<Object>() == original_proto;
}
case JS_DATA_VIEW_TYPE: case JS_DATA_VIEW_TYPE:
return CheckForName(name, isolate->factory()->byte_length_string(), return CheckForName(name, isolate->factory()->byte_length_string(),
JSDataView::kByteLengthOffset, object_offset) || JSDataView::kByteLengthOffset, object_offset) ||

37
deps/v8/test/mjsunit/regress/regress-typedarray-length.js

@ -71,6 +71,43 @@ assertEquals(undefined, get(a));
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. // Ensure we cannot delete length, byteOffset, byteLength.
assertTrue(Int32Array.prototype.hasOwnProperty("length")); assertTrue(Int32Array.prototype.hasOwnProperty("length"));
assertTrue(Int32Array.prototype.hasOwnProperty("byteOffset")); assertTrue(Int32Array.prototype.hasOwnProperty("byteOffset"));

Loading…
Cancel
Save