Reviewers: Jakob,

Message:
ptal

Description:
Add fast path for setting array.length

BUG=

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

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

Affected files (+47, -46 lines):
  M src/accessors.h
  M src/accessors.cc
  M src/objects.h


Index: src/accessors.cc
diff --git a/src/accessors.cc b/src/accessors.cc
index 58db0024ea1b2f824e15fa634e07befa10aa5bc7..5743c7552f1ae7539dec267a87b3bdd6b5c705f5 100644
--- a/src/accessors.cc
+++ b/src/accessors.cc
@@ -173,21 +173,6 @@ Handle<AccessorInfo> Accessors::ArgumentsIteratorInfo(
 //


-// The helper function will 'flatten' Number objects.
-Handle<Object> Accessors::FlattenNumber(Isolate* isolate,
-                                        Handle<Object> value) {
-  if (value->IsNumber() || !value->IsJSValue()) return value;
-  Handle<JSValue> wrapper = Handle<JSValue>::cast(value);
-  DCHECK(wrapper->GetIsolate()->native_context()->number_function()->
-      has_initial_map());
-  if (wrapper->map() == isolate->number_function()->initial_map()) {
-    return handle(wrapper->value(), isolate);
-  }
-
-  return value;
-}
-
-
 void Accessors::ArrayLengthGetter(
     v8::Local<v8::Name> name,
     const v8::PropertyCallbackInfo<v8::Value>& info) {
@@ -200,44 +185,64 @@ void Accessors::ArrayLengthGetter(
 }


+// Tries to non-observably convert |value| to a valid array length.
+// Returns false if it fails.
+static bool FastAsArrayLength(Isolate* isolate, Handle<Object> value,
+                              uint32_t* length) {
+  if (value->ToArrayLength(length)) return true;
+  // We don't support AsArrayLength, so use AsArrayIndex for now. This just
+  // misses out on kMaxUInt32.
+  if (value->IsString()) return String::cast(*value)->AsArrayIndex(length);
+  if (!value->IsJSValue()) return false;
+  Handle<JSValue> wrapper = Handle<JSValue>::cast(value);
+  DCHECK(wrapper->GetIsolate()
+             ->native_context()
+             ->number_function()
+             ->has_initial_map());
+ // Only support fast unwrapping for the initial map. Otherwise valueOf might
+  // have been overwritten, in which case unwrapping is invalid.
+ if (wrapper->map() != isolate->number_function()->initial_map()) return false;
+  return wrapper->value()->ToArrayIndex(length);
+}
+
+
 void Accessors::ArrayLengthSetter(
     v8::Local<v8::Name> name,
     v8::Local<v8::Value> val,
     const v8::PropertyCallbackInfo<void>& info) {
-  // TODO(verwaest): Speed up.
   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
   HandleScope scope(isolate);
+
   Handle<JSObject> object = Utils::OpenHandle(*info.This());
-  Handle<Object> value = Utils::OpenHandle(*val);
+  Handle<JSArray> array = Handle<JSArray>::cast(object);
+  Handle<Object> length_obj = Utils::OpenHandle(*val);
+
+  uint32_t length = 0;
+  if (!FastAsArrayLength(isolate, length_obj, &length)) {
+    Handle<Object> uint32_v;
+    if (!Execution::ToUint32(isolate, length_obj).ToHandle(&uint32_v)) {
+      isolate->OptionalRescheduleException(false);
+      return;
+    }

-  value = FlattenNumber(isolate, value);
+    Handle<Object> number_v;
+    if (!Execution::ToNumber(isolate, length_obj).ToHandle(&number_v)) {
+      isolate->OptionalRescheduleException(false);
+      return;
+    }

-  Handle<JSArray> array_handle = Handle<JSArray>::cast(object);
-  MaybeHandle<Object> maybe;
-  Handle<Object> uint32_v;
-  maybe = Execution::ToUint32(isolate, value);
-  if (!maybe.ToHandle(&uint32_v)) {
-    isolate->OptionalRescheduleException(false);
-    return;
-  }
-  Handle<Object> number_v;
-  maybe = Execution::ToNumber(isolate, value);
-  if (!maybe.ToHandle(&number_v)) {
-    isolate->OptionalRescheduleException(false);
-    return;
-  }
+    if (uint32_v->Number() != number_v->Number()) {
+      Handle<Object> exception = isolate->factory()->NewRangeError(
+          MessageTemplate::kInvalidArrayLength);
+      return isolate->ScheduleThrow(*exception);
+    }

-  if (uint32_v->Number() == number_v->Number()) {
-    uint32_t new_length = 0;
-    CHECK(uint32_v->ToArrayLength(&new_length));
-    maybe = JSArray::ObservableSetLength(array_handle, new_length);
-    if (maybe.is_null()) isolate->OptionalRescheduleException(false);
-    return;
+    CHECK(uint32_v->ToArrayLength(&length));
   }

-  Handle<Object> exception =
- isolate->factory()->NewRangeError(MessageTemplate::kInvalidArrayLength);
-  isolate->ScheduleThrow(*exception);
+  if (JSArray::ObservableSetLength(array, length).is_null()) {
+    isolate->OptionalRescheduleException(false);
+  }
 }


Index: src/accessors.h
diff --git a/src/accessors.h b/src/accessors.h
index d37b6b770cafa5db88b3ed2bf3ef0005e90590be..227af745b70a49328fbf9005eb5ed123c873b330 100644
--- a/src/accessors.h
+++ b/src/accessors.h
@@ -98,11 +98,6 @@ class Accessors : public AllStatic {
   static Handle<ExecutableAccessorInfo> CloneAccessor(
       Isolate* isolate,
       Handle<ExecutableAccessorInfo> accessor);
-
-
- private:
-  // Helper functions.
- static Handle<Object> FlattenNumber(Isolate* isolate, Handle<Object> value);
 };

 } }  // namespace v8::internal
Index: src/objects.h
diff --git a/src/objects.h b/src/objects.h
index 0cfee84e9ee14192b5ec994640a2e5af6dc1b2d3..6ec7ccc8ead2c81f2190649801f9b192fd9d7f44 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -8577,6 +8577,7 @@ class Name: public HeapObject {

   // Conversion.
   inline bool AsArrayIndex(uint32_t* index);
+  inline bool AsArrayLength(uint32_t* index);

   // If the name is private, it can only name own properties.
   inline bool IsPrivate();


--
--
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