| Index: src/builtins.cc
|
| ===================================================================
|
| --- src/builtins.cc (revision 7267)
|
| +++ src/builtins.cc (working copy)
|
| @@ -107,7 +107,6 @@
|
|
|
| } // namespace
|
|
|
| -
|
| // ----------------------------------------------------------------------------
|
| // Support macro for defining builtins in C++.
|
| // ----------------------------------------------------------------------------
|
| @@ -123,26 +122,27 @@
|
|
|
| #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
|
| @@ -153,7 +153,7 @@
|
| 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;
|
| @@ -172,30 +172,30 @@
|
|
|
| // ----------------------------------------------------------------------------
|
|
|
| -
|
| 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);
|
| @@ -212,7 +212,7 @@
|
| 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));
|
| @@ -235,7 +235,7 @@
|
| 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;
|
| }
|
|
|
| @@ -255,77 +255,81 @@
|
| }
|
|
|
|
|
| -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);
|
| @@ -336,7 +340,7 @@
|
| 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.
|
| @@ -349,9 +353,9 @@
|
| // 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(
|
| @@ -359,20 +363,21 @@
|
| }
|
|
|
|
|
| -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;
|
| }
|
| @@ -380,35 +385,38 @@
|
|
|
| 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);
|
| @@ -428,11 +436,14 @@
|
|
|
|
|
| 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);
|
| @@ -453,16 +464,16 @@
|
| // 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);
|
| @@ -482,18 +493,19 @@
|
|
|
|
|
| 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);
|
| @@ -514,38 +526,40 @@
|
|
|
|
|
| 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.
|
| @@ -556,15 +570,17 @@
|
|
|
|
|
| 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);
|
| @@ -581,22 +597,22 @@
|
| // 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.
|
| @@ -613,14 +629,15 @@
|
|
|
|
|
| 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());
|
| @@ -629,28 +646,28 @@
|
| // 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::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);
|
| }
|
| }
|
| }
|
| @@ -667,14 +684,14 @@
|
| 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);
|
| }
|
| }
|
| }
|
| @@ -690,23 +707,23 @@
|
| // 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);
|
| @@ -718,15 +735,17 @@
|
|
|
|
|
| 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);
|
| @@ -742,7 +761,7 @@
|
| 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)
|
| @@ -764,7 +783,7 @@
|
| 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);
|
| @@ -773,27 +792,28 @@
|
| 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);
|
| @@ -811,7 +831,7 @@
|
|
|
| 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) {
|
| @@ -822,15 +842,15 @@
|
| 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
|
| @@ -843,7 +863,7 @@
|
| 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);
|
| @@ -851,22 +871,22 @@
|
| 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));
|
| @@ -887,11 +907,12 @@
|
|
|
|
|
| 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
|
| @@ -902,7 +923,7 @@
|
| 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();
|
| @@ -915,23 +936,23 @@
|
| 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);
|
| @@ -944,7 +965,7 @@
|
| 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;
|
| }
|
| }
|
| @@ -964,29 +985,29 @@
|
|
|
| BUILTIN(StrictArgumentsCallee) {
|
| HandleScope scope;
|
| - return Top::Throw(*Factory::NewTypeError("strict_arguments_callee",
|
| - HandleVector<Object>(NULL, 0)));
|
| + return isolate->Throw(*isolate->factory()->NewTypeError(
|
| + "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
|
| }
|
|
|
|
|
| BUILTIN(StrictArgumentsCaller) {
|
| HandleScope scope;
|
| - return Top::Throw(*Factory::NewTypeError("strict_arguments_caller",
|
| - HandleVector<Object>(NULL, 0)));
|
| + return isolate->Throw(*isolate->factory()->NewTypeError(
|
| + "strict_arguments_caller", HandleVector<Object>(NULL, 0)));
|
| }
|
|
|
|
|
| BUILTIN(StrictFunctionCaller) {
|
| HandleScope scope;
|
| - return Top::Throw(*Factory::NewTypeError("strict_function_caller",
|
| - HandleVector<Object>(NULL, 0)));
|
| + return isolate->Throw(*isolate->factory()->NewTypeError(
|
| + "strict_function_caller", HandleVector<Object>(NULL, 0)));
|
| }
|
|
|
|
|
| BUILTIN(StrictFunctionArguments) {
|
| HandleScope scope;
|
| - return Top::Throw(*Factory::NewTypeError("strict_function_arguments",
|
| - HandleVector<Object>(NULL, 0)));
|
| + return isolate->Throw(*isolate->factory()->NewTypeError(
|
| + "strict_function_arguments", HandleVector<Object>(NULL, 0)));
|
| }
|
|
|
|
|
| @@ -1000,7 +1021,8 @@
|
| // 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];
|
| @@ -1012,12 +1034,12 @@
|
|
|
| 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
|
| @@ -1030,13 +1052,13 @@
|
| 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;
|
| }
|
| @@ -1044,31 +1066,33 @@
|
|
|
| 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();
|
| @@ -1080,10 +1104,10 @@
|
| 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);
|
|
|
| @@ -1096,17 +1120,18 @@
|
| 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;
|
| }
|
|
|
| @@ -1115,12 +1140,12 @@
|
|
|
|
|
| BUILTIN(HandleApiCall) {
|
| - return HandleApiCallHelper<false>(args);
|
| + return HandleApiCallHelper<false>(args, isolate);
|
| }
|
|
|
|
|
| BUILTIN(HandleApiCallConstruct) {
|
| - return HandleApiCallHelper<true>(args);
|
| + return HandleApiCallHelper<true>(args, isolate);
|
| }
|
|
|
|
|
| @@ -1142,7 +1167,8 @@
|
|
|
|
|
| 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.
|
| @@ -1161,25 +1187,26 @@
|
| 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;
|
| }
|
|
|
| @@ -1188,11 +1215,13 @@
|
| // 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);
|
|
|
| @@ -1215,11 +1244,10 @@
|
| // 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(
|
| @@ -1230,18 +1258,19 @@
|
| 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;
|
| }
|
|
|
| @@ -1249,14 +1278,14 @@
|
| // 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);
|
| }
|
|
|
|
|
| @@ -1465,74 +1494,113 @@
|
| }
|
| #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 = 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_);
|
| + Heap* heap = Isolate::Current()->heap();
|
| +
|
| + // Create a scope for the handles in the builtins.
|
| + HandleScope scope;
|
| +
|
| + 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];
|
| @@ -1559,14 +1627,15 @@
|
| // 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,
|
| @@ -1588,12 +1657,12 @@
|
| }
|
|
|
| // Mark as initialized.
|
| - is_initialized = true;
|
| + initialized_ = true;
|
| }
|
|
|
|
|
| void Builtins::TearDown() {
|
| - is_initialized = false;
|
| + initialized_ = false;
|
| }
|
|
|
|
|
| @@ -1603,7 +1672,8 @@
|
|
|
|
|
| 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)) {
|
|
|