Reviewers: Michael Achenbach,

Message:
Hello!

This one seems to be very important for node.js, as we inherit our Buffer from
the Uint8Array.

Note that while we are doing some prototype twiddling:

https://github.com/nodejs/node/blob/f8152df5e815c98be702fe58753258b58f02c4ad/lib/buffer.js#L51

Buffer does not actually override neither of the accessors to the Uint8Array
properties. So it should still be optimizied into a field load.

Applying this fix improves performance in x10 times.

Thanks a lot!

Fedor.

Description:
[accessors] second-chance typed array field lookup

Give a second-chance when looking up accessor for the typed array field
(`length`, `byteLength`, `byteOffset`). Instead of just bailing out,
allow users to do a first-order inheritance from it.

BUG=

Please review this at https://codereview.chromium.org/1313493005/

Base URL: https://chromium.googlesource.com/v8/v8.git@master

Affected files (+61, -9 lines):
  M src/accessors.cc
  M test/mjsunit/regress/regress-typedarray-length.js


Index: src/accessors.cc
diff --git a/src/accessors.cc b/src/accessors.cc
index 6544e7197c1283f50f9e686643650589f1ff7aab..3d67d8751d8863688aa8a18842945915de1bd3cd 100644
--- a/src/accessors.cc
+++ b/src/accessors.cc
@@ -99,22 +99,52 @@ bool Accessors::IsJSArrayBufferViewFieldAccessor(Handle<Map> map,
   Isolate* isolate = name->GetIsolate();

   switch (map->instance_type()) {
-    case JS_TYPED_ARRAY_TYPE:
+    case JS_TYPED_ARRAY_TYPE: {
+      int offset;
+
+      if (Name::Equals(name, isolate->factory()->length_string())) {
+        offset = JSTypedArray::kLengthOffset;
+ } else if (Name::Equals(name, isolate->factory()->byte_length_string())) {
+        offset = JSTypedArray::kByteLengthOffset;
+ } else if (Name::Equals(name, isolate->factory()->byte_offset_string())) {
+        offset = JSTypedArray::kByteOffsetOffset;
+      } else {
+        return false;
+      }
+
+      Object* proto = map->prototype();
+      Object* original_proto =
+          JSFunction::cast(map->GetConstructor())->prototype();
+
// %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()) {
+      if (original_proto == proto) {
+        *object_offset = offset;
+        return true;
+      }
+
+      if (!proto->IsJSObject()) return false;
+
+      JSObject* js_proto = JSObject::cast(proto);
+
+      // Check if the typed array is a second order child of the original
+      // constructor
+      if (js_proto->map()->prototype() != original_proto) return false;
+
+      // If the middle-prototype does not override the fast property -
+      // return it's offset
+      Maybe<PropertyAttributes> maybe_attr =
+          JSReceiver::GetOwnPropertyAttributes(Handle<JSObject>(js_proto),
+                                               name);
+      if (maybe_attr.IsJust() && maybe_attr.FromJust() != ABSENT) {
         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);

+      *object_offset = offset;
+      return true;
+      }
     case JS_DATA_VIEW_TYPE:
       return CheckForName(name, isolate->factory()->byte_length_string(),
                           JSDataView::kByteLengthOffset, object_offset) ||
Index: test/mjsunit/regress/regress-typedarray-length.js
diff --git a/test/mjsunit/regress/regress-typedarray-length.js b/test/mjsunit/regress/regress-typedarray-length.js index cae55731f921ced9e26218d1b47631867aa71c30..4c76bde3c2739b92ecae67a7d81b73d975cef349 100644
--- a/test/mjsunit/regress/regress-typedarray-length.js
+++ b/test/mjsunit/regress/regress-typedarray-length.js
@@ -71,6 +71,28 @@ 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));
+})();
+
 // Ensure we cannot delete length, byteOffset, byteLength.
 assertTrue(Int32Array.prototype.hasOwnProperty("length"));
 assertTrue(Int32Array.prototype.hasOwnProperty("byteOffset"));


--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to