Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(49)

Unified Diff: src/builtins.cc

Issue 650043: Faster moving FixedArray elements around. (Closed)
Patch Set: First round of Soren's comments Created 10 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/array.js ('k') | src/objects.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/builtins.cc
diff --git a/src/builtins.cc b/src/builtins.cc
index 8e88c28695599a1e71f54d633ca53febb545d76a..27a32fa01d272981a18c71d7a8e895672b461352 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -362,7 +362,56 @@ BUILTIN(ArrayShift) {
}
+static Object* CallJsBuiltin(const char* name,
+ BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
+ HandleScope handleScope;
+
+ Handle<Object> js_builtin =
+ GetProperty(Handle<JSObject>(Top::global_context()->builtins()),
+ name);
+ ASSERT(js_builtin->IsJSFunction());
+ Handle<JSFunction> function(Handle<JSFunction>::cast(js_builtin));
+ Vector<Object**> argv(Vector<Object**>::New(args.length() - 1));
+ int n_args = args.length() - 1;
+ for (int i = 0; i < n_args; i++) {
+ argv[i] = &args[i + 1];
+ }
+ bool pending_exception = false;
+ Handle<Object> result = Execution::Call(function,
+ args.receiver(),
+ n_args,
+ argv.start(),
+ &pending_exception);
+ if (pending_exception) return Failure::Exception();
+ return *result;
+}
+
+
+static bool ArrayPrototypeHasNoElements() {
+ // This method depends on non writability of Object and Array prototype
+ // fields.
+ Context* global_context = Top::context()->global_context();
+ // Array.prototype
+ JSObject* proto =
+ JSObject::cast(global_context->array_function()->prototype());
+ if (proto->elements() != Heap::empty_fixed_array()) return false;
+ // Hidden prototype
+ proto = JSObject::cast(proto->GetPrototype());
+ ASSERT(proto->elements() == Heap::empty_fixed_array());
+ // Object.prototype
+ proto = JSObject::cast(proto->GetPrototype());
+ if (proto != global_context->initial_object_prototype()) return false;
+ if (proto->elements() != Heap::empty_fixed_array()) return false;
+ ASSERT(proto->GetPrototype()->IsNull());
+ return true;
+}
+
+
BUILTIN(ArrayUnshift) {
+ if (!ArrayPrototypeHasNoElements()) {
+ return CallJsBuiltin("ArrayUnshift", args);
+ }
+
JSArray* array = JSArray::cast(*args.receiver());
ASSERT(array->HasFastElements());
@@ -379,45 +428,44 @@ BUILTIN(ArrayUnshift) {
FixedArray* elms = FixedArray::cast(array->elements());
- // Fetch the prototype.
- JSFunction* array_function =
- Top::context()->global_context()->array_function();
- JSObject* prototype = JSObject::cast(array_function->prototype());
-
if (new_length > elms->length()) {
// New backing storage is needed.
int capacity = new_length + (new_length >> 1) + 16;
- Object* obj = Heap::AllocateFixedArrayWithHoles(capacity);
+ Object* obj = Heap::AllocateRawFixedArray(capacity);
if (obj->IsFailure()) return obj;
- AssertNoAllocation no_gc;
+ reinterpret_cast<Array*>(obj)->set_map(Heap::fixed_array_map());
FixedArray* new_elms = FixedArray::cast(obj);
- WriteBarrierMode mode = new_elms->GetWriteBarrierMode(no_gc);
- // Fill out the new array with old elements.
- for (int i = 0; i < len; i++)
- new_elms->set(to_add + i,
- GetElementToMove(i, elms, prototype),
- mode);
+ new_elms->set_length(capacity);
+
+ Object** new_elms_data = new_elms->data_start();
+ memcpy(new_elms_data + to_add, elms->data_start(), len * kPointerSize);
+
+ // Let's hope that compiler can easily optimize this filling code.
+ Object* hole = Heap::the_hole_value();
+ for (int i = new_length; i < capacity; i++) {
+ new_elms_data[i] = hole;
+ }
elms = new_elms;
array->set_elements(elms);
} else {
- AssertNoAllocation no_gc;
- WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
-
- // Move elements to the right
- for (int i = 0; i < len; i++) {
- elms->set(new_length - i - 1,
- GetElementToMove(len - i - 1, elms, prototype),
- mode);
- }
+ memmove(elms->data_start() + to_add,
+ elms->data_start(),
+ len * kPointerSize);
}
// Add the provided values.
AssertNoAllocation no_gc;
- WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
for (int i = 0; i < to_add; i++) {
- elms->set(i, args[i + 1], mode);
+ elms->set(i, args[i + 1], SKIP_WRITE_BARRIER);
+ }
+ WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
+ if (mode == UPDATE_WRITE_BARRIER) {
+ Address address = elms->address();
+ for (int i = 0; i < new_length; i++) {
+ Heap::RecordWrite(address, FixedArray::kHeaderSize + i * kPointerSize);
+ }
}
// Set the length.
@@ -426,31 +474,6 @@ BUILTIN(ArrayUnshift) {
}
-static Object* CallJsBuiltin(const char* name,
- BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
- HandleScope handleScope;
-
- Handle<Object> js_builtin =
- GetProperty(Handle<JSObject>(Top::global_context()->builtins()),
- name);
- ASSERT(js_builtin->IsJSFunction());
- Handle<JSFunction> function(Handle<JSFunction>::cast(js_builtin));
- Vector<Object**> argv(Vector<Object**>::New(args.length() - 1));
- int n_args = args.length() - 1;
- for (int i = 0; i < n_args; i++) {
- argv[i] = &args[i + 1];
- }
- bool pending_exception = false;
- Handle<Object> result = Execution::Call(function,
- args.receiver(),
- n_args,
- argv.start(),
- &pending_exception);
- if (pending_exception) return Failure::Exception();
- return *result;
-}
-
-
BUILTIN(ArraySlice) {
JSArray* array = JSArray::cast(*args.receiver());
ASSERT(array->HasFastElements());
« no previous file with comments | « src/array.js ('k') | src/objects.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698