diff options
| author | Ben Murdoch <benm@google.com> | 2012-04-12 10:51:47 +0100 |
|---|---|---|
| committer | Ben Murdoch <benm@google.com> | 2012-04-16 16:41:38 +0100 |
| commit | 3ef787dbeca8a5fb1086949cda830dccee07bfbd (patch) | |
| tree | 0a22edd97aa148abffdd405c585b22213fccbc82 /src/builtins.cc | |
| parent | 85b71799222b55eb5dd74ea26efe0c64ab655c8c (diff) | |
| download | android_external_v8-3ef787dbeca8a5fb1086949cda830dccee07bfbd.tar.gz android_external_v8-3ef787dbeca8a5fb1086949cda830dccee07bfbd.tar.bz2 android_external_v8-3ef787dbeca8a5fb1086949cda830dccee07bfbd.zip | |
Merge V8 at 3.9.24.13
Bug: 5688872
Change-Id: Id0aa8d23375030494d3189c31774059c0f5398fc
Diffstat (limited to 'src/builtins.cc')
| -rw-r--r-- | src/builtins.cc | 490 |
1 files changed, 261 insertions, 229 deletions
diff --git a/src/builtins.cc b/src/builtins.cc index e6a0699f..0f493e6e 100644 --- a/src/builtins.cc +++ b/src/builtins.cc @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -33,6 +33,8 @@ #include "builtins.h" #include "gdb-jit.h" #include "ic-inl.h" +#include "heap-profiler.h" +#include "mark-compact.h" #include "vm-state-inl.h" namespace v8 { @@ -183,39 +185,46 @@ BUILTIN(EmptyFunction) { } -BUILTIN(ArrayCodeGeneric) { +static MaybeObject* ArrayCodeGenericCommon(Arguments* args, + Isolate* isolate, + JSFunction* constructor) { Heap* heap = isolate->heap(); isolate->counters()->array_function_runtime()->Increment(); JSArray* array; if (CalledAsConstructor(isolate)) { - array = JSArray::cast(*args.receiver()); + array = JSArray::cast((*args)[0]); + // Initialize elements and length in case later allocations fail so that the + // array object is initialized in a valid state. + array->set_length(Smi::FromInt(0)); + array->set_elements(heap->empty_fixed_array()); + if (!FLAG_smi_only_arrays) { + Context* global_context = isolate->context()->global_context(); + if (array->GetElementsKind() == FAST_SMI_ONLY_ELEMENTS && + !global_context->object_js_array_map()->IsUndefined()) { + array->set_map(Map::cast(global_context->object_js_array_map())); + } + } } else { // Allocate the JS Array - JSFunction* constructor = - isolate->context()->global_context()->array_function(); - Object* obj; - { MaybeObject* maybe_obj = heap->AllocateJSObject(constructor); - if (!maybe_obj->ToObject(&obj)) return maybe_obj; - } - array = JSArray::cast(obj); + MaybeObject* maybe_obj = heap->AllocateJSObject(constructor); + if (!maybe_obj->To(&array)) return maybe_obj; } - // 'array' now contains the JSArray we should initialize. - ASSERT(array->HasFastElements()); - // Optimize the case where there is one argument and the argument is a // small smi. - if (args.length() == 2) { - Object* obj = args[1]; + if (args->length() == 2) { + Object* obj = (*args)[1]; if (obj->IsSmi()) { int len = Smi::cast(obj)->value(); if (len >= 0 && len < JSObject::kInitialMaxFastElementArray) { - Object* obj; + Object* fixed_array; { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(len); - if (!maybe_obj->ToObject(&obj)) return maybe_obj; + if (!maybe_obj->ToObject(&fixed_array)) return maybe_obj; } - array->SetContent(FixedArray::cast(obj)); + // We do not use SetContent to skip the unnecessary elements type check. + array->set_elements(FixedArray::cast(fixed_array)); + array->set_length(Smi::cast(obj)); return array; } } @@ -223,78 +232,82 @@ BUILTIN(ArrayCodeGeneric) { { MaybeObject* maybe_obj = array->Initialize(0); if (!maybe_obj->ToObject(&obj)) return maybe_obj; } - return array->SetElementsLength(args[1]); + return array->SetElementsLength((*args)[1]); } // Optimize the case where there are no parameters passed. - if (args.length() == 1) { + if (args->length() == 1) { return array->Initialize(JSArray::kPreallocatedArrayElements); } - // Take the arguments as elements. - int number_of_elements = args.length() - 1; - Smi* len = Smi::FromInt(number_of_elements); - Object* obj; - { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(len->value()); - if (!maybe_obj->ToObject(&obj)) return maybe_obj; + // Set length and elements on the array. + int number_of_elements = args->length() - 1; + MaybeObject* maybe_object = + array->EnsureCanContainElements(args, 1, number_of_elements, + ALLOW_CONVERTED_DOUBLE_ELEMENTS); + if (maybe_object->IsFailure()) return maybe_object; + + // Allocate an appropriately typed elements array. + MaybeObject* maybe_elms; + ElementsKind elements_kind = array->GetElementsKind(); + if (elements_kind == FAST_DOUBLE_ELEMENTS) { + maybe_elms = heap->AllocateUninitializedFixedDoubleArray( + number_of_elements); + } else { + maybe_elms = heap->AllocateFixedArrayWithHoles(number_of_elements); } + FixedArrayBase* elms; + if (!maybe_elms->To<FixedArrayBase>(&elms)) return maybe_elms; - AssertNoAllocation no_gc; - FixedArray* elms = FixedArray::cast(obj); - WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); // Fill in the content - for (int index = 0; index < number_of_elements; index++) { - elms->set(index, args[index+1], mode); + switch (array->GetElementsKind()) { + case FAST_SMI_ONLY_ELEMENTS: { + FixedArray* smi_elms = FixedArray::cast(elms); + for (int index = 0; index < number_of_elements; index++) { + smi_elms->set(index, (*args)[index+1], SKIP_WRITE_BARRIER); + } + break; + } + case FAST_ELEMENTS: { + AssertNoAllocation no_gc; + WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); + FixedArray* object_elms = FixedArray::cast(elms); + for (int index = 0; index < number_of_elements; index++) { + object_elms->set(index, (*args)[index+1], mode); + } + break; + } + case FAST_DOUBLE_ELEMENTS: { + FixedDoubleArray* double_elms = FixedDoubleArray::cast(elms); + for (int index = 0; index < number_of_elements; index++) { + double_elms->set(index, (*args)[index+1]->Number()); + } + break; + } + default: + UNREACHABLE(); + break; } - // Set length and elements on the array. - array->set_elements(FixedArray::cast(obj)); - array->set_length(len); - + array->set_elements(elms); + array->set_length(Smi::FromInt(number_of_elements)); return array; } -MUST_USE_RESULT static MaybeObject* AllocateJSArray(Heap* heap) { - JSFunction* array_function = - heap->isolate()->context()->global_context()->array_function(); - Object* result; - { MaybeObject* maybe_result = heap->AllocateJSObject(array_function); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - return result; -} - - -MUST_USE_RESULT static MaybeObject* AllocateEmptyJSArray(Heap* heap) { - Object* result; - { MaybeObject* maybe_result = AllocateJSArray(heap); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - JSArray* result_array = JSArray::cast(result); - result_array->set_length(Smi::FromInt(0)); - result_array->set_elements(heap->empty_fixed_array()); - return result_array; +BUILTIN(InternalArrayCodeGeneric) { + return ArrayCodeGenericCommon( + &args, + isolate, + isolate->context()->global_context()->internal_array_function()); } -static void CopyElements(Heap* heap, - AssertNoAllocation* no_gc, - FixedArray* dst, - int dst_index, - FixedArray* src, - int src_index, - int len) { - ASSERT(dst != src); // Use MoveElements instead. - ASSERT(dst->map() != HEAP->fixed_cow_array_map()); - ASSERT(len > 0); - CopyWords(dst->data_start() + dst_index, - src->data_start() + src_index, - len); - WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc); - if (mode == UPDATE_WRITE_BARRIER) { - heap->RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len); - } +BUILTIN(ArrayCodeGeneric) { + return ArrayCodeGenericCommon( + &args, + isolate, + isolate->context()->global_context()->array_function()); } @@ -305,6 +318,7 @@ static void MoveElements(Heap* heap, FixedArray* src, int src_index, int len) { + if (len == 0) return; ASSERT(dst->map() != HEAP->fixed_cow_array_map()); memmove(dst->data_start() + dst_index, src->data_start() + src_index, @@ -313,6 +327,7 @@ static void MoveElements(Heap* heap, if (mode == UPDATE_WRITE_BARRIER) { heap->RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len); } + heap->incremental_marking()->RecordWrites(dst); } @@ -358,6 +373,16 @@ static FixedArray* LeftTrimFixedArray(Heap* heap, former_start[to_trim] = heap->fixed_array_map(); former_start[to_trim + 1] = Smi::FromInt(len - to_trim); + // Maintain marking consistency for HeapObjectIterator and + // IncrementalMarking. + int size_delta = to_trim * kPointerSize; + if (heap->marking()->TransferMark(elms->address(), + elms->address() + size_delta)) { + MemoryChunk::IncrementLiveBytesFromMutator(elms->address(), -size_delta); + } + + HEAP_PROFILE(heap, ObjectMoveEvent(elms->address(), + elms->address() + size_delta)); return FixedArray::cast(HeapObject::FromAddress( elms->address() + to_trim * kPointerSize)); } @@ -369,9 +394,6 @@ static bool ArrayPrototypeHasNoElements(Heap* heap, // This method depends on non writability of Object and Array prototype // fields. if (array_proto->elements() != heap->empty_fixed_array()) return false; - // Hidden prototype - array_proto = JSObject::cast(array_proto->GetPrototype()); - ASSERT(array_proto->elements() == heap->empty_fixed_array()); // Object.prototype Object* proto = array_proto->GetPrototype(); if (proto == heap->null_value()) return false; @@ -384,20 +406,43 @@ static bool ArrayPrototypeHasNoElements(Heap* heap, MUST_USE_RESULT static inline MaybeObject* EnsureJSArrayWithWritableFastElements( - Heap* heap, Object* receiver) { + Heap* heap, Object* receiver, Arguments* args, int first_added_arg) { if (!receiver->IsJSArray()) return NULL; JSArray* array = JSArray::cast(receiver); HeapObject* elms = array->elements(); - if (elms->map() == heap->fixed_array_map()) return elms; - if (elms->map() == heap->fixed_cow_array_map()) { - return array->EnsureWritableFastElements(); + Map* map = elms->map(); + if (map == heap->fixed_array_map()) { + if (args == NULL || !array->HasFastSmiOnlyElements()) { + return elms; + } + } else if (map == heap->fixed_cow_array_map()) { + MaybeObject* maybe_writable_result = array->EnsureWritableFastElements(); + if (args == NULL || !array->HasFastSmiOnlyElements() || + maybe_writable_result->IsFailure()) { + return maybe_writable_result; + } + } else { + return NULL; } - return NULL; + + // Need to ensure that the arguments passed in args can be contained in + // the array. + int args_length = args->length(); + if (first_added_arg >= args_length) return array->elements(); + + MaybeObject* maybe_array = array->EnsureCanContainElements( + args, + first_added_arg, + args_length - first_added_arg, + DONT_ALLOW_DOUBLE_ELEMENTS); + if (maybe_array->IsFailure()) return maybe_array; + return array->elements(); } static inline bool IsJSArrayFastElementMovingAllowed(Heap* heap, JSArray* receiver) { + if (!FLAG_clever_optimizations) return false; Context* global_context = heap->isolate()->context()->global_context(); JSObject* array_proto = JSObject::cast(global_context->array_function()->prototype()); @@ -413,20 +458,18 @@ MUST_USE_RESULT static MaybeObject* CallJsBuiltin( HandleScope handleScope(isolate); Handle<Object> js_builtin = - GetProperty(Handle<JSObject>( - isolate->global_context()->builtins()), - name); - ASSERT(js_builtin->IsJSFunction()); - Handle<JSFunction> function(Handle<JSFunction>::cast(js_builtin)); - ScopedVector<Object**> argv(args.length() - 1); - int n_args = args.length() - 1; - for (int i = 0; i < n_args; i++) { - argv[i] = args.at<Object>(i + 1).location(); + GetProperty(Handle<JSObject>(isolate->global_context()->builtins()), + name); + Handle<JSFunction> function = Handle<JSFunction>::cast(js_builtin); + int argc = args.length() - 1; + ScopedVector<Handle<Object> > argv(argc); + for (int i = 0; i < argc; ++i) { + argv[i] = args.at<Object>(i + 1); } - bool pending_exception = false; + bool pending_exception; Handle<Object> result = Execution::Call(function, args.receiver(), - n_args, + argc, argv.start(), &pending_exception); if (pending_exception) return Failure::Exception(); @@ -439,7 +482,7 @@ BUILTIN(ArrayPush) { Object* receiver = *args.receiver(); Object* elms_obj; { MaybeObject* maybe_elms_obj = - EnsureJSArrayWithWritableFastElements(heap, receiver); + EnsureJSArrayWithWritableFastElements(heap, receiver, &args, 1); if (maybe_elms_obj == NULL) { return CallJsBuiltin(isolate, "ArrayPush", args); } @@ -468,14 +511,11 @@ BUILTIN(ArrayPush) { } FixedArray* new_elms = FixedArray::cast(obj); - AssertNoAllocation no_gc; - if (len > 0) { - CopyElements(heap, &no_gc, new_elms, 0, elms, 0, len); - } + CopyObjectToObjectElements(elms, FAST_ELEMENTS, 0, + new_elms, FAST_ELEMENTS, 0, len); FillWithHoles(heap, new_elms, new_length, capacity); elms = new_elms; - array->set_elements(elms); } // Add the provided values. @@ -485,6 +525,10 @@ BUILTIN(ArrayPush) { elms->set(index + len, args[index + 1], mode); } + if (elms != array->elements()) { + array->set_elements(elms); + } + // Set the length. array->set_length(Smi::FromInt(new_length)); return Smi::FromInt(new_length); @@ -496,7 +540,7 @@ BUILTIN(ArrayPop) { Object* receiver = *args.receiver(); Object* elms_obj; { MaybeObject* maybe_elms_obj = - EnsureJSArrayWithWritableFastElements(heap, receiver); + EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0); if (maybe_elms_obj == NULL) return CallJsBuiltin(isolate, "ArrayPop", args); if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj; } @@ -529,7 +573,7 @@ BUILTIN(ArrayShift) { Object* receiver = *args.receiver(); Object* elms_obj; { MaybeObject* maybe_elms_obj = - EnsureJSArrayWithWritableFastElements(heap, receiver); + EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0); if (maybe_elms_obj == NULL) return CallJsBuiltin(isolate, "ArrayShift", args); if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj; @@ -539,7 +583,7 @@ BUILTIN(ArrayShift) { } FixedArray* elms = FixedArray::cast(elms_obj); JSArray* array = JSArray::cast(receiver); - ASSERT(array->HasFastElements()); + ASSERT(array->HasFastTypeElements()); int len = Smi::cast(array->length())->value(); if (len == 0) return heap->undefined_value(); @@ -551,9 +595,7 @@ BUILTIN(ArrayShift) { } if (!heap->lo_space()->Contains(elms)) { - // As elms still in the same space they used to be, - // there is no need to update region dirty mark. - array->set_elements(LeftTrimFixedArray(heap, elms, 1), SKIP_WRITE_BARRIER); + array->set_elements(LeftTrimFixedArray(heap, elms, 1)); } else { // Shift the elements. AssertNoAllocation no_gc; @@ -573,7 +615,7 @@ BUILTIN(ArrayUnshift) { Object* receiver = *args.receiver(); Object* elms_obj; { MaybeObject* maybe_elms_obj = - EnsureJSArrayWithWritableFastElements(heap, receiver); + EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0); if (maybe_elms_obj == NULL) return CallJsBuiltin(isolate, "ArrayUnshift", args); if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj; @@ -583,7 +625,7 @@ BUILTIN(ArrayUnshift) { } FixedArray* elms = FixedArray::cast(elms_obj); JSArray* array = JSArray::cast(receiver); - ASSERT(array->HasFastElements()); + ASSERT(array->HasFastTypeElements()); int len = Smi::cast(array->length())->value(); int to_add = args.length() - 1; @@ -592,6 +634,11 @@ BUILTIN(ArrayUnshift) { // we should never hit this case. ASSERT(to_add <= (Smi::kMaxValue - len)); + MaybeObject* maybe_object = + array->EnsureCanContainElements(&args, 1, to_add, + DONT_ALLOW_DOUBLE_ELEMENTS); + if (maybe_object->IsFailure()) return maybe_object; + if (new_length > elms->length()) { // New backing storage is needed. int capacity = new_length + (new_length >> 1) + 16; @@ -600,13 +647,9 @@ BUILTIN(ArrayUnshift) { if (!maybe_obj->ToObject(&obj)) return maybe_obj; } FixedArray* new_elms = FixedArray::cast(obj); - - AssertNoAllocation no_gc; - if (len > 0) { - CopyElements(heap, &no_gc, new_elms, to_add, elms, 0, len); - } + CopyObjectToObjectElements(elms, FAST_ELEMENTS, 0, + new_elms, FAST_ELEMENTS, to_add, len); FillWithHoles(heap, new_elms, new_length, capacity); - elms = new_elms; array->set_elements(elms); } else { @@ -634,7 +677,7 @@ BUILTIN(ArraySlice) { int len = -1; if (receiver->IsJSArray()) { JSArray* array = JSArray::cast(receiver); - if (!array->HasFastElements() || + if (!array->HasFastTypeElements() || !IsJSArrayFastElementMovingAllowed(heap, array)) { return CallJsBuiltin(isolate, "ArraySlice", args); } @@ -650,7 +693,7 @@ BUILTIN(ArraySlice) { bool is_arguments_object_with_fast_elements = receiver->IsJSObject() && JSObject::cast(receiver)->map() == arguments_map - && JSObject::cast(receiver)->HasFastElements(); + && JSObject::cast(receiver)->HasFastTypeElements(); if (!is_arguments_object_with_fast_elements) { return CallJsBuiltin(isolate, "ArraySlice", args); } @@ -703,32 +746,22 @@ BUILTIN(ArraySlice) { int final = (relative_end < 0) ? Max(len + relative_end, 0) : Min(relative_end, len); - // Calculate the length of result array. - int result_len = final - k; - if (result_len <= 0) { - return AllocateEmptyJSArray(heap); - } - - Object* result; - { MaybeObject* maybe_result = AllocateJSArray(heap); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - JSArray* result_array = JSArray::cast(result); + ElementsKind elements_kind = JSObject::cast(receiver)->GetElementsKind(); - { MaybeObject* maybe_result = - heap->AllocateUninitializedFixedArray(result_len); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - FixedArray* result_elms = FixedArray::cast(result); + // Calculate the length of result array. + int result_len = Max(final - k, 0); - AssertNoAllocation no_gc; - CopyElements(heap, &no_gc, result_elms, 0, elms, k, result_len); + MaybeObject* maybe_array = + heap->AllocateJSArrayAndStorage(elements_kind, + result_len, + result_len); + JSArray* result_array; + if (!maybe_array->To(&result_array)) return maybe_array; - // Set elements. - result_array->set_elements(result_elms); + CopyObjectToObjectElements(elms, FAST_ELEMENTS, k, + FixedArray::cast(result_array->elements()), + FAST_ELEMENTS, 0, result_len); - // Set the length. - result_array->set_length(Smi::FromInt(result_len)); return result_array; } @@ -738,7 +771,7 @@ BUILTIN(ArraySplice) { Object* receiver = *args.receiver(); Object* elms_obj; { MaybeObject* maybe_elms_obj = - EnsureJSArrayWithWritableFastElements(heap, receiver); + EnsureJSArrayWithWritableFastElements(heap, receiver, &args, 3); if (maybe_elms_obj == NULL) return CallJsBuiltin(isolate, "ArraySplice", args); if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj; @@ -748,7 +781,7 @@ BUILTIN(ArraySplice) { } FixedArray* elms = FixedArray::cast(elms_obj); JSArray* array = JSArray::cast(receiver); - ASSERT(array->HasFastElements()); + ASSERT(array->HasFastTypeElements()); int len = Smi::cast(array->length())->value(); @@ -789,45 +822,25 @@ BUILTIN(ArraySplice) { } JSArray* result_array = NULL; - if (actual_delete_count == 0) { - Object* result; - { MaybeObject* maybe_result = AllocateEmptyJSArray(heap); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - result_array = JSArray::cast(result); - } else { - // Allocate result array. - Object* result; - { MaybeObject* maybe_result = AllocateJSArray(heap); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - result_array = JSArray::cast(result); - - { MaybeObject* maybe_result = - heap->AllocateUninitializedFixedArray(actual_delete_count); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - FixedArray* result_elms = FixedArray::cast(result); + ElementsKind elements_kind = + JSObject::cast(receiver)->GetElementsKind(); + MaybeObject* maybe_array = + heap->AllocateJSArrayAndStorage(elements_kind, + actual_delete_count, + actual_delete_count); + if (!maybe_array->To(&result_array)) return maybe_array; - AssertNoAllocation no_gc; + { // Fill newly created array. - CopyElements(heap, - &no_gc, - result_elms, 0, - elms, actual_start, - actual_delete_count); - - // Set elements. - result_array->set_elements(result_elms); - - // Set the length. - result_array->set_length(Smi::FromInt(actual_delete_count)); + CopyObjectToObjectElements(elms, FAST_ELEMENTS, actual_start, + FixedArray::cast(result_array->elements()), + FAST_ELEMENTS, 0, actual_delete_count); } int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0; - int new_length = len - actual_delete_count + item_count; + bool elms_changed = false; if (item_count < actual_delete_count) { // Shrink the array. const bool trim_array = !heap->lo_space()->Contains(elms) && @@ -836,13 +849,14 @@ BUILTIN(ArraySplice) { if (trim_array) { const int delta = actual_delete_count - item_count; - if (actual_start > 0) { + { AssertNoAllocation no_gc; MoveElements(heap, &no_gc, elms, delta, elms, 0, actual_start); } elms = LeftTrimFixedArray(heap, elms, delta); - array->set_elements(elms, SKIP_WRITE_BARRIER); + + elms_changed = true; } else { AssertNoAllocation no_gc; MoveElements(heap, &no_gc, @@ -867,22 +881,21 @@ BUILTIN(ArraySplice) { } FixedArray* new_elms = FixedArray::cast(obj); - AssertNoAllocation no_gc; - // Copy the part before actual_start as is. - if (actual_start > 0) { - CopyElements(heap, &no_gc, new_elms, 0, elms, 0, actual_start); - } - const int to_copy = len - actual_delete_count - actual_start; - if (to_copy > 0) { - CopyElements(heap, &no_gc, - new_elms, actual_start + item_count, - elms, actual_start + actual_delete_count, - to_copy); + { + // Copy the part before actual_start as is. + CopyObjectToObjectElements(elms, FAST_ELEMENTS, 0, + new_elms, FAST_ELEMENTS, 0, actual_start); + const int to_copy = len - actual_delete_count - actual_start; + CopyObjectToObjectElements(elms, FAST_ELEMENTS, + actual_start + actual_delete_count, + new_elms, FAST_ELEMENTS, + actual_start + item_count, to_copy); } + FillWithHoles(heap, new_elms, new_length, capacity); elms = new_elms; - array->set_elements(elms); + elms_changed = true; } else { AssertNoAllocation no_gc; MoveElements(heap, &no_gc, @@ -898,6 +911,10 @@ BUILTIN(ArraySplice) { elms->set(k, args[3 + k - actual_start], mode); } + if (elms_changed) { + array->set_elements(elms); + } + // Set the length. array->set_length(Smi::FromInt(new_length)); @@ -918,9 +935,10 @@ BUILTIN(ArrayConcat) { // and calculating total length. int n_arguments = args.length(); int result_len = 0; + ElementsKind elements_kind = FAST_SMI_ONLY_ELEMENTS; for (int i = 0; i < n_arguments; i++) { Object* arg = args[i]; - if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastElements() + if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastTypeElements() || JSArray::cast(arg)->GetPrototype() != array_proto) { return CallJsBuiltin(isolate, "ArrayConcat", args); } @@ -937,43 +955,35 @@ BUILTIN(ArrayConcat) { if (result_len > FixedArray::kMaxLength) { return CallJsBuiltin(isolate, "ArrayConcat", args); } - } - if (result_len == 0) { - return AllocateEmptyJSArray(heap); + if (!JSArray::cast(arg)->HasFastSmiOnlyElements()) { + elements_kind = FAST_ELEMENTS; + } } // Allocate result. - Object* result; - { MaybeObject* maybe_result = AllocateJSArray(heap); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - JSArray* result_array = JSArray::cast(result); - - { MaybeObject* maybe_result = - heap->AllocateUninitializedFixedArray(result_len); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - FixedArray* result_elms = FixedArray::cast(result); + JSArray* result_array; + MaybeObject* maybe_array = + heap->AllocateJSArrayAndStorage(elements_kind, + result_len, + result_len); + if (!maybe_array->To(&result_array)) return maybe_array; + if (result_len == 0) return result_array; // Copy data. - AssertNoAllocation no_gc; int start_pos = 0; + FixedArray* result_elms(FixedArray::cast(result_array->elements())); for (int i = 0; i < n_arguments; i++) { JSArray* array = JSArray::cast(args[i]); int len = Smi::cast(array->length())->value(); - if (len > 0) { - FixedArray* elms = FixedArray::cast(array->elements()); - CopyElements(heap, &no_gc, result_elms, start_pos, elms, 0, len); - start_pos += len; - } + FixedArray* elms = FixedArray::cast(array->elements()); + CopyObjectToObjectElements(elms, FAST_ELEMENTS, 0, + result_elms, FAST_ELEMENTS, + start_pos, len); + start_pos += len; } ASSERT(start_pos == result_len); - // Set the length and elements. - result_array->set_length(Smi::FromInt(result_len)); - result_array->set_elements(result_elms); - return result_array; } @@ -1448,6 +1458,14 @@ static void Generate_KeyedStoreIC_NonStrictArguments(MacroAssembler* masm) { KeyedStoreIC::GenerateNonStrictArguments(masm); } +static void Generate_TransitionElementsSmiToDouble(MacroAssembler* masm) { + KeyedStoreIC::GenerateTransitionElementsSmiToDouble(masm); +} + +static void Generate_TransitionElementsDoubleToObject(MacroAssembler* masm) { + KeyedStoreIC::GenerateTransitionElementsDoubleToObject(masm); +} + #ifdef ENABLE_DEBUGGER_SUPPORT static void Generate_LoadIC_DebugBreak(MacroAssembler* masm) { Debug::GenerateLoadICDebugBreak(masm); @@ -1469,18 +1487,30 @@ static void Generate_KeyedStoreIC_DebugBreak(MacroAssembler* masm) { } -static void Generate_ConstructCall_DebugBreak(MacroAssembler* masm) { - Debug::GenerateConstructCallDebugBreak(masm); +static void Generate_Return_DebugBreak(MacroAssembler* masm) { + Debug::GenerateReturnDebugBreak(masm); } -static void Generate_Return_DebugBreak(MacroAssembler* masm) { - Debug::GenerateReturnDebugBreak(masm); +static void Generate_CallFunctionStub_DebugBreak(MacroAssembler* masm) { + Debug::GenerateCallFunctionStubDebugBreak(masm); +} + + +static void Generate_CallFunctionStub_Recording_DebugBreak( + MacroAssembler* masm) { + Debug::GenerateCallFunctionStubRecordDebugBreak(masm); +} + + +static void Generate_CallConstructStub_DebugBreak(MacroAssembler* masm) { + Debug::GenerateCallConstructStubDebugBreak(masm); } -static void Generate_StubNoRegisters_DebugBreak(MacroAssembler* masm) { - Debug::GenerateStubNoRegistersDebugBreak(masm); +static void Generate_CallConstructStub_Recording_DebugBreak( + MacroAssembler* masm) { + Debug::GenerateCallConstructStubRecordDebugBreak(masm); } @@ -1537,30 +1567,30 @@ struct BuiltinDesc { BuiltinExtraArguments extra_args; }; +#define BUILTIN_FUNCTION_TABLE_INIT { V8_ONCE_INIT, {} } + class BuiltinFunctionTable { public: - BuiltinFunctionTable() { - Builtins::InitBuiltinFunctionTable(); + BuiltinDesc* functions() { + CallOnce(&once_, &Builtins::InitBuiltinFunctionTable); + return functions_; } - static const BuiltinDesc* functions() { return functions_; } - - private: - static BuiltinDesc functions_[Builtins::builtin_count + 1]; + OnceType once_; + BuiltinDesc functions_[Builtins::builtin_count + 1]; friend class Builtins; }; -BuiltinDesc BuiltinFunctionTable::functions_[Builtins::builtin_count + 1]; - -static const BuiltinFunctionTable builtin_function_table_init; +static BuiltinFunctionTable builtin_function_table = + BUILTIN_FUNCTION_TABLE_INIT; // Define array of pointers to generators and C builtin functions. // We do this in a sort of roundabout way so that we can do the initialization // within the lexical scope of Builtins:: and within a context where // Code::Flags names a non-abstract type. void Builtins::InitBuiltinFunctionTable() { - BuiltinDesc* functions = BuiltinFunctionTable::functions_; + BuiltinDesc* functions = builtin_function_table.functions_; functions[builtin_count].generator = NULL; functions[builtin_count].c_code = NULL; functions[builtin_count].s_name = NULL; @@ -1596,7 +1626,7 @@ void Builtins::InitBuiltinFunctionTable() { #undef DEF_FUNCTION_PTR_A } -void Builtins::Setup(bool create_heap_objects) { +void Builtins::SetUp(bool create_heap_objects) { ASSERT(!initialized_); Isolate* isolate = Isolate::Current(); Heap* heap = isolate->heap(); @@ -1604,23 +1634,25 @@ void Builtins::Setup(bool create_heap_objects) { // Create a scope for the handles in the builtins. HandleScope scope(isolate); - const BuiltinDesc* functions = BuiltinFunctionTable::functions(); + const BuiltinDesc* functions = builtin_function_table.functions(); // For now we generate builtin adaptor code into a stack-allocated - // buffer, before copying it into individual code objects. - byte buffer[4*KB]; + // buffer, before copying it into individual code objects. Be careful + // with alignment, some platforms don't like unaligned code. + union { int force_alignment; byte buffer[4*KB]; } u; // Traverse the list of builtins and generate an adaptor in a // separate code object for each one. for (int i = 0; i < builtin_count; i++) { if (create_heap_objects) { - MacroAssembler masm(isolate, buffer, sizeof buffer); + MacroAssembler masm(isolate, u.buffer, sizeof u.buffer); // Generate the code/adaptor. typedef void (*Generator)(MacroAssembler*, int, BuiltinExtraArguments); Generator g = FUNCTION_CAST<Generator>(functions[i].generator); // We pass all arguments to the generator, but it may not use all of // them. This works because the first arguments are on top of the // stack. + ASSERT(!masm.has_frame()); g(&masm, functions[i].name, functions[i].extra_args); // Move the code into the object heap. CodeDesc desc; |
