Revision: 16930
Author:   [email protected]
Date:     Wed Sep 25 08:19:35 2013 UTC
Log:      Speed up ArrayBuffer/typed array/DataView properties.

Optimizes byteLength, byteOffset, buffer and other properties on
ArrayBuffer, typed arrays and DataView into simple field loads. Some
unification with the way Array.length and String.length are treated.

[email protected]

Review URL: https://codereview.chromium.org/24360019
http://code.google.com/p/v8/source/detail?r=16930

Modified:
 /branches/bleeding_edge/src/accessors.cc
 /branches/bleeding_edge/src/accessors.h
 /branches/bleeding_edge/src/heap.h
 /branches/bleeding_edge/src/hydrogen-instructions.h
 /branches/bleeding_edge/src/hydrogen.cc
 /branches/bleeding_edge/src/hydrogen.h
 /branches/bleeding_edge/src/ic.cc

=======================================
--- /branches/bleeding_edge/src/accessors.cc    Thu Sep 12 13:27:42 2013 UTC
+++ /branches/bleeding_edge/src/accessors.cc    Wed Sep 25 08:19:35 2013 UTC
@@ -76,6 +76,61 @@
   // read-only properties must be silently ignored.
   return value;
 }
+
+
+static V8_INLINE bool CheckForName(Handle<String> name,
+                                   String* property_name,
+                                   int offset,
+                                   int* object_offset) {
+  if (name->Equals(property_name)) {
+    *object_offset = offset;
+    return true;
+  }
+  return false;
+}
+
+
+bool Accessors::IsJSObjectFieldAccessor(
+      Handle<Map> map, Handle<String> name,
+      int* object_offset) {
+  Isolate* isolate = map->GetIsolate();
+  switch (map->instance_type()) {
+    case JS_ARRAY_TYPE:
+      return
+        CheckForName(name, isolate->heap()->length_string(),
+                     JSArray::kLengthOffset, object_offset);
+    case JS_TYPED_ARRAY_TYPE:
+      return
+        CheckForName(name, isolate->heap()->length_string(),
+                     JSTypedArray::kLengthOffset, object_offset) ||
+        CheckForName(name, isolate->heap()->byte_length_string(),
+                     JSTypedArray::kByteLengthOffset, object_offset) ||
+        CheckForName(name, isolate->heap()->byte_offset_string(),
+                     JSTypedArray::kByteOffsetOffset, object_offset) ||
+        CheckForName(name, isolate->heap()->buffer_string(),
+                     JSTypedArray::kBufferOffset, object_offset);
+    case JS_ARRAY_BUFFER_TYPE:
+      return
+        CheckForName(name, isolate->heap()->byte_length_string(),
+                     JSArrayBuffer::kByteLengthOffset, object_offset);
+    case JS_DATA_VIEW_TYPE:
+      return
+        CheckForName(name, isolate->heap()->byte_length_string(),
+                     JSDataView::kByteLengthOffset, object_offset) ||
+        CheckForName(name, isolate->heap()->byte_offset_string(),
+                     JSDataView::kByteOffsetOffset, object_offset) ||
+        CheckForName(name, isolate->heap()->buffer_string(),
+                     JSDataView::kBufferOffset, object_offset);
+    default: {
+      if (map->instance_type() < FIRST_NONSTRING_TYPE) {
+        return
+          CheckForName(name, isolate->heap()->length_string(),
+                       String::kLengthOffset, object_offset);
+      }
+      return false;
+    }
+  }
+}


 //
=======================================
--- /branches/bleeding_edge/src/accessors.h     Mon Sep  2 09:25:20 2013 UTC
+++ /branches/bleeding_edge/src/accessors.h     Wed Sep 25 08:19:35 2013 UTC
@@ -86,6 +86,13 @@
   static Handle<AccessorInfo> MakeModuleExport(
       Handle<String> name, int index, PropertyAttributes attributes);

+  // Returns true for properties that are accessors to object fields.
+  // If true, *object_offset contains offset of object field.
+  static bool IsJSObjectFieldAccessor(
+      Handle<Map> map, Handle<String> name,
+      int* object_offset);
+
+
  private:
   // Accessor functions only used through the descriptor.
   static MaybeObject* FunctionSetPrototype(Isolate* isolate,
=======================================
--- /branches/bleeding_edge/src/heap.h  Mon Sep 23 14:48:49 2013 UTC
+++ /branches/bleeding_edge/src/heap.h  Wed Sep 25 08:19:35 2013 UTC
@@ -292,7 +292,10 @@
   V(throw_string, "throw")                                               \
   V(done_string, "done")                                                 \
   V(value_string, "value")                                               \
-  V(next_string, "next")
+  V(next_string, "next")                                                 \
+  V(byte_length_string, "byteLength")                                    \
+  V(byte_offset_string, "byteOffset")                                    \
+  V(buffer_string, "buffer")

 // Forward declarations.
 class GCTracer;
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.h Tue Sep 24 10:30:41 2013 UTC +++ /branches/bleeding_edge/src/hydrogen-instructions.h Wed Sep 25 08:19:35 2013 UTC
@@ -5625,13 +5625,6 @@
             FLAG_track_fields
                 ? Representation::Smi() : Representation::Tagged());
   }
-
-  static HObjectAccess ForTypedArrayLength() {
-    return HObjectAccess(
-        kInobject,
-        JSTypedArray::kLengthOffset,
-        Representation::Tagged());
-  }

   static HObjectAccess ForAllocationSiteTransitionInfo() {
     return HObjectAccess(kInobject, AllocationSite::kTransitionInfoOffset);
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc     Tue Sep 24 09:48:39 2013 UTC
+++ /branches/bleeding_edge/src/hydrogen.cc     Wed Sep 25 08:19:35 2013 UTC
@@ -4766,7 +4766,7 @@

 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadMonomorphic() {
   if (!CanInlinePropertyAccess(*map_)) return IsStringLength();
-  if (IsArrayLength()) return true;
+  if (IsJSObjectFieldAccessor()) return true;
   if (!LookupDescriptor()) return false;
   if (lookup_.IsFound()) return true;
   return LookupInPrototypes();
@@ -4798,9 +4798,10 @@
     return true;
   }

-  if (IsTypedArrayLength()) {
+  if (IsJSObjectFieldAccessor()) {
+    InstanceType instance_type = map_->instance_type();
     for (int i = 1; i < types->length(); ++i) {
- if (types->at(i)->instance_type() != JS_TYPED_ARRAY_TYPE) return false;
+      if (types->at(i)->instance_type() != instance_type) return false;
     }
     return true;
   }
@@ -4821,20 +4822,10 @@
     BailoutId ast_id,
     BailoutId return_id,
     bool can_inline_accessor) {
-  if (info->IsStringLength()) {
-    return New<HLoadNamedField>(
-        checked_object, HObjectAccess::ForStringLength());
-  }

-  if (info->IsArrayLength()) {
-    return New<HLoadNamedField>(
-        checked_object, HObjectAccess::ForArrayLength(
-            info->map()->elements_kind()));
-  }
-
-  if (info->IsTypedArrayLength()) {
-    return New<HLoadNamedField>(
-        checked_object, HObjectAccess::ForTypedArrayLength());
+  HObjectAccess access = HObjectAccess::ForMap();  // bogus default
+  if (info->GetJSObjectFieldAccess(&access)) {
+    return New<HLoadNamedField>(checked_object, access);
   }

   HValue* checked_holder = checked_object;
@@ -5536,16 +5527,6 @@
   return new(zone()) HLoadNamedGeneric(context, object, name);
 }

-
-HInstruction* HOptimizedGraphBuilder::BuildCallGetter(
-    HValue* object,
-    Handle<Map> map,
-    Handle<JSFunction> getter,
-    Handle<JSObject> holder) {
-  AddCheckConstantFunction(holder, object, map);
-  Add<HPushArgument>(object);
-  return new(zone()) HCallConstantFunction(getter, 1);
-}


 HInstruction* HOptimizedGraphBuilder::BuildLoadKeyedGeneric(HValue* object,
=======================================
--- /branches/bleeding_edge/src/hydrogen.h      Tue Sep 24 09:48:39 2013 UTC
+++ /branches/bleeding_edge/src/hydrogen.h      Wed Sep 25 08:19:35 2013 UTC
@@ -30,6 +30,7 @@

 #include "v8.h"

+#include "accessors.h"
 #include "allocation.h"
 #include "ast.h"
 #include "compiler.h"
@@ -2046,19 +2047,26 @@
     // PropertyAccessInfo is built for types->first().
     bool CanLoadAsMonomorphic(SmallMapList* types);

-    bool IsStringLength() {
-      return map_->instance_type() < FIRST_NONSTRING_TYPE &&
-          name_->Equals(isolate()->heap()->length_string());
-    }
-
-    bool IsArrayLength() {
-      return map_->instance_type() == JS_ARRAY_TYPE &&
-          name_->Equals(isolate()->heap()->length_string());
+    bool IsJSObjectFieldAccessor() {
+      int offset;  // unused
+      return Accessors::IsJSObjectFieldAccessor(map_, name_, &offset);
     }

-    bool IsTypedArrayLength() {
-      return map_->instance_type() == JS_TYPED_ARRAY_TYPE &&
-          name_->Equals(isolate()->heap()->length_string());
+    bool GetJSObjectFieldAccess(HObjectAccess* access) {
+      if (IsStringLength()) {
+        *access = HObjectAccess::ForStringLength();
+        return true;
+      } else if (IsArrayLength()) {
+        *access = HObjectAccess::ForArrayLength(map_->elements_kind());
+        return true;
+      } else {
+        int offset;
+        if (Accessors::IsJSObjectFieldAccessor(map_, name_, &offset)) {
+          *access = HObjectAccess::ForJSObjectOffset(offset);
+          return true;
+        }
+        return false;
+      }
     }

     bool has_holder() { return !holder_.is_null(); }
@@ -2072,6 +2080,16 @@

    private:
     Isolate* isolate() { return lookup_.isolate(); }
+
+    bool IsStringLength() {
+      return map_->instance_type() < FIRST_NONSTRING_TYPE &&
+          name_->Equals(isolate()->heap()->length_string());
+    }
+
+    bool IsArrayLength() {
+      return map_->instance_type() == JS_ARRAY_TYPE &&
+          name_->Equals(isolate()->heap()->length_string());
+    }

     bool LoadResult(Handle<Map> map);
     bool LookupDescriptor();
@@ -2173,10 +2191,6 @@
   HInstruction* BuildLoadNamedGeneric(HValue* object,
                                       Handle<String> name,
                                       Property* expr);
-  HInstruction* BuildCallGetter(HValue* object,
-                                Handle<Map> map,
-                                Handle<JSFunction> getter,
-                                Handle<JSObject> holder);

   HCheckMaps* AddCheckMap(HValue* object, Handle<Map> map);

=======================================
--- /branches/bleeding_edge/src/ic.cc   Thu Sep 19 18:19:24 2013 UTC
+++ /branches/bleeding_edge/src/ic.cc   Wed Sep 25 08:19:35 2013 UTC
@@ -1348,20 +1348,19 @@
       if (!holder.is_identical_to(receiver)) break;
       return isolate()->stub_cache()->ComputeLoadNormal(name, receiver);
     case CALLBACKS: {
-      Handle<Object> callback(lookup->GetCallbackObject(), isolate());
-      if (name->Equals(isolate()->heap()->length_string())) {
-        if (receiver->IsJSArray()) {
-          PropertyIndex lengthIndex = PropertyIndex::NewHeaderIndex(
-              JSArray::kLengthOffset / kPointerSize);
-          return isolate()->stub_cache()->ComputeLoadField(
- name, receiver, receiver, lengthIndex, Representation::Tagged());
-        } else if (receiver->IsJSTypedArray()) {
-          PropertyIndex lengthIndex = PropertyIndex::NewHeaderIndex(
-              JSTypedArray::kLengthOffset / kPointerSize);
+      {
+        // Use simple field loads for some well-known callback properties.
+        int object_offset;
+        Handle<Map> map(receiver->map());
+ if (Accessors::IsJSObjectFieldAccessor(map, name, &object_offset)) {
+          PropertyIndex index =
+              PropertyIndex::NewHeaderIndex(object_offset / kPointerSize);
           return isolate()->stub_cache()->ComputeLoadField(
- name, receiver, receiver, lengthIndex, Representation::Tagged());
+              name, receiver, receiver, index, Representation::Tagged());
         }
       }
+
+      Handle<Object> callback(lookup->GetCallbackObject(), isolate());
       if (callback->IsExecutableAccessorInfo()) {
         Handle<ExecutableAccessorInfo> info =
             Handle<ExecutableAccessorInfo>::cast(callback);

--
--
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/groups/opt_out.

Reply via email to