vendor/v8/src/builtins.cc in mustang-0.0.1 vs vendor/v8/src/builtins.cc in mustang-0.1.0

- old
+ new

@@ -105,11 +105,10 @@ BUILTIN_LIST_C(DEF_ARG_TYPE) #undef DEF_ARG_TYPE } // namespace - // ---------------------------------------------------------------------------- // Support macro for defining builtins in C++. // ---------------------------------------------------------------------------- // // A builtin function is defined by writing: @@ -121,41 +120,42 @@ // In the body of the builtin function the arguments can be accessed // through the BuiltinArguments object args. #ifdef DEBUG -#define BUILTIN(name) \ - MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name( \ - name##ArgumentsType args); \ - MUST_USE_RESULT static MaybeObject* Builtin_##name( \ - name##ArgumentsType args) { \ - args.Verify(); \ - return Builtin_Impl_##name(args); \ - } \ - MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name( \ - name##ArgumentsType args) +#define BUILTIN(name) \ + MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name( \ + name##ArgumentsType args, Isolate* isolate); \ + MUST_USE_RESULT static MaybeObject* Builtin_##name( \ + name##ArgumentsType args, Isolate* isolate) { \ + ASSERT(isolate == Isolate::Current()); \ + args.Verify(); \ + return Builtin_Impl_##name(args, isolate); \ + } \ + MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name( \ + name##ArgumentsType args, Isolate* isolate) #else // For release mode. -#define BUILTIN(name) \ - static MaybeObject* Builtin_##name(name##ArgumentsType args) +#define BUILTIN(name) \ + static MaybeObject* Builtin_##name(name##ArgumentsType args, Isolate* isolate) #endif -static inline bool CalledAsConstructor() { +static inline bool CalledAsConstructor(Isolate* isolate) { #ifdef DEBUG // Calculate the result using a full stack frame iterator and check // that the state of the stack is as we assume it to be in the // code below. StackFrameIterator it; ASSERT(it.frame()->is_exit()); it.Advance(); StackFrame* frame = it.frame(); bool reference_result = frame->is_construct(); #endif - Address fp = Top::c_entry_fp(Top::GetCurrentThread()); + Address fp = Isolate::c_entry_fp(isolate->thread_local_top()); // Because we know fp points to an exit frame we can use the relevant // part of ExitFrame::ComputeCallerState directly. const int kCallerOffset = ExitFrameConstants::kCallerFPOffset; Address caller_fp = Memory::Address_at(fp + kCallerOffset); // This inlines the part of StackFrame::ComputeType that grabs the @@ -170,34 +170,34 @@ return result; } // ---------------------------------------------------------------------------- - BUILTIN(Illegal) { UNREACHABLE(); - return Heap::undefined_value(); // Make compiler happy. + return isolate->heap()->undefined_value(); // Make compiler happy. } BUILTIN(EmptyFunction) { - return Heap::undefined_value(); + return isolate->heap()->undefined_value(); } BUILTIN(ArrayCodeGeneric) { - Counters::array_function_runtime.Increment(); + Heap* heap = isolate->heap(); + isolate->counters()->array_function_runtime()->Increment(); JSArray* array; - if (CalledAsConstructor()) { + if (CalledAsConstructor(isolate)) { array = JSArray::cast(*args.receiver()); } else { // Allocate the JS Array JSFunction* constructor = - Top::context()->global_context()->array_function(); + isolate->context()->global_context()->array_function(); Object* obj; - { MaybeObject* maybe_obj = Heap::AllocateJSObject(constructor); + { MaybeObject* maybe_obj = heap->AllocateJSObject(constructor); if (!maybe_obj->ToObject(&obj)) return maybe_obj; } array = JSArray::cast(obj); } @@ -210,11 +210,11 @@ Object* obj = args[1]; if (obj->IsSmi()) { int len = Smi::cast(obj)->value(); if (len >= 0 && len < JSObject::kInitialMaxFastElementArray) { Object* obj; - { MaybeObject* maybe_obj = Heap::AllocateFixedArrayWithHoles(len); + { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(len); if (!maybe_obj->ToObject(&obj)) return maybe_obj; } array->SetContent(FixedArray::cast(obj)); return array; } @@ -233,11 +233,11 @@ // 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()); + { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(len->value()); if (!maybe_obj->ToObject(&obj)) return maybe_obj; } AssertNoAllocation no_gc; FixedArray* elms = FixedArray::cast(obj); @@ -253,92 +253,96 @@ return array; } -MUST_USE_RESULT static MaybeObject* AllocateJSArray() { +MUST_USE_RESULT static MaybeObject* AllocateJSArray(Heap* heap) { JSFunction* array_function = - Top::context()->global_context()->array_function(); + heap->isolate()->context()->global_context()->array_function(); Object* result; - { MaybeObject* maybe_result = Heap::AllocateJSObject(array_function); + { MaybeObject* maybe_result = heap->AllocateJSObject(array_function); if (!maybe_result->ToObject(&result)) return maybe_result; } return result; } -MUST_USE_RESULT static MaybeObject* AllocateEmptyJSArray() { +MUST_USE_RESULT static MaybeObject* AllocateEmptyJSArray(Heap* heap) { Object* result; - { MaybeObject* maybe_result = AllocateJSArray(); + { 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()); + result_array->set_elements(heap->empty_fixed_array()); return result_array; } -static void CopyElements(AssertNoAllocation* no_gc, +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(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); + heap->RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len); } } -static void MoveElements(AssertNoAllocation* no_gc, +static void MoveElements(Heap* heap, + AssertNoAllocation* no_gc, FixedArray* dst, int dst_index, FixedArray* src, int src_index, int len) { - ASSERT(dst->map() != Heap::fixed_cow_array_map()); + ASSERT(dst->map() != HEAP->fixed_cow_array_map()); memmove(dst->data_start() + dst_index, src->data_start() + src_index, len * kPointerSize); WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc); if (mode == UPDATE_WRITE_BARRIER) { - Heap::RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len); + heap->RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len); } } -static void FillWithHoles(FixedArray* dst, int from, int to) { - ASSERT(dst->map() != Heap::fixed_cow_array_map()); - MemsetPointer(dst->data_start() + from, Heap::the_hole_value(), to - from); +static void FillWithHoles(Heap* heap, FixedArray* dst, int from, int to) { + ASSERT(dst->map() != heap->fixed_cow_array_map()); + MemsetPointer(dst->data_start() + from, heap->the_hole_value(), to - from); } -static FixedArray* LeftTrimFixedArray(FixedArray* elms, int to_trim) { - ASSERT(elms->map() != Heap::fixed_cow_array_map()); +static FixedArray* LeftTrimFixedArray(Heap* heap, + FixedArray* elms, + int to_trim) { + ASSERT(elms->map() != HEAP->fixed_cow_array_map()); // For now this trick is only applied to fixed arrays in new and paged space. // In large object space the object's start must coincide with chunk // and thus the trick is just not applicable. - ASSERT(!Heap::lo_space()->Contains(elms)); + ASSERT(!HEAP->lo_space()->Contains(elms)); STATIC_ASSERT(FixedArray::kMapOffset == 0); STATIC_ASSERT(FixedArray::kLengthOffset == kPointerSize); STATIC_ASSERT(FixedArray::kHeaderSize == 2 * kPointerSize); Object** former_start = HeapObject::RawField(elms, 0); const int len = elms->length(); if (to_trim > FixedArray::kHeaderSize / kPointerSize && - !Heap::new_space()->Contains(elms)) { + !heap->new_space()->Contains(elms)) { // If we are doing a big trim in old space then we zap the space that was // formerly part of the array so that the GC (aided by the card-based // remembered set) won't find pointers to new-space there. Object** zap = reinterpret_cast<Object**>(elms->address()); zap++; // Header of filler must be at least one word so skip that. @@ -347,70 +351,74 @@ } } // Technically in new space this write might be omitted (except for // debug mode which iterates through the heap), but to play safer // we still do it. - Heap::CreateFillerObjectAt(elms->address(), to_trim * kPointerSize); + heap->CreateFillerObjectAt(elms->address(), to_trim * kPointerSize); - former_start[to_trim] = Heap::fixed_array_map(); + former_start[to_trim] = heap->fixed_array_map(); former_start[to_trim + 1] = Smi::FromInt(len - to_trim); return FixedArray::cast(HeapObject::FromAddress( elms->address() + to_trim * kPointerSize)); } -static bool ArrayPrototypeHasNoElements(Context* global_context, +static bool ArrayPrototypeHasNoElements(Heap* heap, + Context* global_context, JSObject* array_proto) { // This method depends on non writability of Object and Array prototype // fields. - if (array_proto->elements() != Heap::empty_fixed_array()) return false; + 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()); + ASSERT(array_proto->elements() == heap->empty_fixed_array()); // Object.prototype Object* proto = array_proto->GetPrototype(); - if (proto == Heap::null_value()) return false; + if (proto == heap->null_value()) return false; array_proto = JSObject::cast(proto); if (array_proto != global_context->initial_object_prototype()) return false; - if (array_proto->elements() != Heap::empty_fixed_array()) return false; + if (array_proto->elements() != heap->empty_fixed_array()) return false; ASSERT(array_proto->GetPrototype()->IsNull()); return true; } MUST_USE_RESULT static inline MaybeObject* EnsureJSArrayWithWritableFastElements( - Object* receiver) { + Heap* heap, Object* receiver) { 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()) { + if (elms->map() == heap->fixed_array_map()) return elms; + if (elms->map() == heap->fixed_cow_array_map()) { return array->EnsureWritableFastElements(); } return NULL; } -static inline bool IsJSArrayFastElementMovingAllowed(JSArray* receiver) { - Context* global_context = Top::context()->global_context(); +static inline bool IsJSArrayFastElementMovingAllowed(Heap* heap, + JSArray* receiver) { + Context* global_context = heap->isolate()->context()->global_context(); JSObject* array_proto = JSObject::cast(global_context->array_function()->prototype()); return receiver->GetPrototype() == array_proto && - ArrayPrototypeHasNoElements(global_context, array_proto); + ArrayPrototypeHasNoElements(heap, global_context, array_proto); } MUST_USE_RESULT static MaybeObject* CallJsBuiltin( + Isolate* isolate, const char* name, BuiltinArguments<NO_EXTRA_ARGUMENTS> args) { - HandleScope handleScope; + HandleScope handleScope(isolate); Handle<Object> js_builtin = - GetProperty(Handle<JSObject>(Top::global_context()->builtins()), - name); + 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++) { @@ -426,15 +434,18 @@ return *result; } BUILTIN(ArrayPush) { + Heap* heap = isolate->heap(); Object* receiver = *args.receiver(); Object* elms_obj; { MaybeObject* maybe_elms_obj = - EnsureJSArrayWithWritableFastElements(receiver); - if (maybe_elms_obj == NULL) return CallJsBuiltin("ArrayPush", args); + EnsureJSArrayWithWritableFastElements(heap, receiver); + if (maybe_elms_obj == NULL) { + return CallJsBuiltin(isolate, "ArrayPush", args); + } if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj; } FixedArray* elms = FixedArray::cast(elms_obj); JSArray* array = JSArray::cast(receiver); @@ -451,20 +462,20 @@ if (new_length > elms->length()) { // New backing storage is needed. int capacity = new_length + (new_length >> 1) + 16; Object* obj; - { MaybeObject* maybe_obj = Heap::AllocateUninitializedFixedArray(capacity); + { MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity); if (!maybe_obj->ToObject(&obj)) return maybe_obj; } FixedArray* new_elms = FixedArray::cast(obj); AssertNoAllocation no_gc; if (len > 0) { - CopyElements(&no_gc, new_elms, 0, elms, 0, len); + CopyElements(heap, &no_gc, new_elms, 0, elms, 0, len); } - FillWithHoles(new_elms, new_length, capacity); + FillWithHoles(heap, new_elms, new_length, capacity); elms = new_elms; array->set_elements(elms); } @@ -480,22 +491,23 @@ return Smi::FromInt(new_length); } BUILTIN(ArrayPop) { + Heap* heap = isolate->heap(); Object* receiver = *args.receiver(); Object* elms_obj; { MaybeObject* maybe_elms_obj = - EnsureJSArrayWithWritableFastElements(receiver); - if (maybe_elms_obj == NULL) return CallJsBuiltin("ArrayPop", args); + EnsureJSArrayWithWritableFastElements(heap, receiver); + if (maybe_elms_obj == NULL) return CallJsBuiltin(isolate, "ArrayPop", args); if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj; } FixedArray* elms = FixedArray::cast(elms_obj); JSArray* array = JSArray::cast(receiver); int len = Smi::cast(array->length())->value(); - if (len == 0) return Heap::undefined_value(); + if (len == 0) return heap->undefined_value(); // Get top element MaybeObject* top = elms->get(len - 1); // Set the length. @@ -512,61 +524,65 @@ return top; } BUILTIN(ArrayShift) { + Heap* heap = isolate->heap(); Object* receiver = *args.receiver(); Object* elms_obj; { MaybeObject* maybe_elms_obj = - EnsureJSArrayWithWritableFastElements(receiver); - if (maybe_elms_obj == NULL) return CallJsBuiltin("ArrayShift", args); + EnsureJSArrayWithWritableFastElements(heap, receiver); + if (maybe_elms_obj == NULL) + return CallJsBuiltin(isolate, "ArrayShift", args); if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj; } - if (!IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) { - return CallJsBuiltin("ArrayShift", args); + if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) { + return CallJsBuiltin(isolate, "ArrayShift", args); } FixedArray* elms = FixedArray::cast(elms_obj); JSArray* array = JSArray::cast(receiver); ASSERT(array->HasFastElements()); int len = Smi::cast(array->length())->value(); - if (len == 0) return Heap::undefined_value(); + if (len == 0) return heap->undefined_value(); // Get first element Object* first = elms->get(0); if (first->IsTheHole()) { - first = Heap::undefined_value(); + first = heap->undefined_value(); } - if (!Heap::lo_space()->Contains(elms)) { + 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(elms, 1), SKIP_WRITE_BARRIER); + array->set_elements(LeftTrimFixedArray(heap, elms, 1), SKIP_WRITE_BARRIER); } else { // Shift the elements. AssertNoAllocation no_gc; - MoveElements(&no_gc, elms, 0, elms, 1, len - 1); - elms->set(len - 1, Heap::the_hole_value()); + MoveElements(heap, &no_gc, elms, 0, elms, 1, len - 1); + elms->set(len - 1, heap->the_hole_value()); } // Set the length. array->set_length(Smi::FromInt(len - 1)); return first; } BUILTIN(ArrayUnshift) { + Heap* heap = isolate->heap(); Object* receiver = *args.receiver(); Object* elms_obj; { MaybeObject* maybe_elms_obj = - EnsureJSArrayWithWritableFastElements(receiver); - if (maybe_elms_obj == NULL) return CallJsBuiltin("ArrayUnshift", args); + EnsureJSArrayWithWritableFastElements(heap, receiver); + if (maybe_elms_obj == NULL) + return CallJsBuiltin(isolate, "ArrayUnshift", args); if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj; } - if (!IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) { - return CallJsBuiltin("ArrayUnshift", args); + if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) { + return CallJsBuiltin(isolate, "ArrayUnshift", args); } FixedArray* elms = FixedArray::cast(elms_obj); JSArray* array = JSArray::cast(receiver); ASSERT(array->HasFastElements()); @@ -579,26 +595,26 @@ if (new_length > elms->length()) { // New backing storage is needed. int capacity = new_length + (new_length >> 1) + 16; Object* obj; - { MaybeObject* maybe_obj = Heap::AllocateUninitializedFixedArray(capacity); + { MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity); if (!maybe_obj->ToObject(&obj)) return maybe_obj; } FixedArray* new_elms = FixedArray::cast(obj); AssertNoAllocation no_gc; if (len > 0) { - CopyElements(&no_gc, new_elms, to_add, elms, 0, len); + CopyElements(heap, &no_gc, new_elms, to_add, elms, 0, len); } - FillWithHoles(new_elms, new_length, capacity); + FillWithHoles(heap, new_elms, new_length, capacity); elms = new_elms; array->set_elements(elms); } else { AssertNoAllocation no_gc; - MoveElements(&no_gc, elms, to_add, elms, 0, len); + MoveElements(heap, &no_gc, elms, to_add, elms, 0, len); } // Add the provided values. AssertNoAllocation no_gc; WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); @@ -611,48 +627,49 @@ return Smi::FromInt(new_length); } BUILTIN(ArraySlice) { + Heap* heap = isolate->heap(); Object* receiver = *args.receiver(); FixedArray* elms; int len = -1; if (receiver->IsJSArray()) { JSArray* array = JSArray::cast(receiver); if (!array->HasFastElements() || - !IsJSArrayFastElementMovingAllowed(array)) { - return CallJsBuiltin("ArraySlice", args); + !IsJSArrayFastElementMovingAllowed(heap, array)) { + return CallJsBuiltin(isolate, "ArraySlice", args); } elms = FixedArray::cast(array->elements()); len = Smi::cast(array->length())->value(); } else { // Array.slice(arguments, ...) is quite a common idiom (notably more // than 50% of invocations in Web apps). Treat it in C++ as well. Map* arguments_map = - Top::context()->global_context()->arguments_boilerplate()->map(); + isolate->context()->global_context()->arguments_boilerplate()->map(); bool is_arguments_object_with_fast_elements = receiver->IsJSObject() && JSObject::cast(receiver)->map() == arguments_map && JSObject::cast(receiver)->HasFastElements(); if (!is_arguments_object_with_fast_elements) { - return CallJsBuiltin("ArraySlice", args); + return CallJsBuiltin(isolate, "ArraySlice", args); } elms = FixedArray::cast(JSObject::cast(receiver)->elements()); Object* len_obj = JSObject::cast(receiver) - ->InObjectPropertyAt(Heap::arguments_length_index); + ->InObjectPropertyAt(Heap::kArgumentsLengthIndex); if (!len_obj->IsSmi()) { - return CallJsBuiltin("ArraySlice", args); + return CallJsBuiltin(isolate, "ArraySlice", args); } len = Smi::cast(len_obj)->value(); if (len > elms->length()) { - return CallJsBuiltin("ArraySlice", args); + return CallJsBuiltin(isolate, "ArraySlice", args); } for (int i = 0; i < len; i++) { - if (elms->get(i) == Heap::the_hole_value()) { - return CallJsBuiltin("ArraySlice", args); + if (elms->get(i) == heap->the_hole_value()) { + return CallJsBuiltin(isolate, "ArraySlice", args); } } } ASSERT(len >= 0); int n_arguments = args.length() - 1; @@ -665,18 +682,18 @@ if (n_arguments > 0) { Object* arg1 = args[1]; if (arg1->IsSmi()) { relative_start = Smi::cast(arg1)->value(); } else if (!arg1->IsUndefined()) { - return CallJsBuiltin("ArraySlice", args); + return CallJsBuiltin(isolate, "ArraySlice", args); } if (n_arguments > 1) { Object* arg2 = args[2]; if (arg2->IsSmi()) { relative_end = Smi::cast(arg2)->value(); } else if (!arg2->IsUndefined()) { - return CallJsBuiltin("ArraySlice", args); + return CallJsBuiltin(isolate, "ArraySlice", args); } } } // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6. @@ -688,27 +705,27 @@ : Min(relative_end, len); // Calculate the length of result array. int result_len = final - k; if (result_len <= 0) { - return AllocateEmptyJSArray(); + return AllocateEmptyJSArray(heap); } Object* result; - { MaybeObject* maybe_result = AllocateJSArray(); + { 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); + heap->AllocateUninitializedFixedArray(result_len); if (!maybe_result->ToObject(&result)) return maybe_result; } FixedArray* result_elms = FixedArray::cast(result); AssertNoAllocation no_gc; - CopyElements(&no_gc, result_elms, 0, elms, k, result_len); + CopyElements(heap, &no_gc, result_elms, 0, elms, k, result_len); // Set elements. result_array->set_elements(result_elms); // Set the length. @@ -716,19 +733,21 @@ return result_array; } BUILTIN(ArraySplice) { + Heap* heap = isolate->heap(); Object* receiver = *args.receiver(); Object* elms_obj; { MaybeObject* maybe_elms_obj = - EnsureJSArrayWithWritableFastElements(receiver); - if (maybe_elms_obj == NULL) return CallJsBuiltin("ArraySplice", args); + EnsureJSArrayWithWritableFastElements(heap, receiver); + if (maybe_elms_obj == NULL) + return CallJsBuiltin(isolate, "ArraySplice", args); if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj; } - if (!IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) { - return CallJsBuiltin("ArraySplice", args); + if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) { + return CallJsBuiltin(isolate, "ArraySplice", args); } FixedArray* elms = FixedArray::cast(elms_obj); JSArray* array = JSArray::cast(receiver); ASSERT(array->HasFastElements()); @@ -740,11 +759,11 @@ if (n_arguments > 0) { Object* arg1 = args[1]; if (arg1->IsSmi()) { relative_start = Smi::cast(arg1)->value(); } else if (!arg1->IsUndefined()) { - return CallJsBuiltin("ArraySplice", args); + return CallJsBuiltin(isolate, "ArraySplice", args); } } int actual_start = (relative_start < 0) ? Max(len + relative_start, 0) : Min(relative_start, len); @@ -762,40 +781,41 @@ if (n_arguments > 1) { Object* arg2 = args[2]; if (arg2->IsSmi()) { value = Smi::cast(arg2)->value(); } else { - return CallJsBuiltin("ArraySplice", args); + return CallJsBuiltin(isolate, "ArraySplice", args); } } actual_delete_count = Min(Max(value, 0), len - actual_start); } JSArray* result_array = NULL; if (actual_delete_count == 0) { Object* result; - { MaybeObject* maybe_result = AllocateEmptyJSArray(); + { 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(); + { 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); + heap->AllocateUninitializedFixedArray(actual_delete_count); if (!maybe_result->ToObject(&result)) return maybe_result; } FixedArray* result_elms = FixedArray::cast(result); AssertNoAllocation no_gc; // Fill newly created array. - CopyElements(&no_gc, + CopyElements(heap, + &no_gc, result_elms, 0, elms, actual_start, actual_delete_count); // Set elements. @@ -809,30 +829,30 @@ int new_length = len - actual_delete_count + item_count; if (item_count < actual_delete_count) { // Shrink the array. - const bool trim_array = !Heap::lo_space()->Contains(elms) && + const bool trim_array = !heap->lo_space()->Contains(elms) && ((actual_start + item_count) < (len - actual_delete_count - actual_start)); if (trim_array) { const int delta = actual_delete_count - item_count; if (actual_start > 0) { Object** start = elms->data_start(); memmove(start + delta, start, actual_start * kPointerSize); } - elms = LeftTrimFixedArray(elms, delta); + elms = LeftTrimFixedArray(heap, elms, delta); array->set_elements(elms, SKIP_WRITE_BARRIER); } else { AssertNoAllocation no_gc; - MoveElements(&no_gc, + MoveElements(heap, &no_gc, elms, actual_start + item_count, elms, actual_start + actual_delete_count, (len - actual_delete_count - actual_start)); - FillWithHoles(elms, new_length, len); + FillWithHoles(heap, elms, new_length, len); } } else if (item_count > actual_delete_count) { // Currently fixed arrays cannot grow too big, so // we should never hit this case. ASSERT((item_count - actual_delete_count) <= (Smi::kMaxValue - len)); @@ -841,34 +861,34 @@ if (new_length > elms->length()) { // New backing storage is needed. int capacity = new_length + (new_length >> 1) + 16; Object* obj; { MaybeObject* maybe_obj = - Heap::AllocateUninitializedFixedArray(capacity); + heap->AllocateUninitializedFixedArray(capacity); if (!maybe_obj->ToObject(&obj)) return maybe_obj; } FixedArray* new_elms = FixedArray::cast(obj); AssertNoAllocation no_gc; // Copy the part before actual_start as is. if (actual_start > 0) { - CopyElements(&no_gc, new_elms, 0, elms, 0, actual_start); + 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(&no_gc, + CopyElements(heap, &no_gc, new_elms, actual_start + item_count, elms, actual_start + actual_delete_count, to_copy); } - FillWithHoles(new_elms, new_length, capacity); + FillWithHoles(heap, new_elms, new_length, capacity); elms = new_elms; array->set_elements(elms); } else { AssertNoAllocation no_gc; - MoveElements(&no_gc, + MoveElements(heap, &no_gc, elms, actual_start + item_count, elms, actual_start + actual_delete_count, (len - actual_delete_count - actual_start)); } } @@ -885,26 +905,27 @@ return result_array; } BUILTIN(ArrayConcat) { - Context* global_context = Top::context()->global_context(); + Heap* heap = isolate->heap(); + Context* global_context = isolate->context()->global_context(); JSObject* array_proto = JSObject::cast(global_context->array_function()->prototype()); - if (!ArrayPrototypeHasNoElements(global_context, array_proto)) { - return CallJsBuiltin("ArrayConcat", args); + if (!ArrayPrototypeHasNoElements(heap, global_context, array_proto)) { + return CallJsBuiltin(isolate, "ArrayConcat", args); } // Iterate through all the arguments performing checks // and calculating total length. int n_arguments = args.length(); int result_len = 0; for (int i = 0; i < n_arguments; i++) { Object* arg = args[i]; if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastElements() || JSArray::cast(arg)->GetPrototype() != array_proto) { - return CallJsBuiltin("ArrayConcat", args); + return CallJsBuiltin(isolate, "ArrayConcat", args); } int len = Smi::cast(JSArray::cast(arg)->length())->value(); // We shouldn't overflow when adding another len. @@ -913,27 +934,27 @@ USE(kHalfOfMaxInt); result_len += len; ASSERT(result_len >= 0); if (result_len > FixedArray::kMaxLength) { - return CallJsBuiltin("ArrayConcat", args); + return CallJsBuiltin(isolate, "ArrayConcat", args); } } if (result_len == 0) { - return AllocateEmptyJSArray(); + return AllocateEmptyJSArray(heap); } // Allocate result. Object* result; - { MaybeObject* maybe_result = AllocateJSArray(); + { 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); + heap->AllocateUninitializedFixedArray(result_len); if (!maybe_result->ToObject(&result)) return maybe_result; } FixedArray* result_elms = FixedArray::cast(result); // Copy data. @@ -942,11 +963,11 @@ 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(&no_gc, result_elms, start_pos, elms, 0, len); + CopyElements(heap, &no_gc, result_elms, start_pos, elms, 0, len); start_pos += len; } } ASSERT(start_pos == result_len); @@ -957,20 +978,53 @@ return result_array; } // ----------------------------------------------------------------------------- +// Strict mode poison pills + + +BUILTIN(StrictArgumentsCallee) { + HandleScope scope; + return isolate->Throw(*isolate->factory()->NewTypeError( + "strict_arguments_callee", HandleVector<Object>(NULL, 0))); +} + + +BUILTIN(StrictArgumentsCaller) { + HandleScope scope; + return isolate->Throw(*isolate->factory()->NewTypeError( + "strict_arguments_caller", HandleVector<Object>(NULL, 0))); +} + + +BUILTIN(StrictFunctionCaller) { + HandleScope scope; + return isolate->Throw(*isolate->factory()->NewTypeError( + "strict_function_caller", HandleVector<Object>(NULL, 0))); +} + + +BUILTIN(StrictFunctionArguments) { + HandleScope scope; + return isolate->Throw(*isolate->factory()->NewTypeError( + "strict_function_arguments", HandleVector<Object>(NULL, 0))); +} + + +// ----------------------------------------------------------------------------- // // Returns the holder JSObject if the function can legally be called // with this receiver. Returns Heap::null_value() if the call is // illegal. Any arguments that don't fit the expected type is // overwritten with undefined. Arguments that do fit the expected // type is overwritten with the object in the prototype chain that // actually has that type. -static inline Object* TypeCheck(int argc, +static inline Object* TypeCheck(Heap* heap, + int argc, Object** argv, FunctionTemplateInfo* info) { Object* recv = argv[0]; Object* sig_obj = info->signature(); if (sig_obj->IsUndefined()) return recv; @@ -978,16 +1032,16 @@ // If necessary, check the receiver Object* recv_type = sig->receiver(); Object* holder = recv; if (!recv_type->IsUndefined()) { - for (; holder != Heap::null_value(); holder = holder->GetPrototype()) { + for (; holder != heap->null_value(); holder = holder->GetPrototype()) { if (holder->IsInstanceOf(FunctionTemplateInfo::cast(recv_type))) { break; } } - if (holder == Heap::null_value()) return holder; + if (holder == heap->null_value()) return holder; } Object* args_obj = sig->args(); // If there is no argument signature we're done if (args_obj->IsUndefined()) return holder; FixedArray* args = FixedArray::cast(args_obj); @@ -996,49 +1050,51 @@ for (int i = 0; i < length; i++) { Object* argtype = args->get(i); if (argtype->IsUndefined()) continue; Object** arg = &argv[-1 - i]; Object* current = *arg; - for (; current != Heap::null_value(); current = current->GetPrototype()) { + for (; current != heap->null_value(); current = current->GetPrototype()) { if (current->IsInstanceOf(FunctionTemplateInfo::cast(argtype))) { *arg = current; break; } } - if (current == Heap::null_value()) *arg = Heap::undefined_value(); + if (current == heap->null_value()) *arg = heap->undefined_value(); } return holder; } template <bool is_construct> MUST_USE_RESULT static MaybeObject* HandleApiCallHelper( - BuiltinArguments<NEEDS_CALLED_FUNCTION> args) { - ASSERT(is_construct == CalledAsConstructor()); + BuiltinArguments<NEEDS_CALLED_FUNCTION> args, Isolate* isolate) { + ASSERT(is_construct == CalledAsConstructor(isolate)); + Heap* heap = isolate->heap(); - HandleScope scope; + HandleScope scope(isolate); Handle<JSFunction> function = args.called_function(); ASSERT(function->shared()->IsApiFunction()); FunctionTemplateInfo* fun_data = function->shared()->get_api_func_data(); if (is_construct) { - Handle<FunctionTemplateInfo> desc(fun_data); + Handle<FunctionTemplateInfo> desc(fun_data, isolate); bool pending_exception = false; - Factory::ConfigureInstance(desc, Handle<JSObject>::cast(args.receiver()), - &pending_exception); - ASSERT(Top::has_pending_exception() == pending_exception); + isolate->factory()->ConfigureInstance( + desc, Handle<JSObject>::cast(args.receiver()), &pending_exception); + ASSERT(isolate->has_pending_exception() == pending_exception); if (pending_exception) return Failure::Exception(); fun_data = *desc; } - Object* raw_holder = TypeCheck(args.length(), &args[0], fun_data); + Object* raw_holder = TypeCheck(heap, args.length(), &args[0], fun_data); if (raw_holder->IsNull()) { // This function cannot be called with the given receiver. Abort! Handle<Object> obj = - Factory::NewTypeError("illegal_invocation", HandleVector(&function, 1)); - return Top::Throw(*obj); + isolate->factory()->NewTypeError( + "illegal_invocation", HandleVector(&function, 1)); + return isolate->Throw(*obj); } Object* raw_call_data = fun_data->call_code(); if (!raw_call_data->IsUndefined()) { CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data); @@ -1046,14 +1102,14 @@ v8::InvocationCallback callback = v8::ToCData<v8::InvocationCallback>(callback_obj); Object* data_obj = call_data->data(); Object* result; - LOG(ApiObjectAccess("call", JSObject::cast(*args.receiver()))); + LOG(isolate, ApiObjectAccess("call", JSObject::cast(*args.receiver()))); ASSERT(raw_holder->IsJSObject()); - CustomArguments custom; + CustomArguments custom(isolate); v8::ImplementationUtilities::PrepareArgumentsData(custom.end(), data_obj, *function, raw_holder); v8::Arguments new_args = v8::ImplementationUtilities::NewArguments( custom.end(), @@ -1062,35 +1118,36 @@ is_construct); v8::Handle<v8::Value> value; { // Leaving JavaScript. - VMState state(EXTERNAL); - ExternalCallbackScope call_scope(v8::ToCData<Address>(callback_obj)); + VMState state(isolate, EXTERNAL); + ExternalCallbackScope call_scope(isolate, + v8::ToCData<Address>(callback_obj)); value = callback(new_args); } if (value.IsEmpty()) { - result = Heap::undefined_value(); + result = heap->undefined_value(); } else { result = *reinterpret_cast<Object**>(*value); } - RETURN_IF_SCHEDULED_EXCEPTION(); + RETURN_IF_SCHEDULED_EXCEPTION(isolate); if (!is_construct || result->IsJSObject()) return result; } return *args.receiver(); } BUILTIN(HandleApiCall) { - return HandleApiCallHelper<false>(args); + return HandleApiCallHelper<false>(args, isolate); } BUILTIN(HandleApiCallConstruct) { - return HandleApiCallHelper<true>(args); + return HandleApiCallHelper<true>(args, isolate); } #ifdef DEBUG @@ -1108,11 +1165,12 @@ #endif BUILTIN(FastHandleApiCall) { - ASSERT(!CalledAsConstructor()); + ASSERT(!CalledAsConstructor(isolate)); + Heap* heap = isolate->heap(); const bool is_construct = false; // We expect four more arguments: callback, function, call data, and holder. const int args_length = args.length() - 4; ASSERT(args_length >= 0); @@ -1127,42 +1185,45 @@ #ifdef DEBUG VerifyTypeCheck(Utils::OpenHandle(*new_args.Holder()), Utils::OpenHandle(*new_args.Callee())); #endif - HandleScope scope; + HandleScope scope(isolate); Object* result; v8::Handle<v8::Value> value; { // Leaving JavaScript. - VMState state(EXTERNAL); - ExternalCallbackScope call_scope(v8::ToCData<Address>(callback_obj)); + VMState state(isolate, EXTERNAL); + ExternalCallbackScope call_scope(isolate, + v8::ToCData<Address>(callback_obj)); v8::InvocationCallback callback = v8::ToCData<v8::InvocationCallback>(callback_obj); value = callback(new_args); } if (value.IsEmpty()) { - result = Heap::undefined_value(); + result = heap->undefined_value(); } else { result = *reinterpret_cast<Object**>(*value); } - RETURN_IF_SCHEDULED_EXCEPTION(); + RETURN_IF_SCHEDULED_EXCEPTION(isolate); return result; } // Helper function to handle calls to non-function objects created through the // API. The object can be called as either a constructor (using new) or just as // a function (without new). MUST_USE_RESULT static MaybeObject* HandleApiCallAsFunctionOrConstructor( + Isolate* isolate, bool is_construct_call, BuiltinArguments<NO_EXTRA_ARGUMENTS> args) { // Non-functions are never called as constructors. Even if this is an object // called as a constructor the delegate call is not a construct call. - ASSERT(!CalledAsConstructor()); + ASSERT(!CalledAsConstructor(isolate)); + Heap* heap = isolate->heap(); Handle<Object> receiver = args.at<Object>(0); // Get the object called. JSObject* obj = JSObject::cast(*args.receiver()); @@ -1181,52 +1242,52 @@ v8::ToCData<v8::InvocationCallback>(callback_obj); // Get the data for the call and perform the callback. Object* result; { - HandleScope scope; + HandleScope scope(isolate); + LOG(isolate, ApiObjectAccess("call non-function", obj)); - LOG(ApiObjectAccess("call non-function", obj)); - - CustomArguments custom; + CustomArguments custom(isolate); v8::ImplementationUtilities::PrepareArgumentsData(custom.end(), call_data->data(), constructor, obj); v8::Arguments new_args = v8::ImplementationUtilities::NewArguments( custom.end(), &args[0] - 1, args.length() - 1, is_construct_call); v8::Handle<v8::Value> value; { // Leaving JavaScript. - VMState state(EXTERNAL); - ExternalCallbackScope call_scope(v8::ToCData<Address>(callback_obj)); + VMState state(isolate, EXTERNAL); + ExternalCallbackScope call_scope(isolate, + v8::ToCData<Address>(callback_obj)); value = callback(new_args); } if (value.IsEmpty()) { - result = Heap::undefined_value(); + result = heap->undefined_value(); } else { result = *reinterpret_cast<Object**>(*value); } } // Check for exceptions and return result. - RETURN_IF_SCHEDULED_EXCEPTION(); + RETURN_IF_SCHEDULED_EXCEPTION(isolate); return result; } // Handle calls to non-function objects created through the API. This delegate // function is used when the call is a normal function call. BUILTIN(HandleApiCallAsFunction) { - return HandleApiCallAsFunctionOrConstructor(false, args); + return HandleApiCallAsFunctionOrConstructor(isolate, false, args); } // Handle calls to non-function objects created through the API. This delegate // function is used when the call is a construct call. BUILTIN(HandleApiCallAsConstructor) { - return HandleApiCallAsFunctionOrConstructor(true, args); + return HandleApiCallAsFunctionOrConstructor(isolate, true, args); } static void Generate_LoadIC_ArrayLength(MacroAssembler* masm) { LoadIC::GenerateArrayLength(masm); @@ -1326,16 +1387,16 @@ StoreIC::GenerateNormal(masm); } static void Generate_StoreIC_Megamorphic(MacroAssembler* masm) { - StoreIC::GenerateMegamorphic(masm, StoreIC::kStoreICNonStrict); + StoreIC::GenerateMegamorphic(masm, kNonStrictMode); } static void Generate_StoreIC_Megamorphic_Strict(MacroAssembler* masm) { - StoreIC::GenerateMegamorphic(masm, StoreIC::kStoreICStrict); + StoreIC::GenerateMegamorphic(masm, kStrictMode); } static void Generate_StoreIC_ArrayLength(MacroAssembler* masm) { StoreIC::GenerateArrayLength(masm); @@ -1346,34 +1407,44 @@ StoreIC::GenerateArrayLength(masm); } static void Generate_StoreIC_GlobalProxy(MacroAssembler* masm) { - StoreIC::GenerateGlobalProxy(masm); + StoreIC::GenerateGlobalProxy(masm, kNonStrictMode); } static void Generate_StoreIC_GlobalProxy_Strict(MacroAssembler* masm) { - StoreIC::GenerateGlobalProxy(masm); + StoreIC::GenerateGlobalProxy(masm, kStrictMode); } static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) { - KeyedStoreIC::GenerateGeneric(masm); + KeyedStoreIC::GenerateGeneric(masm, kNonStrictMode); } +static void Generate_KeyedStoreIC_Generic_Strict(MacroAssembler* masm) { + KeyedStoreIC::GenerateGeneric(masm, kStrictMode); +} + + static void Generate_KeyedStoreIC_Miss(MacroAssembler* masm) { KeyedStoreIC::GenerateMiss(masm); } static void Generate_KeyedStoreIC_Initialize(MacroAssembler* masm) { KeyedStoreIC::GenerateInitialize(masm); } +static void Generate_KeyedStoreIC_Initialize_Strict(MacroAssembler* masm) { + KeyedStoreIC::GenerateInitialize(masm); +} + + #ifdef ENABLE_DEBUGGER_SUPPORT static void Generate_LoadIC_DebugBreak(MacroAssembler* masm) { Debug::GenerateLoadICDebugBreak(masm); } @@ -1421,87 +1492,127 @@ static void Generate_FrameDropper_LiveEdit(MacroAssembler* masm) { Debug::GenerateFrameDropperLiveEdit(masm); } #endif -Object* Builtins::builtins_[builtin_count] = { NULL, }; -const char* Builtins::names_[builtin_count] = { NULL, }; +Builtins::Builtins() : initialized_(false) { + memset(builtins_, 0, sizeof(builtins_[0]) * builtin_count); + memset(names_, 0, sizeof(names_[0]) * builtin_count); +} + + +Builtins::~Builtins() { +} + + #define DEF_ENUM_C(name, ignore) FUNCTION_ADDR(Builtin_##name), - Address Builtins::c_functions_[cfunction_count] = { - BUILTIN_LIST_C(DEF_ENUM_C) - }; +Address const Builtins::c_functions_[cfunction_count] = { + BUILTIN_LIST_C(DEF_ENUM_C) +}; #undef DEF_ENUM_C #define DEF_JS_NAME(name, ignore) #name, #define DEF_JS_ARGC(ignore, argc) argc, -const char* Builtins::javascript_names_[id_count] = { +const char* const Builtins::javascript_names_[id_count] = { BUILTINS_LIST_JS(DEF_JS_NAME) }; -int Builtins::javascript_argc_[id_count] = { +int const Builtins::javascript_argc_[id_count] = { BUILTINS_LIST_JS(DEF_JS_ARGC) }; #undef DEF_JS_NAME #undef DEF_JS_ARGC -static bool is_initialized = false; -void Builtins::Setup(bool create_heap_objects) { - ASSERT(!is_initialized); +struct BuiltinDesc { + byte* generator; + byte* c_code; + const char* s_name; // name is only used for generating log information. + int name; + Code::Flags flags; + BuiltinExtraArguments extra_args; +}; - // Create a scope for the handles in the builtins. - HandleScope scope; +class BuiltinFunctionTable { + public: + BuiltinFunctionTable() { + Builtins::InitBuiltinFunctionTable(); + } - struct BuiltinDesc { - byte* generator; - byte* c_code; - const char* s_name; // name is only used for generating log information. - int name; - Code::Flags flags; - BuiltinExtraArguments extra_args; - }; + static const BuiltinDesc* functions() { return functions_; } -#define DEF_FUNCTION_PTR_C(name, extra_args) \ - { FUNCTION_ADDR(Generate_Adaptor), \ - FUNCTION_ADDR(Builtin_##name), \ - #name, \ - c_##name, \ - Code::ComputeFlags(Code::BUILTIN), \ - extra_args \ - }, + private: + static BuiltinDesc functions_[Builtins::builtin_count + 1]; -#define DEF_FUNCTION_PTR_A(name, kind, state, extra) \ - { FUNCTION_ADDR(Generate_##name), \ - NULL, \ - #name, \ - name, \ - Code::ComputeFlags(Code::kind, NOT_IN_LOOP, state, extra), \ - NO_EXTRA_ARGUMENTS \ - }, + friend class Builtins; +}; - // Define array of pointers to generators and C builtin functions. - static BuiltinDesc functions[] = { - BUILTIN_LIST_C(DEF_FUNCTION_PTR_C) - BUILTIN_LIST_A(DEF_FUNCTION_PTR_A) - BUILTIN_LIST_DEBUG_A(DEF_FUNCTION_PTR_A) - // Terminator: - { NULL, NULL, NULL, builtin_count, static_cast<Code::Flags>(0), - NO_EXTRA_ARGUMENTS } - }; +BuiltinDesc BuiltinFunctionTable::functions_[Builtins::builtin_count + 1]; +static const BuiltinFunctionTable 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_; + functions[builtin_count].generator = NULL; + functions[builtin_count].c_code = NULL; + functions[builtin_count].s_name = NULL; + functions[builtin_count].name = builtin_count; + functions[builtin_count].flags = static_cast<Code::Flags>(0); + functions[builtin_count].extra_args = NO_EXTRA_ARGUMENTS; + +#define DEF_FUNCTION_PTR_C(aname, aextra_args) \ + functions->generator = FUNCTION_ADDR(Generate_Adaptor); \ + functions->c_code = FUNCTION_ADDR(Builtin_##aname); \ + functions->s_name = #aname; \ + functions->name = c_##aname; \ + functions->flags = Code::ComputeFlags(Code::BUILTIN); \ + functions->extra_args = aextra_args; \ + ++functions; + +#define DEF_FUNCTION_PTR_A(aname, kind, state, extra) \ + functions->generator = FUNCTION_ADDR(Generate_##aname); \ + functions->c_code = NULL; \ + functions->s_name = #aname; \ + functions->name = k##aname; \ + functions->flags = Code::ComputeFlags(Code::kind, \ + NOT_IN_LOOP, \ + state, \ + extra); \ + functions->extra_args = NO_EXTRA_ARGUMENTS; \ + ++functions; + + BUILTIN_LIST_C(DEF_FUNCTION_PTR_C) + BUILTIN_LIST_A(DEF_FUNCTION_PTR_A) + BUILTIN_LIST_DEBUG_A(DEF_FUNCTION_PTR_A) + #undef DEF_FUNCTION_PTR_C #undef DEF_FUNCTION_PTR_A +} +void Builtins::Setup(bool create_heap_objects) { + ASSERT(!initialized_); + Isolate* isolate = Isolate::Current(); + Heap* heap = isolate->heap(); + + // Create a scope for the handles in the builtins. + HandleScope scope(isolate); + + const BuiltinDesc* functions = BuiltinFunctionTable::functions(); + // For now we generate builtin adaptor code into a stack-allocated // buffer, before copying it into individual code objects. byte buffer[4*KB]; // 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(buffer, sizeof buffer); + MacroAssembler masm(isolate, buffer, sizeof 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 @@ -1515,18 +1626,19 @@ { // During startup it's OK to always allocate and defer GC to later. // This simplifies things because we don't need to retry. AlwaysAllocateScope __scope__; { MaybeObject* maybe_code = - Heap::CreateCode(desc, flags, masm.CodeObject()); + heap->CreateCode(desc, flags, masm.CodeObject()); if (!maybe_code->ToObject(&code)) { v8::internal::V8::FatalProcessOutOfMemory("CreateCode"); } } } // Log the event and add the code to the builtins array. - PROFILE(CodeCreateEvent(Logger::BUILTIN_TAG, + PROFILE(isolate, + CodeCreateEvent(Logger::BUILTIN_TAG, Code::cast(code), functions[i].s_name)); GDBJIT(AddCode(GDBJITInterface::BUILTIN, functions[i].s_name, Code::cast(code))); @@ -1544,33 +1656,53 @@ } names_[i] = functions[i].s_name; } // Mark as initialized. - is_initialized = true; + initialized_ = true; } void Builtins::TearDown() { - is_initialized = false; + initialized_ = false; } void Builtins::IterateBuiltins(ObjectVisitor* v) { v->VisitPointers(&builtins_[0], &builtins_[0] + builtin_count); } const char* Builtins::Lookup(byte* pc) { - if (is_initialized) { // may be called during initialization (disassembler!) + // may be called during initialization (disassembler!) + if (initialized_) { for (int i = 0; i < builtin_count; i++) { Code* entry = Code::cast(builtins_[i]); if (entry->contains(pc)) { return names_[i]; } } } return NULL; } + + +#define DEFINE_BUILTIN_ACCESSOR_C(name, ignore) \ +Handle<Code> Builtins::name() { \ + Code** code_address = \ + reinterpret_cast<Code**>(builtin_address(k##name)); \ + return Handle<Code>(code_address); \ +} +#define DEFINE_BUILTIN_ACCESSOR_A(name, kind, state, extra) \ +Handle<Code> Builtins::name() { \ + Code** code_address = \ + reinterpret_cast<Code**>(builtin_address(k##name)); \ + return Handle<Code>(code_address); \ +} +BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C) +BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A) +BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) +#undef DEFINE_BUILTIN_ACCESSOR_C +#undef DEFINE_BUILTIN_ACCESSOR_A } } // namespace v8::internal