1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include "arguments.h"
32 #include "bootstrapper.h"
36 #include "heap-profiler.h"
37 #include "mark-compact.h"
38 #include "vm-state-inl.h"
45 // Arguments object passed to C++ builtins.
46 template <BuiltinExtraArguments extra_args>
47 class BuiltinArguments : public Arguments {
49 BuiltinArguments(int length, Object** arguments)
50 : Arguments(length, arguments) { }
52 Object*& operator[] (int index) {
53 ASSERT(index < length());
54 return Arguments::operator[](index);
57 template <class S> Handle<S> at(int index) {
58 ASSERT(index < length());
59 return Arguments::at<S>(index);
62 Handle<Object> receiver() {
63 return Arguments::at<Object>(0);
66 Handle<JSFunction> called_function() {
67 STATIC_ASSERT(extra_args == NEEDS_CALLED_FUNCTION);
68 return Arguments::at<JSFunction>(Arguments::length() - 1);
71 // Gets the total number of arguments including the receiver (but
72 // excluding extra arguments).
74 STATIC_ASSERT(extra_args == NO_EXTRA_ARGUMENTS);
75 return Arguments::length();
80 // Check we have at least the receiver.
81 ASSERT(Arguments::length() >= 1);
87 // Specialize BuiltinArguments for the called function extra argument.
90 int BuiltinArguments<NEEDS_CALLED_FUNCTION>::length() const {
91 return Arguments::length() - 1;
96 void BuiltinArguments<NEEDS_CALLED_FUNCTION>::Verify() {
97 // Check we have at least the receiver and the called function.
98 ASSERT(Arguments::length() >= 2);
99 // Make sure cast to JSFunction succeeds.
105 #define DEF_ARG_TYPE(name, spec) \
106 typedef BuiltinArguments<spec> name##ArgumentsType;
107 BUILTIN_LIST_C(DEF_ARG_TYPE)
112 // ----------------------------------------------------------------------------
113 // Support macro for defining builtins in C++.
114 // ----------------------------------------------------------------------------
116 // A builtin function is defined by writing:
122 // In the body of the builtin function the arguments can be accessed
123 // through the BuiltinArguments object args.
127 #define BUILTIN(name) \
128 MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name( \
129 name##ArgumentsType args, Isolate* isolate); \
130 MUST_USE_RESULT static MaybeObject* Builtin_##name( \
131 name##ArgumentsType args, Isolate* isolate) { \
132 ASSERT(isolate == Isolate::Current()); \
134 return Builtin_Impl_##name(args, isolate); \
136 MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name( \
137 name##ArgumentsType args, Isolate* isolate)
139 #else // For release mode.
141 #define BUILTIN(name) \
142 static MaybeObject* Builtin_##name(name##ArgumentsType args, Isolate* isolate)
147 static inline bool CalledAsConstructor(Isolate* isolate) {
149 // Calculate the result using a full stack frame iterator and check
150 // that the state of the stack is as we assume it to be in the
152 StackFrameIterator it;
153 ASSERT(it.frame()->is_exit());
155 StackFrame* frame = it.frame();
156 bool reference_result = frame->is_construct();
158 Address fp = Isolate::c_entry_fp(isolate->thread_local_top());
159 // Because we know fp points to an exit frame we can use the relevant
160 // part of ExitFrame::ComputeCallerState directly.
161 const int kCallerOffset = ExitFrameConstants::kCallerFPOffset;
162 Address caller_fp = Memory::Address_at(fp + kCallerOffset);
163 // This inlines the part of StackFrame::ComputeType that grabs the
164 // type of the current frame. Note that StackFrame::ComputeType
165 // has been specialized for each architecture so if any one of them
166 // changes this code has to be changed as well.
167 const int kMarkerOffset = StandardFrameConstants::kMarkerOffset;
168 const Smi* kConstructMarker = Smi::FromInt(StackFrame::CONSTRUCT);
169 Object* marker = Memory::Object_at(caller_fp + kMarkerOffset);
170 bool result = (marker == kConstructMarker);
171 ASSERT_EQ(result, reference_result);
175 // ----------------------------------------------------------------------------
179 return isolate->heap()->undefined_value(); // Make compiler happy.
183 BUILTIN(EmptyFunction) {
184 return isolate->heap()->undefined_value();
188 static MaybeObject* ArrayCodeGenericCommon(Arguments* args,
190 JSFunction* constructor) {
191 Heap* heap = isolate->heap();
192 isolate->counters()->array_function_runtime()->Increment();
195 if (CalledAsConstructor(isolate)) {
196 array = JSArray::cast((*args)[0]);
197 // Initialize elements and length in case later allocations fail so that the
198 // array object is initialized in a valid state.
199 array->set_length(Smi::FromInt(0));
200 array->set_elements(heap->empty_fixed_array());
201 if (!FLAG_smi_only_arrays) {
202 Context* global_context = isolate->context()->global_context();
203 if (array->GetElementsKind() == FAST_SMI_ONLY_ELEMENTS &&
204 !global_context->object_js_array_map()->IsUndefined()) {
205 array->set_map(Map::cast(global_context->object_js_array_map()));
209 // Allocate the JS Array
210 MaybeObject* maybe_obj = heap->AllocateJSObject(constructor);
211 if (!maybe_obj->To(&array)) return maybe_obj;
214 // Optimize the case where there is one argument and the argument is a
216 if (args->length() == 2) {
217 Object* obj = (*args)[1];
219 int len = Smi::cast(obj)->value();
220 if (len >= 0 && len < JSObject::kInitialMaxFastElementArray) {
222 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(len);
223 if (!maybe_obj->ToObject(&fixed_array)) return maybe_obj;
225 // We do not use SetContent to skip the unnecessary elements type check.
226 array->set_elements(FixedArray::cast(fixed_array));
227 array->set_length(Smi::cast(obj));
231 // Take the argument as the length.
232 { MaybeObject* maybe_obj = array->Initialize(0);
233 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
235 return array->SetElementsLength((*args)[1]);
238 // Optimize the case where there are no parameters passed.
239 if (args->length() == 1) {
240 return array->Initialize(JSArray::kPreallocatedArrayElements);
243 // Set length and elements on the array.
244 int number_of_elements = args->length() - 1;
245 MaybeObject* maybe_object =
246 array->EnsureCanContainElements(args, 1, number_of_elements,
247 ALLOW_CONVERTED_DOUBLE_ELEMENTS);
248 if (maybe_object->IsFailure()) return maybe_object;
250 // Allocate an appropriately typed elements array.
251 MaybeObject* maybe_elms;
252 ElementsKind elements_kind = array->GetElementsKind();
253 if (elements_kind == FAST_DOUBLE_ELEMENTS) {
254 maybe_elms = heap->AllocateUninitializedFixedDoubleArray(
257 maybe_elms = heap->AllocateFixedArrayWithHoles(number_of_elements);
259 FixedArrayBase* elms;
260 if (!maybe_elms->To<FixedArrayBase>(&elms)) return maybe_elms;
262 // Fill in the content
263 switch (array->GetElementsKind()) {
264 case FAST_SMI_ONLY_ELEMENTS: {
265 FixedArray* smi_elms = FixedArray::cast(elms);
266 for (int index = 0; index < number_of_elements; index++) {
267 smi_elms->set(index, (*args)[index+1], SKIP_WRITE_BARRIER);
271 case FAST_ELEMENTS: {
272 AssertNoAllocation no_gc;
273 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
274 FixedArray* object_elms = FixedArray::cast(elms);
275 for (int index = 0; index < number_of_elements; index++) {
276 object_elms->set(index, (*args)[index+1], mode);
280 case FAST_DOUBLE_ELEMENTS: {
281 FixedDoubleArray* double_elms = FixedDoubleArray::cast(elms);
282 for (int index = 0; index < number_of_elements; index++) {
283 double_elms->set(index, (*args)[index+1]->Number());
292 array->set_elements(elms);
293 array->set_length(Smi::FromInt(number_of_elements));
298 BUILTIN(InternalArrayCodeGeneric) {
299 return ArrayCodeGenericCommon(
302 isolate->context()->global_context()->internal_array_function());
306 BUILTIN(ArrayCodeGeneric) {
307 return ArrayCodeGenericCommon(
310 isolate->context()->global_context()->array_function());
314 static void MoveElements(Heap* heap,
315 AssertNoAllocation* no_gc,
321 if (len == 0) return;
322 ASSERT(dst->map() != HEAP->fixed_cow_array_map());
323 memmove(dst->data_start() + dst_index,
324 src->data_start() + src_index,
326 WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc);
327 if (mode == UPDATE_WRITE_BARRIER) {
328 heap->RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
330 heap->incremental_marking()->RecordWrites(dst);
334 static void FillWithHoles(Heap* heap, FixedArray* dst, int from, int to) {
335 ASSERT(dst->map() != heap->fixed_cow_array_map());
336 MemsetPointer(dst->data_start() + from, heap->the_hole_value(), to - from);
340 static FixedArray* LeftTrimFixedArray(Heap* heap,
343 ASSERT(elms->map() != HEAP->fixed_cow_array_map());
344 // For now this trick is only applied to fixed arrays in new and paged space.
345 // In large object space the object's start must coincide with chunk
346 // and thus the trick is just not applicable.
347 ASSERT(!HEAP->lo_space()->Contains(elms));
349 STATIC_ASSERT(FixedArray::kMapOffset == 0);
350 STATIC_ASSERT(FixedArray::kLengthOffset == kPointerSize);
351 STATIC_ASSERT(FixedArray::kHeaderSize == 2 * kPointerSize);
353 Object** former_start = HeapObject::RawField(elms, 0);
355 const int len = elms->length();
357 if (to_trim > FixedArray::kHeaderSize / kPointerSize &&
358 !heap->new_space()->Contains(elms)) {
359 // If we are doing a big trim in old space then we zap the space that was
360 // formerly part of the array so that the GC (aided by the card-based
361 // remembered set) won't find pointers to new-space there.
362 Object** zap = reinterpret_cast<Object**>(elms->address());
363 zap++; // Header of filler must be at least one word so skip that.
364 for (int i = 1; i < to_trim; i++) {
365 *zap++ = Smi::FromInt(0);
368 // Technically in new space this write might be omitted (except for
369 // debug mode which iterates through the heap), but to play safer
371 heap->CreateFillerObjectAt(elms->address(), to_trim * kPointerSize);
373 former_start[to_trim] = heap->fixed_array_map();
374 former_start[to_trim + 1] = Smi::FromInt(len - to_trim);
376 // Maintain marking consistency for HeapObjectIterator and
377 // IncrementalMarking.
378 int size_delta = to_trim * kPointerSize;
379 if (heap->marking()->TransferMark(elms->address(),
380 elms->address() + size_delta)) {
381 MemoryChunk::IncrementLiveBytesFromMutator(elms->address(), -size_delta);
384 HEAP_PROFILE(heap, ObjectMoveEvent(elms->address(),
385 elms->address() + size_delta));
386 return FixedArray::cast(HeapObject::FromAddress(
387 elms->address() + to_trim * kPointerSize));
391 static bool ArrayPrototypeHasNoElements(Heap* heap,
392 Context* global_context,
393 JSObject* array_proto) {
394 // This method depends on non writability of Object and Array prototype
396 if (array_proto->elements() != heap->empty_fixed_array()) return false;
398 Object* proto = array_proto->GetPrototype();
399 if (proto == heap->null_value()) return false;
400 array_proto = JSObject::cast(proto);
401 if (array_proto != global_context->initial_object_prototype()) return false;
402 if (array_proto->elements() != heap->empty_fixed_array()) return false;
403 return array_proto->GetPrototype()->IsNull();
408 static inline MaybeObject* EnsureJSArrayWithWritableFastElements(
409 Heap* heap, Object* receiver, Arguments* args, int first_added_arg) {
410 if (!receiver->IsJSArray()) return NULL;
411 JSArray* array = JSArray::cast(receiver);
412 HeapObject* elms = array->elements();
413 Map* map = elms->map();
414 if (map == heap->fixed_array_map()) {
415 if (args == NULL || array->HasFastElements()) return elms;
416 if (array->HasFastDoubleElements()) {
417 ASSERT(elms == heap->empty_fixed_array());
418 MaybeObject* maybe_transition =
419 array->TransitionElementsKind(FAST_ELEMENTS);
420 if (maybe_transition->IsFailure()) return maybe_transition;
423 } else if (map == heap->fixed_cow_array_map()) {
424 MaybeObject* maybe_writable_result = array->EnsureWritableFastElements();
425 if (args == NULL || array->HasFastElements() ||
426 maybe_writable_result->IsFailure()) {
427 return maybe_writable_result;
433 // Need to ensure that the arguments passed in args can be contained in
435 int args_length = args->length();
436 if (first_added_arg >= args_length) return array->elements();
438 MaybeObject* maybe_array = array->EnsureCanContainElements(
441 args_length - first_added_arg,
442 DONT_ALLOW_DOUBLE_ELEMENTS);
443 if (maybe_array->IsFailure()) return maybe_array;
444 return array->elements();
448 static inline bool IsJSArrayFastElementMovingAllowed(Heap* heap,
450 if (!FLAG_clever_optimizations) return false;
451 Context* global_context = heap->isolate()->context()->global_context();
452 JSObject* array_proto =
453 JSObject::cast(global_context->array_function()->prototype());
454 return receiver->GetPrototype() == array_proto &&
455 ArrayPrototypeHasNoElements(heap, global_context, array_proto);
459 MUST_USE_RESULT static MaybeObject* CallJsBuiltin(
462 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
463 HandleScope handleScope(isolate);
465 Handle<Object> js_builtin =
466 GetProperty(Handle<JSObject>(isolate->global_context()->builtins()),
468 Handle<JSFunction> function = Handle<JSFunction>::cast(js_builtin);
469 int argc = args.length() - 1;
470 ScopedVector<Handle<Object> > argv(argc);
471 for (int i = 0; i < argc; ++i) {
472 argv[i] = args.at<Object>(i + 1);
474 bool pending_exception;
475 Handle<Object> result = Execution::Call(function,
480 if (pending_exception) return Failure::Exception();
486 Heap* heap = isolate->heap();
487 Object* receiver = *args.receiver();
489 { MaybeObject* maybe_elms_obj =
490 EnsureJSArrayWithWritableFastElements(heap, receiver, &args, 1);
491 if (maybe_elms_obj == NULL) {
492 return CallJsBuiltin(isolate, "ArrayPush", args);
494 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
496 FixedArray* elms = FixedArray::cast(elms_obj);
497 JSArray* array = JSArray::cast(receiver);
499 int len = Smi::cast(array->length())->value();
500 int to_add = args.length() - 1;
502 return Smi::FromInt(len);
504 // Currently fixed arrays cannot grow too big, so
505 // we should never hit this case.
506 ASSERT(to_add <= (Smi::kMaxValue - len));
508 int new_length = len + to_add;
510 if (new_length > elms->length()) {
511 // New backing storage is needed.
512 int capacity = new_length + (new_length >> 1) + 16;
514 { MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity);
515 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
517 FixedArray* new_elms = FixedArray::cast(obj);
519 CopyObjectToObjectElements(elms, FAST_ELEMENTS, 0,
520 new_elms, FAST_ELEMENTS, 0, len);
521 FillWithHoles(heap, new_elms, new_length, capacity);
526 // Add the provided values.
527 AssertNoAllocation no_gc;
528 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
529 for (int index = 0; index < to_add; index++) {
530 elms->set(index + len, args[index + 1], mode);
533 if (elms != array->elements()) {
534 array->set_elements(elms);
538 array->set_length(Smi::FromInt(new_length));
539 return Smi::FromInt(new_length);
544 Heap* heap = isolate->heap();
545 Object* receiver = *args.receiver();
547 { MaybeObject* maybe_elms_obj =
548 EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
549 if (maybe_elms_obj == NULL) return CallJsBuiltin(isolate, "ArrayPop", args);
550 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
552 FixedArray* elms = FixedArray::cast(elms_obj);
553 JSArray* array = JSArray::cast(receiver);
555 int len = Smi::cast(array->length())->value();
556 if (len == 0) return heap->undefined_value();
559 MaybeObject* top = elms->get(len - 1);
562 array->set_length(Smi::FromInt(len - 1));
564 if (!top->IsTheHole()) {
565 // Delete the top element.
566 elms->set_the_hole(len - 1);
570 top = array->GetPrototype()->GetElement(len - 1);
576 BUILTIN(ArrayShift) {
577 Heap* heap = isolate->heap();
578 Object* receiver = *args.receiver();
580 { MaybeObject* maybe_elms_obj =
581 EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
582 if (maybe_elms_obj == NULL)
583 return CallJsBuiltin(isolate, "ArrayShift", args);
584 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
586 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
587 return CallJsBuiltin(isolate, "ArrayShift", args);
589 FixedArray* elms = FixedArray::cast(elms_obj);
590 JSArray* array = JSArray::cast(receiver);
591 ASSERT(array->HasFastTypeElements());
593 int len = Smi::cast(array->length())->value();
594 if (len == 0) return heap->undefined_value();
597 Object* first = elms->get(0);
598 if (first->IsTheHole()) {
599 first = heap->undefined_value();
602 if (!heap->lo_space()->Contains(elms)) {
603 array->set_elements(LeftTrimFixedArray(heap, elms, 1));
605 // Shift the elements.
606 AssertNoAllocation no_gc;
607 MoveElements(heap, &no_gc, elms, 0, elms, 1, len - 1);
608 elms->set(len - 1, heap->the_hole_value());
612 array->set_length(Smi::FromInt(len - 1));
618 BUILTIN(ArrayUnshift) {
619 Heap* heap = isolate->heap();
620 Object* receiver = *args.receiver();
622 { MaybeObject* maybe_elms_obj =
623 EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
624 if (maybe_elms_obj == NULL)
625 return CallJsBuiltin(isolate, "ArrayUnshift", args);
626 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
628 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
629 return CallJsBuiltin(isolate, "ArrayUnshift", args);
631 FixedArray* elms = FixedArray::cast(elms_obj);
632 JSArray* array = JSArray::cast(receiver);
633 ASSERT(array->HasFastTypeElements());
635 int len = Smi::cast(array->length())->value();
636 int to_add = args.length() - 1;
637 int new_length = len + to_add;
638 // Currently fixed arrays cannot grow too big, so
639 // we should never hit this case.
640 ASSERT(to_add <= (Smi::kMaxValue - len));
642 MaybeObject* maybe_object =
643 array->EnsureCanContainElements(&args, 1, to_add,
644 DONT_ALLOW_DOUBLE_ELEMENTS);
645 if (maybe_object->IsFailure()) return maybe_object;
647 if (new_length > elms->length()) {
648 // New backing storage is needed.
649 int capacity = new_length + (new_length >> 1) + 16;
651 { MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity);
652 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
654 FixedArray* new_elms = FixedArray::cast(obj);
655 CopyObjectToObjectElements(elms, FAST_ELEMENTS, 0,
656 new_elms, FAST_ELEMENTS, to_add, len);
657 FillWithHoles(heap, new_elms, new_length, capacity);
659 array->set_elements(elms);
661 AssertNoAllocation no_gc;
662 MoveElements(heap, &no_gc, elms, to_add, elms, 0, len);
665 // Add the provided values.
666 AssertNoAllocation no_gc;
667 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
668 for (int i = 0; i < to_add; i++) {
669 elms->set(i, args[i + 1], mode);
673 array->set_length(Smi::FromInt(new_length));
674 return Smi::FromInt(new_length);
678 BUILTIN(ArraySlice) {
679 Heap* heap = isolate->heap();
680 Object* receiver = *args.receiver();
683 if (receiver->IsJSArray()) {
684 JSArray* array = JSArray::cast(receiver);
685 if (!array->HasFastTypeElements() ||
686 !IsJSArrayFastElementMovingAllowed(heap, array)) {
687 return CallJsBuiltin(isolate, "ArraySlice", args);
690 elms = FixedArray::cast(array->elements());
691 len = Smi::cast(array->length())->value();
693 // Array.slice(arguments, ...) is quite a common idiom (notably more
694 // than 50% of invocations in Web apps). Treat it in C++ as well.
696 isolate->context()->global_context()->arguments_boilerplate()->map();
698 bool is_arguments_object_with_fast_elements =
699 receiver->IsJSObject()
700 && JSObject::cast(receiver)->map() == arguments_map
701 && JSObject::cast(receiver)->HasFastTypeElements();
702 if (!is_arguments_object_with_fast_elements) {
703 return CallJsBuiltin(isolate, "ArraySlice", args);
705 elms = FixedArray::cast(JSObject::cast(receiver)->elements());
706 Object* len_obj = JSObject::cast(receiver)
707 ->InObjectPropertyAt(Heap::kArgumentsLengthIndex);
708 if (!len_obj->IsSmi()) {
709 return CallJsBuiltin(isolate, "ArraySlice", args);
711 len = Smi::cast(len_obj)->value();
712 if (len > elms->length()) {
713 return CallJsBuiltin(isolate, "ArraySlice", args);
715 for (int i = 0; i < len; i++) {
716 if (elms->get(i) == heap->the_hole_value()) {
717 return CallJsBuiltin(isolate, "ArraySlice", args);
722 int n_arguments = args.length() - 1;
724 // Note carefully choosen defaults---if argument is missing,
725 // it's undefined which gets converted to 0 for relative_start
726 // and to len for relative_end.
727 int relative_start = 0;
728 int relative_end = len;
729 if (n_arguments > 0) {
730 Object* arg1 = args[1];
732 relative_start = Smi::cast(arg1)->value();
733 } else if (!arg1->IsUndefined()) {
734 return CallJsBuiltin(isolate, "ArraySlice", args);
736 if (n_arguments > 1) {
737 Object* arg2 = args[2];
739 relative_end = Smi::cast(arg2)->value();
740 } else if (!arg2->IsUndefined()) {
741 return CallJsBuiltin(isolate, "ArraySlice", args);
746 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6.
747 int k = (relative_start < 0) ? Max(len + relative_start, 0)
748 : Min(relative_start, len);
750 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8.
751 int final = (relative_end < 0) ? Max(len + relative_end, 0)
752 : Min(relative_end, len);
754 ElementsKind elements_kind = JSObject::cast(receiver)->GetElementsKind();
756 // Calculate the length of result array.
757 int result_len = Max(final - k, 0);
759 MaybeObject* maybe_array =
760 heap->AllocateJSArrayAndStorage(elements_kind,
763 JSArray* result_array;
764 if (!maybe_array->To(&result_array)) return maybe_array;
766 CopyObjectToObjectElements(elms, FAST_ELEMENTS, k,
767 FixedArray::cast(result_array->elements()),
768 FAST_ELEMENTS, 0, result_len);
774 BUILTIN(ArraySplice) {
775 Heap* heap = isolate->heap();
776 Object* receiver = *args.receiver();
778 { MaybeObject* maybe_elms_obj =
779 EnsureJSArrayWithWritableFastElements(heap, receiver, &args, 3);
780 if (maybe_elms_obj == NULL)
781 return CallJsBuiltin(isolate, "ArraySplice", args);
782 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
784 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
785 return CallJsBuiltin(isolate, "ArraySplice", args);
787 FixedArray* elms = FixedArray::cast(elms_obj);
788 JSArray* array = JSArray::cast(receiver);
789 ASSERT(array->HasFastTypeElements());
791 int len = Smi::cast(array->length())->value();
793 int n_arguments = args.length() - 1;
795 int relative_start = 0;
796 if (n_arguments > 0) {
797 Object* arg1 = args[1];
799 relative_start = Smi::cast(arg1)->value();
800 } else if (!arg1->IsUndefined()) {
801 return CallJsBuiltin(isolate, "ArraySplice", args);
804 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
805 : Min(relative_start, len);
807 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
808 // given as a request to delete all the elements from the start.
809 // And it differs from the case of undefined delete count.
810 // This does not follow ECMA-262, but we do the same for
812 int actual_delete_count;
813 if (n_arguments == 1) {
814 ASSERT(len - actual_start >= 0);
815 actual_delete_count = len - actual_start;
817 int value = 0; // ToInteger(undefined) == 0
818 if (n_arguments > 1) {
819 Object* arg2 = args[2];
821 value = Smi::cast(arg2)->value();
823 return CallJsBuiltin(isolate, "ArraySplice", args);
826 actual_delete_count = Min(Max(value, 0), len - actual_start);
829 JSArray* result_array = NULL;
830 ElementsKind elements_kind =
831 JSObject::cast(receiver)->GetElementsKind();
832 MaybeObject* maybe_array =
833 heap->AllocateJSArrayAndStorage(elements_kind,
835 actual_delete_count);
836 if (!maybe_array->To(&result_array)) return maybe_array;
839 // Fill newly created array.
840 CopyObjectToObjectElements(elms, FAST_ELEMENTS, actual_start,
841 FixedArray::cast(result_array->elements()),
842 FAST_ELEMENTS, 0, actual_delete_count);
845 int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0;
846 int new_length = len - actual_delete_count + item_count;
848 bool elms_changed = false;
849 if (item_count < actual_delete_count) {
851 const bool trim_array = !heap->lo_space()->Contains(elms) &&
852 ((actual_start + item_count) <
853 (len - actual_delete_count - actual_start));
855 const int delta = actual_delete_count - item_count;
858 AssertNoAllocation no_gc;
859 MoveElements(heap, &no_gc, elms, delta, elms, 0, actual_start);
862 elms = LeftTrimFixedArray(heap, elms, delta);
866 AssertNoAllocation no_gc;
867 MoveElements(heap, &no_gc,
868 elms, actual_start + item_count,
869 elms, actual_start + actual_delete_count,
870 (len - actual_delete_count - actual_start));
871 FillWithHoles(heap, elms, new_length, len);
873 } else if (item_count > actual_delete_count) {
874 // Currently fixed arrays cannot grow too big, so
875 // we should never hit this case.
876 ASSERT((item_count - actual_delete_count) <= (Smi::kMaxValue - len));
878 // Check if array need to grow.
879 if (new_length > elms->length()) {
880 // New backing storage is needed.
881 int capacity = new_length + (new_length >> 1) + 16;
883 { MaybeObject* maybe_obj =
884 heap->AllocateUninitializedFixedArray(capacity);
885 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
887 FixedArray* new_elms = FixedArray::cast(obj);
890 // Copy the part before actual_start as is.
891 CopyObjectToObjectElements(elms, FAST_ELEMENTS, 0,
892 new_elms, FAST_ELEMENTS, 0, actual_start);
893 const int to_copy = len - actual_delete_count - actual_start;
894 CopyObjectToObjectElements(elms, FAST_ELEMENTS,
895 actual_start + actual_delete_count,
896 new_elms, FAST_ELEMENTS,
897 actual_start + item_count, to_copy);
900 FillWithHoles(heap, new_elms, new_length, capacity);
905 AssertNoAllocation no_gc;
906 MoveElements(heap, &no_gc,
907 elms, actual_start + item_count,
908 elms, actual_start + actual_delete_count,
909 (len - actual_delete_count - actual_start));
913 AssertNoAllocation no_gc;
914 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
915 for (int k = actual_start; k < actual_start + item_count; k++) {
916 elms->set(k, args[3 + k - actual_start], mode);
920 array->set_elements(elms);
924 array->set_length(Smi::FromInt(new_length));
930 BUILTIN(ArrayConcat) {
931 Heap* heap = isolate->heap();
932 Context* global_context = isolate->context()->global_context();
933 JSObject* array_proto =
934 JSObject::cast(global_context->array_function()->prototype());
935 if (!ArrayPrototypeHasNoElements(heap, global_context, array_proto)) {
936 return CallJsBuiltin(isolate, "ArrayConcat", args);
939 // Iterate through all the arguments performing checks
940 // and calculating total length.
941 int n_arguments = args.length();
943 ElementsKind elements_kind = FAST_SMI_ONLY_ELEMENTS;
944 for (int i = 0; i < n_arguments; i++) {
945 Object* arg = args[i];
946 if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastTypeElements()
947 || JSArray::cast(arg)->GetPrototype() != array_proto) {
948 return CallJsBuiltin(isolate, "ArrayConcat", args);
951 int len = Smi::cast(JSArray::cast(arg)->length())->value();
953 // We shouldn't overflow when adding another len.
954 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
955 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt);
958 ASSERT(result_len >= 0);
960 if (result_len > FixedArray::kMaxLength) {
961 return CallJsBuiltin(isolate, "ArrayConcat", args);
964 if (!JSArray::cast(arg)->HasFastSmiOnlyElements()) {
965 elements_kind = FAST_ELEMENTS;
970 JSArray* result_array;
971 MaybeObject* maybe_array =
972 heap->AllocateJSArrayAndStorage(elements_kind,
975 if (!maybe_array->To(&result_array)) return maybe_array;
976 if (result_len == 0) return result_array;
980 FixedArray* result_elms(FixedArray::cast(result_array->elements()));
981 for (int i = 0; i < n_arguments; i++) {
982 JSArray* array = JSArray::cast(args[i]);
983 int len = Smi::cast(array->length())->value();
984 FixedArray* elms = FixedArray::cast(array->elements());
985 CopyObjectToObjectElements(elms, FAST_ELEMENTS, 0,
986 result_elms, FAST_ELEMENTS,
990 ASSERT(start_pos == result_len);
996 // -----------------------------------------------------------------------------
997 // Strict mode poison pills
1000 BUILTIN(StrictModePoisonPill) {
1002 return isolate->Throw(*isolate->factory()->NewTypeError(
1003 "strict_poison_pill", HandleVector<Object>(NULL, 0)));
1006 // -----------------------------------------------------------------------------
1010 // Returns the holder JSObject if the function can legally be called
1011 // with this receiver. Returns Heap::null_value() if the call is
1012 // illegal. Any arguments that don't fit the expected type is
1013 // overwritten with undefined. Arguments that do fit the expected
1014 // type is overwritten with the object in the prototype chain that
1015 // actually has that type.
1016 static inline Object* TypeCheck(Heap* heap,
1019 FunctionTemplateInfo* info) {
1020 Object* recv = argv[0];
1021 // API calls are only supported with JSObject receivers.
1022 if (!recv->IsJSObject()) return heap->null_value();
1023 Object* sig_obj = info->signature();
1024 if (sig_obj->IsUndefined()) return recv;
1025 SignatureInfo* sig = SignatureInfo::cast(sig_obj);
1026 // If necessary, check the receiver
1027 Object* recv_type = sig->receiver();
1029 Object* holder = recv;
1030 if (!recv_type->IsUndefined()) {
1031 for (; holder != heap->null_value(); holder = holder->GetPrototype()) {
1032 if (holder->IsInstanceOf(FunctionTemplateInfo::cast(recv_type))) {
1036 if (holder == heap->null_value()) return holder;
1038 Object* args_obj = sig->args();
1039 // If there is no argument signature we're done
1040 if (args_obj->IsUndefined()) return holder;
1041 FixedArray* args = FixedArray::cast(args_obj);
1042 int length = args->length();
1043 if (argc <= length) length = argc - 1;
1044 for (int i = 0; i < length; i++) {
1045 Object* argtype = args->get(i);
1046 if (argtype->IsUndefined()) continue;
1047 Object** arg = &argv[-1 - i];
1048 Object* current = *arg;
1049 for (; current != heap->null_value(); current = current->GetPrototype()) {
1050 if (current->IsInstanceOf(FunctionTemplateInfo::cast(argtype))) {
1055 if (current == heap->null_value()) *arg = heap->undefined_value();
1061 template <bool is_construct>
1062 MUST_USE_RESULT static MaybeObject* HandleApiCallHelper(
1063 BuiltinArguments<NEEDS_CALLED_FUNCTION> args, Isolate* isolate) {
1064 ASSERT(is_construct == CalledAsConstructor(isolate));
1065 Heap* heap = isolate->heap();
1067 HandleScope scope(isolate);
1068 Handle<JSFunction> function = args.called_function();
1069 ASSERT(function->shared()->IsApiFunction());
1071 FunctionTemplateInfo* fun_data = function->shared()->get_api_func_data();
1073 Handle<FunctionTemplateInfo> desc(fun_data, isolate);
1074 bool pending_exception = false;
1075 isolate->factory()->ConfigureInstance(
1076 desc, Handle<JSObject>::cast(args.receiver()), &pending_exception);
1077 ASSERT(isolate->has_pending_exception() == pending_exception);
1078 if (pending_exception) return Failure::Exception();
1082 Object* raw_holder = TypeCheck(heap, args.length(), &args[0], fun_data);
1084 if (raw_holder->IsNull()) {
1085 // This function cannot be called with the given receiver. Abort!
1086 Handle<Object> obj =
1087 isolate->factory()->NewTypeError(
1088 "illegal_invocation", HandleVector(&function, 1));
1089 return isolate->Throw(*obj);
1092 Object* raw_call_data = fun_data->call_code();
1093 if (!raw_call_data->IsUndefined()) {
1094 CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
1095 Object* callback_obj = call_data->callback();
1096 v8::InvocationCallback callback =
1097 v8::ToCData<v8::InvocationCallback>(callback_obj);
1098 Object* data_obj = call_data->data();
1101 LOG(isolate, ApiObjectAccess("call", JSObject::cast(*args.receiver())));
1102 ASSERT(raw_holder->IsJSObject());
1104 CustomArguments custom(isolate);
1105 v8::ImplementationUtilities::PrepareArgumentsData(custom.end(),
1106 isolate, data_obj, *function, raw_holder);
1108 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
1114 v8::Handle<v8::Value> value;
1116 // Leaving JavaScript.
1117 VMState state(isolate, EXTERNAL);
1118 ExternalCallbackScope call_scope(isolate,
1119 v8::ToCData<Address>(callback_obj));
1120 value = callback(new_args);
1122 if (value.IsEmpty()) {
1123 result = heap->undefined_value();
1125 result = *reinterpret_cast<Object**>(*value);
1128 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1129 if (!is_construct || result->IsJSObject()) return result;
1132 return *args.receiver();
1136 BUILTIN(HandleApiCall) {
1137 return HandleApiCallHelper<false>(args, isolate);
1141 BUILTIN(HandleApiCallConstruct) {
1142 return HandleApiCallHelper<true>(args, isolate);
1146 // Helper function to handle calls to non-function objects created through the
1147 // API. The object can be called as either a constructor (using new) or just as
1148 // a function (without new).
1149 MUST_USE_RESULT static MaybeObject* HandleApiCallAsFunctionOrConstructor(
1151 bool is_construct_call,
1152 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
1153 // Non-functions are never called as constructors. Even if this is an object
1154 // called as a constructor the delegate call is not a construct call.
1155 ASSERT(!CalledAsConstructor(isolate));
1156 Heap* heap = isolate->heap();
1158 Handle<Object> receiver = args.receiver();
1160 // Get the object called.
1161 JSObject* obj = JSObject::cast(*receiver);
1163 // Get the invocation callback from the function descriptor that was
1164 // used to create the called object.
1165 ASSERT(obj->map()->has_instance_call_handler());
1166 JSFunction* constructor = JSFunction::cast(obj->map()->constructor());
1167 ASSERT(constructor->shared()->IsApiFunction());
1169 constructor->shared()->get_api_func_data()->instance_call_handler();
1170 ASSERT(!handler->IsUndefined());
1171 CallHandlerInfo* call_data = CallHandlerInfo::cast(handler);
1172 Object* callback_obj = call_data->callback();
1173 v8::InvocationCallback callback =
1174 v8::ToCData<v8::InvocationCallback>(callback_obj);
1176 // Get the data for the call and perform the callback.
1179 HandleScope scope(isolate);
1180 LOG(isolate, ApiObjectAccess("call non-function", obj));
1182 CustomArguments custom(isolate);
1183 v8::ImplementationUtilities::PrepareArgumentsData(custom.end(),
1184 isolate, call_data->data(), constructor, obj);
1185 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
1190 v8::Handle<v8::Value> value;
1192 // Leaving JavaScript.
1193 VMState state(isolate, EXTERNAL);
1194 ExternalCallbackScope call_scope(isolate,
1195 v8::ToCData<Address>(callback_obj));
1196 value = callback(new_args);
1198 if (value.IsEmpty()) {
1199 result = heap->undefined_value();
1201 result = *reinterpret_cast<Object**>(*value);
1204 // Check for exceptions and return result.
1205 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1210 // Handle calls to non-function objects created through the API. This delegate
1211 // function is used when the call is a normal function call.
1212 BUILTIN(HandleApiCallAsFunction) {
1213 return HandleApiCallAsFunctionOrConstructor(isolate, false, args);
1217 // Handle calls to non-function objects created through the API. This delegate
1218 // function is used when the call is a construct call.
1219 BUILTIN(HandleApiCallAsConstructor) {
1220 return HandleApiCallAsFunctionOrConstructor(isolate, true, args);
1224 static void Generate_LoadIC_ArrayLength(MacroAssembler* masm) {
1225 LoadIC::GenerateArrayLength(masm);
1229 static void Generate_LoadIC_StringLength(MacroAssembler* masm) {
1230 LoadIC::GenerateStringLength(masm, false);
1234 static void Generate_LoadIC_StringWrapperLength(MacroAssembler* masm) {
1235 LoadIC::GenerateStringLength(masm, true);
1239 static void Generate_LoadIC_FunctionPrototype(MacroAssembler* masm) {
1240 LoadIC::GenerateFunctionPrototype(masm);
1244 static void Generate_LoadIC_Initialize(MacroAssembler* masm) {
1245 LoadIC::GenerateInitialize(masm);
1249 static void Generate_LoadIC_PreMonomorphic(MacroAssembler* masm) {
1250 LoadIC::GeneratePreMonomorphic(masm);
1254 static void Generate_LoadIC_Miss(MacroAssembler* masm) {
1255 LoadIC::GenerateMiss(masm);
1259 static void Generate_LoadIC_Megamorphic(MacroAssembler* masm) {
1260 LoadIC::GenerateMegamorphic(masm);
1264 static void Generate_LoadIC_Normal(MacroAssembler* masm) {
1265 LoadIC::GenerateNormal(masm);
1269 static void Generate_KeyedLoadIC_Initialize(MacroAssembler* masm) {
1270 KeyedLoadIC::GenerateInitialize(masm);
1274 static void Generate_KeyedLoadIC_Slow(MacroAssembler* masm) {
1275 KeyedLoadIC::GenerateRuntimeGetProperty(masm);
1279 static void Generate_KeyedLoadIC_Miss(MacroAssembler* masm) {
1280 KeyedLoadIC::GenerateMiss(masm, false);
1284 static void Generate_KeyedLoadIC_MissForceGeneric(MacroAssembler* masm) {
1285 KeyedLoadIC::GenerateMiss(masm, true);
1289 static void Generate_KeyedLoadIC_Generic(MacroAssembler* masm) {
1290 KeyedLoadIC::GenerateGeneric(masm);
1294 static void Generate_KeyedLoadIC_String(MacroAssembler* masm) {
1295 KeyedLoadIC::GenerateString(masm);
1299 static void Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler* masm) {
1300 KeyedLoadIC::GeneratePreMonomorphic(masm);
1303 static void Generate_KeyedLoadIC_IndexedInterceptor(MacroAssembler* masm) {
1304 KeyedLoadIC::GenerateIndexedInterceptor(masm);
1307 static void Generate_KeyedLoadIC_NonStrictArguments(MacroAssembler* masm) {
1308 KeyedLoadIC::GenerateNonStrictArguments(masm);
1311 static void Generate_StoreIC_Initialize(MacroAssembler* masm) {
1312 StoreIC::GenerateInitialize(masm);
1316 static void Generate_StoreIC_Initialize_Strict(MacroAssembler* masm) {
1317 StoreIC::GenerateInitialize(masm);
1321 static void Generate_StoreIC_Miss(MacroAssembler* masm) {
1322 StoreIC::GenerateMiss(masm);
1326 static void Generate_StoreIC_Normal(MacroAssembler* masm) {
1327 StoreIC::GenerateNormal(masm);
1331 static void Generate_StoreIC_Normal_Strict(MacroAssembler* masm) {
1332 StoreIC::GenerateNormal(masm);
1336 static void Generate_StoreIC_Megamorphic(MacroAssembler* masm) {
1337 StoreIC::GenerateMegamorphic(masm, kNonStrictMode);
1341 static void Generate_StoreIC_Megamorphic_Strict(MacroAssembler* masm) {
1342 StoreIC::GenerateMegamorphic(masm, kStrictMode);
1346 static void Generate_StoreIC_ArrayLength(MacroAssembler* masm) {
1347 StoreIC::GenerateArrayLength(masm);
1351 static void Generate_StoreIC_ArrayLength_Strict(MacroAssembler* masm) {
1352 StoreIC::GenerateArrayLength(masm);
1356 static void Generate_StoreIC_GlobalProxy(MacroAssembler* masm) {
1357 StoreIC::GenerateGlobalProxy(masm, kNonStrictMode);
1361 static void Generate_StoreIC_GlobalProxy_Strict(MacroAssembler* masm) {
1362 StoreIC::GenerateGlobalProxy(masm, kStrictMode);
1366 static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) {
1367 KeyedStoreIC::GenerateGeneric(masm, kNonStrictMode);
1371 static void Generate_KeyedStoreIC_Generic_Strict(MacroAssembler* masm) {
1372 KeyedStoreIC::GenerateGeneric(masm, kStrictMode);
1376 static void Generate_KeyedStoreIC_Miss(MacroAssembler* masm) {
1377 KeyedStoreIC::GenerateMiss(masm, false);
1381 static void Generate_KeyedStoreIC_MissForceGeneric(MacroAssembler* masm) {
1382 KeyedStoreIC::GenerateMiss(masm, true);
1386 static void Generate_KeyedStoreIC_Slow(MacroAssembler* masm) {
1387 KeyedStoreIC::GenerateSlow(masm);
1391 static void Generate_KeyedStoreIC_Initialize(MacroAssembler* masm) {
1392 KeyedStoreIC::GenerateInitialize(masm);
1396 static void Generate_KeyedStoreIC_Initialize_Strict(MacroAssembler* masm) {
1397 KeyedStoreIC::GenerateInitialize(masm);
1400 static void Generate_KeyedStoreIC_NonStrictArguments(MacroAssembler* masm) {
1401 KeyedStoreIC::GenerateNonStrictArguments(masm);
1404 static void Generate_TransitionElementsSmiToDouble(MacroAssembler* masm) {
1405 KeyedStoreIC::GenerateTransitionElementsSmiToDouble(masm);
1408 static void Generate_TransitionElementsDoubleToObject(MacroAssembler* masm) {
1409 KeyedStoreIC::GenerateTransitionElementsDoubleToObject(masm);
1412 #ifdef ENABLE_DEBUGGER_SUPPORT
1413 static void Generate_LoadIC_DebugBreak(MacroAssembler* masm) {
1414 Debug::GenerateLoadICDebugBreak(masm);
1418 static void Generate_StoreIC_DebugBreak(MacroAssembler* masm) {
1419 Debug::GenerateStoreICDebugBreak(masm);
1423 static void Generate_KeyedLoadIC_DebugBreak(MacroAssembler* masm) {
1424 Debug::GenerateKeyedLoadICDebugBreak(masm);
1428 static void Generate_KeyedStoreIC_DebugBreak(MacroAssembler* masm) {
1429 Debug::GenerateKeyedStoreICDebugBreak(masm);
1433 static void Generate_Return_DebugBreak(MacroAssembler* masm) {
1434 Debug::GenerateReturnDebugBreak(masm);
1438 static void Generate_CallFunctionStub_DebugBreak(MacroAssembler* masm) {
1439 Debug::GenerateCallFunctionStubDebugBreak(masm);
1443 static void Generate_CallFunctionStub_Recording_DebugBreak(
1444 MacroAssembler* masm) {
1445 Debug::GenerateCallFunctionStubRecordDebugBreak(masm);
1449 static void Generate_CallConstructStub_DebugBreak(MacroAssembler* masm) {
1450 Debug::GenerateCallConstructStubDebugBreak(masm);
1454 static void Generate_CallConstructStub_Recording_DebugBreak(
1455 MacroAssembler* masm) {
1456 Debug::GenerateCallConstructStubRecordDebugBreak(masm);
1460 static void Generate_Slot_DebugBreak(MacroAssembler* masm) {
1461 Debug::GenerateSlotDebugBreak(masm);
1465 static void Generate_PlainReturn_LiveEdit(MacroAssembler* masm) {
1466 Debug::GeneratePlainReturnLiveEdit(masm);
1470 static void Generate_FrameDropper_LiveEdit(MacroAssembler* masm) {
1471 Debug::GenerateFrameDropperLiveEdit(masm);
1476 Builtins::Builtins() : initialized_(false) {
1477 memset(builtins_, 0, sizeof(builtins_[0]) * builtin_count);
1478 memset(names_, 0, sizeof(names_[0]) * builtin_count);
1482 Builtins::~Builtins() {
1486 #define DEF_ENUM_C(name, ignore) FUNCTION_ADDR(Builtin_##name),
1487 Address const Builtins::c_functions_[cfunction_count] = {
1488 BUILTIN_LIST_C(DEF_ENUM_C)
1492 #define DEF_JS_NAME(name, ignore) #name,
1493 #define DEF_JS_ARGC(ignore, argc) argc,
1494 const char* const Builtins::javascript_names_[id_count] = {
1495 BUILTINS_LIST_JS(DEF_JS_NAME)
1498 int const Builtins::javascript_argc_[id_count] = {
1499 BUILTINS_LIST_JS(DEF_JS_ARGC)
1504 struct BuiltinDesc {
1507 const char* s_name; // name is only used for generating log information.
1510 BuiltinExtraArguments extra_args;
1513 #define BUILTIN_FUNCTION_TABLE_INIT { V8_ONCE_INIT, {} }
1515 class BuiltinFunctionTable {
1517 BuiltinDesc* functions() {
1518 CallOnce(&once_, &Builtins::InitBuiltinFunctionTable);
1523 BuiltinDesc functions_[Builtins::builtin_count + 1];
1525 friend class Builtins;
1528 static BuiltinFunctionTable builtin_function_table =
1529 BUILTIN_FUNCTION_TABLE_INIT;
1531 // Define array of pointers to generators and C builtin functions.
1532 // We do this in a sort of roundabout way so that we can do the initialization
1533 // within the lexical scope of Builtins:: and within a context where
1534 // Code::Flags names a non-abstract type.
1535 void Builtins::InitBuiltinFunctionTable() {
1536 BuiltinDesc* functions = builtin_function_table.functions_;
1537 functions[builtin_count].generator = NULL;
1538 functions[builtin_count].c_code = NULL;
1539 functions[builtin_count].s_name = NULL;
1540 functions[builtin_count].name = builtin_count;
1541 functions[builtin_count].flags = static_cast<Code::Flags>(0);
1542 functions[builtin_count].extra_args = NO_EXTRA_ARGUMENTS;
1544 #define DEF_FUNCTION_PTR_C(aname, aextra_args) \
1545 functions->generator = FUNCTION_ADDR(Generate_Adaptor); \
1546 functions->c_code = FUNCTION_ADDR(Builtin_##aname); \
1547 functions->s_name = #aname; \
1548 functions->name = c_##aname; \
1549 functions->flags = Code::ComputeFlags(Code::BUILTIN); \
1550 functions->extra_args = aextra_args; \
1553 #define DEF_FUNCTION_PTR_A(aname, kind, state, extra) \
1554 functions->generator = FUNCTION_ADDR(Generate_##aname); \
1555 functions->c_code = NULL; \
1556 functions->s_name = #aname; \
1557 functions->name = k##aname; \
1558 functions->flags = Code::ComputeFlags(Code::kind, \
1561 functions->extra_args = NO_EXTRA_ARGUMENTS; \
1564 BUILTIN_LIST_C(DEF_FUNCTION_PTR_C)
1565 BUILTIN_LIST_A(DEF_FUNCTION_PTR_A)
1566 BUILTIN_LIST_DEBUG_A(DEF_FUNCTION_PTR_A)
1568 #undef DEF_FUNCTION_PTR_C
1569 #undef DEF_FUNCTION_PTR_A
1572 void Builtins::SetUp(bool create_heap_objects) {
1573 ASSERT(!initialized_);
1574 Isolate* isolate = Isolate::Current();
1575 Heap* heap = isolate->heap();
1577 // Create a scope for the handles in the builtins.
1578 HandleScope scope(isolate);
1580 const BuiltinDesc* functions = builtin_function_table.functions();
1582 // For now we generate builtin adaptor code into a stack-allocated
1583 // buffer, before copying it into individual code objects. Be careful
1584 // with alignment, some platforms don't like unaligned code.
1585 union { int force_alignment; byte buffer[4*KB]; } u;
1587 // Traverse the list of builtins and generate an adaptor in a
1588 // separate code object for each one.
1589 for (int i = 0; i < builtin_count; i++) {
1590 if (create_heap_objects) {
1591 MacroAssembler masm(isolate, u.buffer, sizeof u.buffer);
1592 // Generate the code/adaptor.
1593 typedef void (*Generator)(MacroAssembler*, int, BuiltinExtraArguments);
1594 Generator g = FUNCTION_CAST<Generator>(functions[i].generator);
1595 // We pass all arguments to the generator, but it may not use all of
1596 // them. This works because the first arguments are on top of the
1598 ASSERT(!masm.has_frame());
1599 g(&masm, functions[i].name, functions[i].extra_args);
1600 // Move the code into the object heap.
1602 masm.GetCode(&desc);
1603 Code::Flags flags = functions[i].flags;
1604 Object* code = NULL;
1606 // During startup it's OK to always allocate and defer GC to later.
1607 // This simplifies things because we don't need to retry.
1608 AlwaysAllocateScope __scope__;
1609 { MaybeObject* maybe_code =
1610 heap->CreateCode(desc, flags, masm.CodeObject());
1611 if (!maybe_code->ToObject(&code)) {
1612 v8::internal::V8::FatalProcessOutOfMemory("CreateCode");
1616 // Log the event and add the code to the builtins array.
1618 CodeCreateEvent(Logger::BUILTIN_TAG,
1620 functions[i].s_name));
1621 GDBJIT(AddCode(GDBJITInterface::BUILTIN,
1622 functions[i].s_name,
1624 builtins_[i] = code;
1625 #ifdef ENABLE_DISASSEMBLER
1626 if (FLAG_print_builtin_code) {
1627 PrintF("Builtin: %s\n", functions[i].s_name);
1628 Code::cast(code)->Disassemble(functions[i].s_name);
1633 // Deserializing. The values will be filled in during IterateBuiltins.
1634 builtins_[i] = NULL;
1636 names_[i] = functions[i].s_name;
1639 // Mark as initialized.
1640 initialized_ = true;
1644 void Builtins::TearDown() {
1645 initialized_ = false;
1649 void Builtins::IterateBuiltins(ObjectVisitor* v) {
1650 v->VisitPointers(&builtins_[0], &builtins_[0] + builtin_count);
1654 const char* Builtins::Lookup(byte* pc) {
1655 // may be called during initialization (disassembler!)
1657 for (int i = 0; i < builtin_count; i++) {
1658 Code* entry = Code::cast(builtins_[i]);
1659 if (entry->contains(pc)) {
1668 #define DEFINE_BUILTIN_ACCESSOR_C(name, ignore) \
1669 Handle<Code> Builtins::name() { \
1670 Code** code_address = \
1671 reinterpret_cast<Code**>(builtin_address(k##name)); \
1672 return Handle<Code>(code_address); \
1674 #define DEFINE_BUILTIN_ACCESSOR_A(name, kind, state, extra) \
1675 Handle<Code> Builtins::name() { \
1676 Code** code_address = \
1677 reinterpret_cast<Code**>(builtin_address(k##name)); \
1678 return Handle<Code>(code_address); \
1680 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C)
1681 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A)
1682 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A)
1683 #undef DEFINE_BUILTIN_ACCESSOR_C
1684 #undef DEFINE_BUILTIN_ACCESSOR_A
1687 } } // namespace v8::internal