1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
8 #include "src/api-natives.h"
9 #include "src/arguments.h"
10 #include "src/base/once.h"
11 #include "src/bootstrapper.h"
12 #include "src/builtins.h"
13 #include "src/cpu-profiler.h"
14 #include "src/gdb-jit.h"
15 #include "src/heap/mark-compact.h"
16 #include "src/heap-profiler.h"
17 #include "src/ic/handler-compiler.h"
18 #include "src/ic/ic.h"
19 #include "src/messages.h"
20 #include "src/prototype.h"
21 #include "src/vm-state-inl.h"
28 // Arguments object passed to C++ builtins.
29 template <BuiltinExtraArguments extra_args>
30 class BuiltinArguments : public Arguments {
32 BuiltinArguments(int length, Object** arguments)
33 : Arguments(length, arguments) { }
35 Object*& operator[] (int index) {
36 DCHECK(index < length());
37 return Arguments::operator[](index);
40 template <class S> Handle<S> at(int index) {
41 DCHECK(index < length());
42 return Arguments::at<S>(index);
45 Handle<Object> receiver() {
46 return Arguments::at<Object>(0);
49 Handle<JSFunction> called_function() {
50 STATIC_ASSERT(extra_args == NEEDS_CALLED_FUNCTION);
51 return Arguments::at<JSFunction>(Arguments::length() - 1);
54 // Gets the total number of arguments including the receiver (but
55 // excluding extra arguments).
57 STATIC_ASSERT(extra_args == NO_EXTRA_ARGUMENTS);
58 return Arguments::length();
63 // Check we have at least the receiver.
64 DCHECK(Arguments::length() >= 1);
70 // Specialize BuiltinArguments for the called function extra argument.
73 int BuiltinArguments<NEEDS_CALLED_FUNCTION>::length() const {
74 return Arguments::length() - 1;
79 void BuiltinArguments<NEEDS_CALLED_FUNCTION>::Verify() {
80 // Check we have at least the receiver and the called function.
81 DCHECK(Arguments::length() >= 2);
82 // Make sure cast to JSFunction succeeds.
88 #define DEF_ARG_TYPE(name, spec) \
89 typedef BuiltinArguments<spec> name##ArgumentsType;
90 BUILTIN_LIST_C(DEF_ARG_TYPE)
95 // ----------------------------------------------------------------------------
96 // Support macro for defining builtins in C++.
97 // ----------------------------------------------------------------------------
99 // A builtin function is defined by writing:
105 // In the body of the builtin function the arguments can be accessed
106 // through the BuiltinArguments object args.
110 #define BUILTIN(name) \
111 MUST_USE_RESULT static Object* Builtin_Impl_##name( \
112 name##ArgumentsType args, Isolate* isolate); \
113 MUST_USE_RESULT static Object* Builtin_##name( \
114 int args_length, Object** args_object, Isolate* isolate) { \
115 name##ArgumentsType args(args_length, args_object); \
117 return Builtin_Impl_##name(args, isolate); \
119 MUST_USE_RESULT static Object* Builtin_Impl_##name( \
120 name##ArgumentsType args, Isolate* isolate)
122 #else // For release mode.
124 #define BUILTIN(name) \
125 static Object* Builtin_impl##name( \
126 name##ArgumentsType args, Isolate* isolate); \
127 static Object* Builtin_##name( \
128 int args_length, Object** args_object, Isolate* isolate) { \
129 name##ArgumentsType args(args_length, args_object); \
130 return Builtin_impl##name(args, isolate); \
132 static Object* Builtin_impl##name( \
133 name##ArgumentsType args, Isolate* isolate)
138 static inline bool CalledAsConstructor(Isolate* isolate) {
139 // Calculate the result using a full stack frame iterator and check
140 // that the state of the stack is as we assume it to be in the
142 StackFrameIterator it(isolate);
143 DCHECK(it.frame()->is_exit());
145 StackFrame* frame = it.frame();
146 bool reference_result = frame->is_construct();
147 Address fp = Isolate::c_entry_fp(isolate->thread_local_top());
148 // Because we know fp points to an exit frame we can use the relevant
149 // part of ExitFrame::ComputeCallerState directly.
150 const int kCallerOffset = ExitFrameConstants::kCallerFPOffset;
151 Address caller_fp = Memory::Address_at(fp + kCallerOffset);
152 // This inlines the part of StackFrame::ComputeType that grabs the
153 // type of the current frame. Note that StackFrame::ComputeType
154 // has been specialized for each architecture so if any one of them
155 // changes this code has to be changed as well.
156 const int kMarkerOffset = StandardFrameConstants::kMarkerOffset;
157 const Smi* kConstructMarker = Smi::FromInt(StackFrame::CONSTRUCT);
158 Object* marker = Memory::Object_at(caller_fp + kMarkerOffset);
159 bool result = (marker == kConstructMarker);
160 DCHECK_EQ(result, reference_result);
166 // ----------------------------------------------------------------------------
170 return isolate->heap()->undefined_value(); // Make compiler happy.
174 BUILTIN(EmptyFunction) {
175 return isolate->heap()->undefined_value();
179 static void MoveDoubleElements(FixedDoubleArray* dst, int dst_index,
180 FixedDoubleArray* src, int src_index, int len) {
181 if (len == 0) return;
182 MemMove(dst->data_start() + dst_index, src->data_start() + src_index,
187 static bool ArrayPrototypeHasNoElements(Heap* heap, PrototypeIterator* iter) {
188 DisallowHeapAllocation no_gc;
189 for (; !iter->IsAtEnd(); iter->Advance()) {
190 if (iter->GetCurrent()->IsJSProxy()) return false;
191 if (JSObject::cast(iter->GetCurrent())->elements() !=
192 heap->empty_fixed_array()) {
200 static inline bool IsJSArrayFastElementMovingAllowed(Heap* heap,
202 DisallowHeapAllocation no_gc;
203 Isolate* isolate = heap->isolate();
204 if (!isolate->IsFastArrayConstructorPrototypeChainIntact()) {
208 // If the array prototype chain is intact (and free of elements), and if the
209 // receiver's prototype is the array prototype, then we are done.
210 Object* prototype = receiver->map()->prototype();
211 if (prototype->IsJSArray() &&
212 isolate->is_initial_array_prototype(JSArray::cast(prototype))) {
217 PrototypeIterator iter(isolate, receiver);
218 return ArrayPrototypeHasNoElements(heap, &iter);
222 // Returns empty handle if not applicable.
224 static inline MaybeHandle<FixedArrayBase> EnsureJSArrayWithWritableFastElements(
226 Handle<Object> receiver,
228 int first_added_arg) {
229 if (!receiver->IsJSArray()) return MaybeHandle<FixedArrayBase>();
230 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
231 // If there may be elements accessors in the prototype chain, the fast path
232 // cannot be used if there arguments to add to the array.
233 Heap* heap = isolate->heap();
234 if (args != NULL && !IsJSArrayFastElementMovingAllowed(heap, *array)) {
235 return MaybeHandle<FixedArrayBase>();
237 if (array->map()->is_observed()) return MaybeHandle<FixedArrayBase>();
238 if (!array->map()->is_extensible()) return MaybeHandle<FixedArrayBase>();
239 Handle<FixedArrayBase> elms(array->elements(), isolate);
240 Map* map = elms->map();
241 if (map == heap->fixed_array_map()) {
242 if (args == NULL || array->HasFastObjectElements()) return elms;
243 } else if (map == heap->fixed_cow_array_map()) {
244 elms = JSObject::EnsureWritableFastElements(array);
245 if (args == NULL || array->HasFastObjectElements()) return elms;
246 } else if (map == heap->fixed_double_array_map()) {
247 if (args == NULL) return elms;
249 return MaybeHandle<FixedArrayBase>();
252 // Adding elements to the array prototype would break code that makes sure
253 // it has no elements. Handle that elsewhere.
254 if (isolate->IsAnyInitialArrayPrototype(array)) {
255 return MaybeHandle<FixedArrayBase>();
258 // Need to ensure that the arguments passed in args can be contained in
260 int args_length = args->length();
261 if (first_added_arg >= args_length) return handle(array->elements(), isolate);
263 ElementsKind origin_kind = array->map()->elements_kind();
264 DCHECK(!IsFastObjectElementsKind(origin_kind));
265 ElementsKind target_kind = origin_kind;
267 DisallowHeapAllocation no_gc;
268 int arg_count = args->length() - first_added_arg;
269 Object** arguments = args->arguments() - first_added_arg - (arg_count - 1);
270 for (int i = 0; i < arg_count; i++) {
271 Object* arg = arguments[i];
272 if (arg->IsHeapObject()) {
273 if (arg->IsHeapNumber()) {
274 target_kind = FAST_DOUBLE_ELEMENTS;
276 target_kind = FAST_ELEMENTS;
282 if (target_kind != origin_kind) {
283 JSObject::TransitionElementsKind(array, target_kind);
284 return handle(array->elements(), isolate);
290 MUST_USE_RESULT static Object* CallJsBuiltin(
293 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
294 HandleScope handleScope(isolate);
296 Handle<Object> js_builtin = Object::GetProperty(
298 handle(isolate->native_context()->builtins(), isolate),
299 name).ToHandleChecked();
300 Handle<JSFunction> function = Handle<JSFunction>::cast(js_builtin);
301 int argc = args.length() - 1;
302 ScopedVector<Handle<Object> > argv(argc);
303 for (int i = 0; i < argc; ++i) {
304 argv[i] = args.at<Object>(i + 1);
306 Handle<Object> result;
307 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
309 Execution::Call(isolate,
319 HandleScope scope(isolate);
320 Handle<Object> receiver = args.receiver();
321 MaybeHandle<FixedArrayBase> maybe_elms_obj =
322 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1);
323 Handle<FixedArrayBase> elms_obj;
324 if (!maybe_elms_obj.ToHandle(&elms_obj)) {
325 return CallJsBuiltin(isolate, "$arrayPush", args);
328 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
329 int len = Smi::cast(array->length())->value();
330 int to_add = args.length() - 1;
331 if (to_add > 0 && JSArray::WouldChangeReadOnlyLength(array, len + to_add)) {
332 return CallJsBuiltin(isolate, "$arrayPush", args);
334 DCHECK(!array->map()->is_observed());
336 ElementsKind kind = array->GetElementsKind();
338 if (IsFastSmiOrObjectElementsKind(kind)) {
339 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
341 return Smi::FromInt(len);
343 // Currently fixed arrays cannot grow too big, so
344 // we should never hit this case.
345 DCHECK(to_add <= (Smi::kMaxValue - len));
347 int new_length = len + to_add;
349 if (new_length > elms->length()) {
350 // New backing storage is needed.
351 int capacity = new_length + (new_length >> 1) + 16;
352 Handle<FixedArray> new_elms =
353 isolate->factory()->NewUninitializedFixedArray(capacity);
355 ElementsAccessor* accessor = array->GetElementsAccessor();
356 accessor->CopyElements(
357 elms_obj, 0, kind, new_elms, 0,
358 ElementsAccessor::kCopyToEndAndInitializeToHole);
363 // Add the provided values.
364 DisallowHeapAllocation no_gc;
365 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
366 for (int index = 0; index < to_add; index++) {
367 elms->set(index + len, args[index + 1], mode);
370 if (*elms != array->elements()) {
371 array->set_elements(*elms);
375 array->set_length(Smi::FromInt(new_length));
376 return Smi::FromInt(new_length);
378 int elms_len = elms_obj->length();
380 return Smi::FromInt(len);
382 // Currently fixed arrays cannot grow too big, so
383 // we should never hit this case.
384 DCHECK(to_add <= (Smi::kMaxValue - len));
386 int new_length = len + to_add;
388 Handle<FixedDoubleArray> new_elms;
390 if (new_length > elms_len) {
391 // New backing storage is needed.
392 int capacity = new_length + (new_length >> 1) + 16;
393 // Create new backing store; since capacity > 0, we can
394 // safely cast to FixedDoubleArray.
395 new_elms = Handle<FixedDoubleArray>::cast(
396 isolate->factory()->NewFixedDoubleArray(capacity));
398 ElementsAccessor* accessor = array->GetElementsAccessor();
399 accessor->CopyElements(
400 elms_obj, 0, kind, new_elms, 0,
401 ElementsAccessor::kCopyToEndAndInitializeToHole);
404 // to_add is > 0 and new_length <= elms_len, so elms_obj cannot be the
405 // empty_fixed_array.
406 new_elms = Handle<FixedDoubleArray>::cast(elms_obj);
409 // Add the provided values.
410 DisallowHeapAllocation no_gc;
412 for (index = 0; index < to_add; index++) {
413 Object* arg = args[index + 1];
414 new_elms->set(index + len, arg->Number());
417 if (*new_elms != array->elements()) {
418 array->set_elements(*new_elms);
422 array->set_length(Smi::FromInt(new_length));
423 return Smi::FromInt(new_length);
429 HandleScope scope(isolate);
430 Handle<Object> receiver = args.receiver();
431 MaybeHandle<FixedArrayBase> maybe_elms_obj =
432 EnsureJSArrayWithWritableFastElements(isolate, receiver, NULL, 0);
433 Handle<FixedArrayBase> elms_obj;
434 if (!maybe_elms_obj.ToHandle(&elms_obj)) {
435 return CallJsBuiltin(isolate, "$arrayPop", args);
438 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
439 DCHECK(!array->map()->is_observed());
441 uint32_t len = static_cast<uint32_t>(Smi::cast(array->length())->value());
442 if (len == 0) return isolate->heap()->undefined_value();
444 if (JSArray::HasReadOnlyLength(array)) {
445 return CallJsBuiltin(isolate, "$arrayPop", args);
448 ElementsAccessor* accessor = array->GetElementsAccessor();
449 uint32_t new_length = len - 1;
450 Handle<Object> element;
451 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
452 isolate, element, Object::GetElement(isolate, array, new_length));
454 RETURN_FAILURE_ON_EXCEPTION(
456 accessor->SetLength(array, handle(Smi::FromInt(new_length), isolate)));
461 BUILTIN(ArrayShift) {
462 HandleScope scope(isolate);
463 Heap* heap = isolate->heap();
464 Handle<Object> receiver = args.receiver();
465 MaybeHandle<FixedArrayBase> maybe_elms_obj =
466 EnsureJSArrayWithWritableFastElements(isolate, receiver, NULL, 0);
467 Handle<FixedArrayBase> elms_obj;
468 if (!maybe_elms_obj.ToHandle(&elms_obj) ||
469 !IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(*receiver))) {
470 return CallJsBuiltin(isolate, "$arrayShift", args);
472 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
473 DCHECK(!array->map()->is_observed());
475 int len = Smi::cast(array->length())->value();
476 if (len == 0) return heap->undefined_value();
478 if (JSArray::HasReadOnlyLength(array)) {
479 return CallJsBuiltin(isolate, "$arrayShift", args);
483 Handle<Object> first;
484 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, first,
485 Object::GetElement(isolate, array, 0));
487 if (heap->CanMoveObjectStart(*elms_obj)) {
488 array->set_elements(heap->LeftTrimFixedArray(*elms_obj, 1));
490 // Shift the elements.
491 if (elms_obj->IsFixedArray()) {
492 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
493 DisallowHeapAllocation no_gc;
494 heap->MoveElements(*elms, 0, 1, len - 1);
495 elms->set(len - 1, heap->the_hole_value());
497 Handle<FixedDoubleArray> elms = Handle<FixedDoubleArray>::cast(elms_obj);
498 MoveDoubleElements(*elms, 0, *elms, 1, len - 1);
499 elms->set_the_hole(len - 1);
504 array->set_length(Smi::FromInt(len - 1));
510 BUILTIN(ArrayUnshift) {
511 HandleScope scope(isolate);
512 Heap* heap = isolate->heap();
513 Handle<Object> receiver = args.receiver();
514 MaybeHandle<FixedArrayBase> maybe_elms_obj =
515 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1);
516 Handle<FixedArrayBase> elms_obj;
517 if (!maybe_elms_obj.ToHandle(&elms_obj)) {
518 return CallJsBuiltin(isolate, "$arrayUnshift", args);
520 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
521 DCHECK(!array->map()->is_observed());
522 if (!array->HasFastSmiOrObjectElements()) {
523 return CallJsBuiltin(isolate, "$arrayUnshift", args);
525 int len = Smi::cast(array->length())->value();
526 int to_add = args.length() - 1;
527 int new_length = len + to_add;
528 // Currently fixed arrays cannot grow too big, so
529 // we should never hit this case.
530 DCHECK(to_add <= (Smi::kMaxValue - len));
532 if (to_add > 0 && JSArray::WouldChangeReadOnlyLength(array, len + to_add)) {
533 return CallJsBuiltin(isolate, "$arrayUnshift", args);
536 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
538 if (new_length > elms->length()) {
539 // New backing storage is needed.
540 int capacity = new_length + (new_length >> 1) + 16;
541 Handle<FixedArray> new_elms =
542 isolate->factory()->NewUninitializedFixedArray(capacity);
544 ElementsKind kind = array->GetElementsKind();
545 ElementsAccessor* accessor = array->GetElementsAccessor();
546 accessor->CopyElements(
547 elms, 0, kind, new_elms, to_add,
548 ElementsAccessor::kCopyToEndAndInitializeToHole);
551 array->set_elements(*elms);
553 DisallowHeapAllocation no_gc;
554 heap->MoveElements(*elms, to_add, 0, len);
557 // Add the provided values.
558 DisallowHeapAllocation no_gc;
559 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
560 for (int i = 0; i < to_add; i++) {
561 elms->set(i, args[i + 1], mode);
565 array->set_length(Smi::FromInt(new_length));
566 return Smi::FromInt(new_length);
570 BUILTIN(ArraySlice) {
571 HandleScope scope(isolate);
572 Heap* heap = isolate->heap();
573 Handle<Object> receiver = args.receiver();
575 int relative_start = 0;
576 int relative_end = 0;
578 DisallowHeapAllocation no_gc;
579 if (receiver->IsJSArray()) {
580 JSArray* array = JSArray::cast(*receiver);
581 if (!IsJSArrayFastElementMovingAllowed(heap, array)) {
582 AllowHeapAllocation allow_allocation;
583 return CallJsBuiltin(isolate, "$arraySlice", args);
586 if (!array->HasFastElements()) {
587 AllowHeapAllocation allow_allocation;
588 return CallJsBuiltin(isolate, "$arraySlice", args);
591 len = Smi::cast(array->length())->value();
593 // Array.slice(arguments, ...) is quite a common idiom (notably more
594 // than 50% of invocations in Web apps). Treat it in C++ as well.
596 isolate->context()->native_context()->sloppy_arguments_map();
598 bool is_arguments_object_with_fast_elements =
599 receiver->IsJSObject() &&
600 JSObject::cast(*receiver)->map() == arguments_map;
601 if (!is_arguments_object_with_fast_elements) {
602 AllowHeapAllocation allow_allocation;
603 return CallJsBuiltin(isolate, "$arraySlice", args);
605 JSObject* object = JSObject::cast(*receiver);
607 if (!object->HasFastElements()) {
608 AllowHeapAllocation allow_allocation;
609 return CallJsBuiltin(isolate, "$arraySlice", args);
612 Object* len_obj = object->InObjectPropertyAt(Heap::kArgumentsLengthIndex);
613 if (!len_obj->IsSmi()) {
614 AllowHeapAllocation allow_allocation;
615 return CallJsBuiltin(isolate, "$arraySlice", args);
617 len = Smi::cast(len_obj)->value();
618 if (len > object->elements()->length()) {
619 AllowHeapAllocation allow_allocation;
620 return CallJsBuiltin(isolate, "$arraySlice", args);
625 int n_arguments = args.length() - 1;
627 // Note carefully choosen defaults---if argument is missing,
628 // it's undefined which gets converted to 0 for relative_start
629 // and to len for relative_end.
632 if (n_arguments > 0) {
633 Object* arg1 = args[1];
635 relative_start = Smi::cast(arg1)->value();
636 } else if (arg1->IsHeapNumber()) {
637 double start = HeapNumber::cast(arg1)->value();
638 if (start < kMinInt || start > kMaxInt) {
639 AllowHeapAllocation allow_allocation;
640 return CallJsBuiltin(isolate, "$arraySlice", args);
642 relative_start = std::isnan(start) ? 0 : static_cast<int>(start);
643 } else if (!arg1->IsUndefined()) {
644 AllowHeapAllocation allow_allocation;
645 return CallJsBuiltin(isolate, "$arraySlice", args);
647 if (n_arguments > 1) {
648 Object* arg2 = args[2];
650 relative_end = Smi::cast(arg2)->value();
651 } else if (arg2->IsHeapNumber()) {
652 double end = HeapNumber::cast(arg2)->value();
653 if (end < kMinInt || end > kMaxInt) {
654 AllowHeapAllocation allow_allocation;
655 return CallJsBuiltin(isolate, "$arraySlice", args);
657 relative_end = std::isnan(end) ? 0 : static_cast<int>(end);
658 } else if (!arg2->IsUndefined()) {
659 AllowHeapAllocation allow_allocation;
660 return CallJsBuiltin(isolate, "$arraySlice", args);
666 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6.
667 int k = (relative_start < 0) ? Max(len + relative_start, 0)
668 : Min(relative_start, len);
670 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8.
671 int final = (relative_end < 0) ? Max(len + relative_end, 0)
672 : Min(relative_end, len);
674 // Calculate the length of result array.
675 int result_len = Max(final - k, 0);
677 Handle<JSObject> object = Handle<JSObject>::cast(receiver);
678 Handle<FixedArrayBase> elms(object->elements(), isolate);
680 ElementsKind kind = object->GetElementsKind();
681 if (IsHoleyElementsKind(kind)) {
682 DisallowHeapAllocation no_gc;
684 ElementsAccessor* accessor = ElementsAccessor::ForKind(kind);
685 for (int i = k; i < final; i++) {
686 if (!accessor->HasElement(object, i, elms)) {
692 kind = GetPackedElementsKind(kind);
693 } else if (!receiver->IsJSArray()) {
694 AllowHeapAllocation allow_allocation;
695 return CallJsBuiltin(isolate, "$arraySlice", args);
699 Handle<JSArray> result_array =
700 isolate->factory()->NewJSArray(kind, result_len, result_len);
702 DisallowHeapAllocation no_gc;
703 if (result_len == 0) return *result_array;
705 ElementsAccessor* accessor = object->GetElementsAccessor();
706 accessor->CopyElements(
707 elms, k, kind, handle(result_array->elements(), isolate), 0, result_len);
708 return *result_array;
712 BUILTIN(ArraySplice) {
713 HandleScope scope(isolate);
714 Heap* heap = isolate->heap();
715 Handle<Object> receiver = args.receiver();
716 MaybeHandle<FixedArrayBase> maybe_elms_obj =
717 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3);
718 Handle<FixedArrayBase> elms_obj;
719 if (!maybe_elms_obj.ToHandle(&elms_obj)) {
720 return CallJsBuiltin(isolate, "$arraySplice", args);
722 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
723 DCHECK(!array->map()->is_observed());
725 int len = Smi::cast(array->length())->value();
727 int n_arguments = args.length() - 1;
729 int relative_start = 0;
730 if (n_arguments > 0) {
731 DisallowHeapAllocation no_gc;
732 Object* arg1 = args[1];
734 relative_start = Smi::cast(arg1)->value();
735 } else if (arg1->IsHeapNumber()) {
736 double start = HeapNumber::cast(arg1)->value();
737 if (start < kMinInt || start > kMaxInt) {
738 AllowHeapAllocation allow_allocation;
739 return CallJsBuiltin(isolate, "$arraySplice", args);
741 relative_start = std::isnan(start) ? 0 : static_cast<int>(start);
742 } else if (!arg1->IsUndefined()) {
743 AllowHeapAllocation allow_allocation;
744 return CallJsBuiltin(isolate, "$arraySplice", args);
747 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
748 : Min(relative_start, len);
750 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
751 // given as a request to delete all the elements from the start.
752 // And it differs from the case of undefined delete count.
753 // This does not follow ECMA-262, but we do the same for
755 int actual_delete_count;
756 if (n_arguments == 1) {
757 DCHECK(len - actual_start >= 0);
758 actual_delete_count = len - actual_start;
760 int value = 0; // ToInteger(undefined) == 0
761 if (n_arguments > 1) {
762 DisallowHeapAllocation no_gc;
763 Object* arg2 = args[2];
765 value = Smi::cast(arg2)->value();
767 AllowHeapAllocation allow_allocation;
768 return CallJsBuiltin(isolate, "$arraySplice", args);
771 actual_delete_count = Min(Max(value, 0), len - actual_start);
774 ElementsKind elements_kind = array->GetElementsKind();
776 int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0;
777 int new_length = len - actual_delete_count + item_count;
779 // For double mode we do not support changing the length.
780 if (new_length > len && IsFastDoubleElementsKind(elements_kind)) {
781 return CallJsBuiltin(isolate, "$arraySplice", args);
784 if (new_length != len && JSArray::HasReadOnlyLength(array)) {
785 AllowHeapAllocation allow_allocation;
786 return CallJsBuiltin(isolate, "$arraySplice", args);
789 if (new_length == 0) {
790 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(
791 elms_obj, elements_kind, actual_delete_count);
792 array->set_elements(heap->empty_fixed_array());
793 array->set_length(Smi::FromInt(0));
797 Handle<JSArray> result_array =
798 isolate->factory()->NewJSArray(elements_kind,
800 actual_delete_count);
802 if (actual_delete_count > 0) {
803 DisallowHeapAllocation no_gc;
804 ElementsAccessor* accessor = array->GetElementsAccessor();
805 accessor->CopyElements(
806 elms_obj, actual_start, elements_kind,
807 handle(result_array->elements(), isolate), 0, actual_delete_count);
810 bool elms_changed = false;
811 if (item_count < actual_delete_count) {
813 const bool trim_array = !heap->lo_space()->Contains(*elms_obj) &&
814 ((actual_start + item_count) <
815 (len - actual_delete_count - actual_start));
817 const int delta = actual_delete_count - item_count;
819 if (elms_obj->IsFixedDoubleArray()) {
820 Handle<FixedDoubleArray> elms =
821 Handle<FixedDoubleArray>::cast(elms_obj);
822 MoveDoubleElements(*elms, delta, *elms, 0, actual_start);
824 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
825 DisallowHeapAllocation no_gc;
826 heap->MoveElements(*elms, delta, 0, actual_start);
829 if (heap->CanMoveObjectStart(*elms_obj)) {
830 // On the fast path we move the start of the object in memory.
831 elms_obj = handle(heap->LeftTrimFixedArray(*elms_obj, delta));
833 // This is the slow path. We are going to move the elements to the left
834 // by copying them. For trimmed values we store the hole.
835 if (elms_obj->IsFixedDoubleArray()) {
836 Handle<FixedDoubleArray> elms =
837 Handle<FixedDoubleArray>::cast(elms_obj);
838 MoveDoubleElements(*elms, 0, *elms, delta, len - delta);
839 elms->FillWithHoles(len - delta, len);
841 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
842 DisallowHeapAllocation no_gc;
843 heap->MoveElements(*elms, 0, delta, len - delta);
844 elms->FillWithHoles(len - delta, len);
849 if (elms_obj->IsFixedDoubleArray()) {
850 Handle<FixedDoubleArray> elms =
851 Handle<FixedDoubleArray>::cast(elms_obj);
852 MoveDoubleElements(*elms, actual_start + item_count,
853 *elms, actual_start + actual_delete_count,
854 (len - actual_delete_count - actual_start));
855 elms->FillWithHoles(new_length, len);
857 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
858 DisallowHeapAllocation no_gc;
859 heap->MoveElements(*elms, actual_start + item_count,
860 actual_start + actual_delete_count,
861 (len - actual_delete_count - actual_start));
862 elms->FillWithHoles(new_length, len);
865 } else if (item_count > actual_delete_count) {
866 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
867 // Currently fixed arrays cannot grow too big, so
868 // we should never hit this case.
869 DCHECK((item_count - actual_delete_count) <= (Smi::kMaxValue - len));
871 // Check if array need to grow.
872 if (new_length > elms->length()) {
873 // New backing storage is needed.
874 int capacity = new_length + (new_length >> 1) + 16;
875 Handle<FixedArray> new_elms =
876 isolate->factory()->NewUninitializedFixedArray(capacity);
878 DisallowHeapAllocation no_gc;
880 ElementsKind kind = array->GetElementsKind();
881 ElementsAccessor* accessor = array->GetElementsAccessor();
882 if (actual_start > 0) {
883 // Copy the part before actual_start as is.
884 accessor->CopyElements(
885 elms, 0, kind, new_elms, 0, actual_start);
887 accessor->CopyElements(
888 elms, actual_start + actual_delete_count, kind,
889 new_elms, actual_start + item_count,
890 ElementsAccessor::kCopyToEndAndInitializeToHole);
895 DisallowHeapAllocation no_gc;
896 heap->MoveElements(*elms, actual_start + item_count,
897 actual_start + actual_delete_count,
898 (len - actual_delete_count - actual_start));
902 if (IsFastDoubleElementsKind(elements_kind)) {
903 Handle<FixedDoubleArray> elms = Handle<FixedDoubleArray>::cast(elms_obj);
904 for (int k = actual_start; k < actual_start + item_count; k++) {
905 Object* arg = args[3 + k - actual_start];
907 elms->set(k, Smi::cast(arg)->value());
909 elms->set(k, HeapNumber::cast(arg)->value());
913 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
914 DisallowHeapAllocation no_gc;
915 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
916 for (int k = actual_start; k < actual_start + item_count; k++) {
917 elms->set(k, args[3 + k - actual_start], mode);
922 array->set_elements(*elms_obj);
925 array->set_length(Smi::FromInt(new_length));
927 return *result_array;
931 BUILTIN(ArrayConcat) {
932 HandleScope scope(isolate);
934 int n_arguments = args.length();
936 ElementsKind elements_kind = GetInitialFastElementsKind();
937 bool has_double = false;
939 DisallowHeapAllocation no_gc;
940 Heap* heap = isolate->heap();
941 Context* native_context = isolate->context()->native_context();
942 Object* array_proto = native_context->array_function()->prototype();
943 PrototypeIterator iter(isolate, array_proto,
944 PrototypeIterator::START_AT_RECEIVER);
945 if (!ArrayPrototypeHasNoElements(heap, &iter)) {
946 AllowHeapAllocation allow_allocation;
947 return CallJsBuiltin(isolate, "$arrayConcat", args);
950 // Iterate through all the arguments performing checks
951 // and calculating total length.
952 bool is_holey = false;
953 for (int i = 0; i < n_arguments; i++) {
954 Object* arg = args[i];
955 PrototypeIterator iter(isolate, arg);
956 if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastElements() ||
957 iter.GetCurrent() != array_proto) {
958 AllowHeapAllocation allow_allocation;
959 return CallJsBuiltin(isolate, "$arrayConcat", args);
961 int len = Smi::cast(JSArray::cast(arg)->length())->value();
963 // We shouldn't overflow when adding another len.
964 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
965 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt);
968 DCHECK(result_len >= 0);
970 if (result_len > FixedDoubleArray::kMaxLength) {
971 AllowHeapAllocation allow_allocation;
972 return CallJsBuiltin(isolate, "$arrayConcat", args);
975 ElementsKind arg_kind = JSArray::cast(arg)->map()->elements_kind();
976 has_double = has_double || IsFastDoubleElementsKind(arg_kind);
977 is_holey = is_holey || IsFastHoleyElementsKind(arg_kind);
978 if (IsMoreGeneralElementsKindTransition(elements_kind, arg_kind)) {
979 elements_kind = arg_kind;
982 if (is_holey) elements_kind = GetHoleyElementsKind(elements_kind);
985 // If a double array is concatted into a fast elements array, the fast
986 // elements array needs to be initialized to contain proper holes, since
987 // boxing doubles may cause incremental marking.
988 ArrayStorageAllocationMode mode =
989 has_double && IsFastObjectElementsKind(elements_kind)
990 ? INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE : DONT_INITIALIZE_ARRAY_ELEMENTS;
991 Handle<JSArray> result_array = isolate->factory()->NewJSArray(
992 elements_kind, result_len, result_len, WEAK, mode);
993 if (result_len == 0) return *result_array;
996 Handle<FixedArrayBase> storage(result_array->elements(), isolate);
997 ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind);
998 for (int i = 0; i < n_arguments; i++) {
999 // It is crucial to keep |array| in a raw pointer form to avoid performance
1001 JSArray* array = JSArray::cast(args[i]);
1002 int len = Smi::cast(array->length())->value();
1004 ElementsKind from_kind = array->GetElementsKind();
1005 accessor->CopyElements(array, 0, from_kind, storage, j, len);
1010 DCHECK(j == result_len);
1012 return *result_array;
1016 // -----------------------------------------------------------------------------
1017 // Throwers for restricted function properties and strict arguments object
1021 BUILTIN(RestrictedFunctionPropertiesThrower) {
1022 HandleScope scope(isolate);
1023 THROW_NEW_ERROR_RETURN_FAILURE(
1024 isolate, NewTypeError(MessageTemplate::kRestrictedFunctionProperties));
1028 BUILTIN(RestrictedStrictArgumentsPropertiesThrower) {
1029 HandleScope scope(isolate);
1030 THROW_NEW_ERROR_RETURN_FAILURE(
1031 isolate, NewTypeError(MessageTemplate::kStrictPoisonPill));
1035 // -----------------------------------------------------------------------------
1039 template <bool is_construct>
1040 MUST_USE_RESULT static MaybeHandle<Object> HandleApiCallHelper(
1041 Isolate* isolate, BuiltinArguments<NEEDS_CALLED_FUNCTION>& args) {
1042 HandleScope scope(isolate);
1043 Handle<JSFunction> function = args.called_function();
1044 // TODO(ishell): turn this back to a DCHECK.
1045 CHECK(function->shared()->IsApiFunction());
1047 Handle<FunctionTemplateInfo> fun_data(
1048 function->shared()->get_api_func_data(), isolate);
1050 ASSIGN_RETURN_ON_EXCEPTION(
1052 ApiNatives::ConfigureInstance(isolate, fun_data,
1053 Handle<JSObject>::cast(args.receiver())),
1057 DCHECK(!args[0]->IsNull());
1058 if (args[0]->IsUndefined()) args[0] = function->global_proxy();
1060 if (!is_construct && !fun_data->accept_any_receiver()) {
1061 Handle<Object> receiver(&args[0]);
1062 if (receiver->IsJSObject() && receiver->IsAccessCheckNeeded()) {
1063 Handle<JSObject> js_receiver = Handle<JSObject>::cast(receiver);
1064 if (!isolate->MayAccess(js_receiver)) {
1065 isolate->ReportFailedAccessCheck(js_receiver);
1066 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1071 Object* raw_holder = fun_data->GetCompatibleReceiver(isolate, args[0]);
1073 if (raw_holder->IsNull()) {
1074 // This function cannot be called with the given receiver. Abort!
1075 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIllegalInvocation),
1079 Object* raw_call_data = fun_data->call_code();
1080 if (!raw_call_data->IsUndefined()) {
1081 // TODO(ishell): remove this debugging code.
1082 CHECK(raw_call_data->IsCallHandlerInfo());
1083 CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
1084 Object* callback_obj = call_data->callback();
1085 v8::FunctionCallback callback =
1086 v8::ToCData<v8::FunctionCallback>(callback_obj);
1087 Object* data_obj = call_data->data();
1089 LOG(isolate, ApiObjectAccess("call", JSObject::cast(*args.receiver())));
1090 DCHECK(raw_holder->IsJSObject());
1092 FunctionCallbackArguments custom(isolate,
1100 v8::Handle<v8::Value> value = custom.Call(callback);
1101 Handle<Object> result;
1102 if (value.IsEmpty()) {
1103 result = isolate->factory()->undefined_value();
1105 result = v8::Utils::OpenHandle(*value);
1106 result->VerifyApiCallResultType();
1109 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
1110 if (!is_construct || result->IsJSObject()) {
1111 return scope.CloseAndEscape(result);
1115 return scope.CloseAndEscape(args.receiver());
1119 BUILTIN(HandleApiCall) {
1120 HandleScope scope(isolate);
1121 DCHECK(!CalledAsConstructor(isolate));
1122 Handle<Object> result;
1123 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
1124 HandleApiCallHelper<false>(isolate, args));
1129 BUILTIN(HandleApiCallConstruct) {
1130 HandleScope scope(isolate);
1131 DCHECK(CalledAsConstructor(isolate));
1132 Handle<Object> result;
1133 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
1134 HandleApiCallHelper<true>(isolate, args));
1141 class RelocatableArguments : public BuiltinArguments<NEEDS_CALLED_FUNCTION>,
1142 public Relocatable {
1144 RelocatableArguments(Isolate* isolate, int length, Object** arguments)
1145 : BuiltinArguments<NEEDS_CALLED_FUNCTION>(length, arguments),
1146 Relocatable(isolate) {}
1148 virtual inline void IterateInstance(ObjectVisitor* v) {
1149 if (length() == 0) return;
1150 v->VisitPointers(lowest_address(), highest_address() + 1);
1154 DISALLOW_COPY_AND_ASSIGN(RelocatableArguments);
1160 MaybeHandle<Object> Builtins::InvokeApiFunction(Handle<JSFunction> function,
1161 Handle<Object> receiver,
1163 Handle<Object> args[]) {
1164 // Construct BuiltinArguments object: function, arguments reversed, receiver.
1165 const int kBufferSize = 32;
1166 Object* small_argv[kBufferSize];
1168 if (argc + 2 <= kBufferSize) {
1171 argv = new Object* [argc + 2];
1173 argv[argc + 1] = *receiver;
1174 for (int i = 0; i < argc; ++i) {
1175 argv[argc - i] = *args[i];
1177 argv[0] = *function;
1178 MaybeHandle<Object> result;
1180 auto isolate = function->GetIsolate();
1181 RelocatableArguments arguments(isolate, argc + 2, &argv[argc + 1]);
1182 result = HandleApiCallHelper<false>(isolate, arguments);
1184 if (argv != small_argv) {
1191 // Helper function to handle calls to non-function objects created through the
1192 // API. The object can be called as either a constructor (using new) or just as
1193 // a function (without new).
1194 MUST_USE_RESULT static Object* HandleApiCallAsFunctionOrConstructor(
1196 bool is_construct_call,
1197 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
1198 // Non-functions are never called as constructors. Even if this is an object
1199 // called as a constructor the delegate call is not a construct call.
1200 DCHECK(!CalledAsConstructor(isolate));
1201 Heap* heap = isolate->heap();
1203 Handle<Object> receiver = args.receiver();
1205 // Get the object called.
1206 JSObject* obj = JSObject::cast(*receiver);
1208 // Get the invocation callback from the function descriptor that was
1209 // used to create the called object.
1210 DCHECK(obj->map()->has_instance_call_handler());
1211 JSFunction* constructor = JSFunction::cast(obj->map()->GetConstructor());
1212 // TODO(ishell): turn this back to a DCHECK.
1213 CHECK(constructor->shared()->IsApiFunction());
1215 constructor->shared()->get_api_func_data()->instance_call_handler();
1216 DCHECK(!handler->IsUndefined());
1217 // TODO(ishell): remove this debugging code.
1218 CHECK(handler->IsCallHandlerInfo());
1219 CallHandlerInfo* call_data = CallHandlerInfo::cast(handler);
1220 Object* callback_obj = call_data->callback();
1221 v8::FunctionCallback callback =
1222 v8::ToCData<v8::FunctionCallback>(callback_obj);
1224 // Get the data for the call and perform the callback.
1227 HandleScope scope(isolate);
1228 LOG(isolate, ApiObjectAccess("call non-function", obj));
1230 FunctionCallbackArguments custom(isolate,
1237 v8::Handle<v8::Value> value = custom.Call(callback);
1238 if (value.IsEmpty()) {
1239 result = heap->undefined_value();
1241 result = *reinterpret_cast<Object**>(*value);
1242 result->VerifyApiCallResultType();
1245 // Check for exceptions and return result.
1246 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
1251 // Handle calls to non-function objects created through the API. This delegate
1252 // function is used when the call is a normal function call.
1253 BUILTIN(HandleApiCallAsFunction) {
1254 return HandleApiCallAsFunctionOrConstructor(isolate, false, args);
1258 // Handle calls to non-function objects created through the API. This delegate
1259 // function is used when the call is a construct call.
1260 BUILTIN(HandleApiCallAsConstructor) {
1261 return HandleApiCallAsFunctionOrConstructor(isolate, true, args);
1265 static void Generate_LoadIC_Miss(MacroAssembler* masm) {
1266 LoadIC::GenerateMiss(masm);
1270 static void Generate_LoadIC_Normal(MacroAssembler* masm) {
1271 LoadIC::GenerateNormal(masm);
1275 static void Generate_LoadIC_Getter_ForDeopt(MacroAssembler* masm) {
1276 NamedLoadHandlerCompiler::GenerateLoadViaGetterForDeopt(masm);
1280 static void Generate_LoadIC_Slow(MacroAssembler* masm) {
1281 LoadIC::GenerateRuntimeGetProperty(masm);
1285 static void Generate_KeyedLoadIC_Initialize(MacroAssembler* masm) {
1286 KeyedLoadIC::GenerateInitialize(masm);
1290 static void Generate_KeyedLoadIC_Slow(MacroAssembler* masm) {
1291 KeyedLoadIC::GenerateRuntimeGetProperty(masm);
1295 static void Generate_KeyedLoadIC_Miss(MacroAssembler* masm) {
1296 KeyedLoadIC::GenerateMiss(masm);
1300 static void Generate_KeyedLoadIC_Megamorphic(MacroAssembler* masm) {
1301 KeyedLoadIC::GenerateMegamorphic(masm);
1305 static void Generate_StoreIC_Miss(MacroAssembler* masm) {
1306 StoreIC::GenerateMiss(masm);
1310 static void Generate_StoreIC_Normal(MacroAssembler* masm) {
1311 StoreIC::GenerateNormal(masm);
1315 static void Generate_StoreIC_Slow(MacroAssembler* masm) {
1316 NamedStoreHandlerCompiler::GenerateSlow(masm);
1320 static void Generate_KeyedStoreIC_Slow(MacroAssembler* masm) {
1321 ElementHandlerCompiler::GenerateStoreSlow(masm);
1325 static void Generate_StoreIC_Setter_ForDeopt(MacroAssembler* masm) {
1326 NamedStoreHandlerCompiler::GenerateStoreViaSetterForDeopt(masm);
1330 static void Generate_KeyedStoreIC_Megamorphic(MacroAssembler* masm) {
1331 KeyedStoreIC::GenerateMegamorphic(masm, SLOPPY);
1335 static void Generate_KeyedStoreIC_Megamorphic_Strict(MacroAssembler* masm) {
1336 KeyedStoreIC::GenerateMegamorphic(masm, STRICT);
1340 static void Generate_KeyedStoreIC_Miss(MacroAssembler* masm) {
1341 KeyedStoreIC::GenerateMiss(masm);
1345 static void Generate_KeyedStoreIC_Initialize(MacroAssembler* masm) {
1346 KeyedStoreIC::GenerateInitialize(masm);
1350 static void Generate_KeyedStoreIC_Initialize_Strict(MacroAssembler* masm) {
1351 KeyedStoreIC::GenerateInitialize(masm);
1355 static void Generate_KeyedStoreIC_PreMonomorphic(MacroAssembler* masm) {
1356 KeyedStoreIC::GeneratePreMonomorphic(masm);
1360 static void Generate_KeyedStoreIC_PreMonomorphic_Strict(MacroAssembler* masm) {
1361 KeyedStoreIC::GeneratePreMonomorphic(masm);
1365 static void Generate_CallICStub_DebugBreak(MacroAssembler* masm) {
1366 DebugCodegen::GenerateCallICStubDebugBreak(masm);
1370 static void Generate_LoadIC_DebugBreak(MacroAssembler* masm) {
1371 DebugCodegen::GenerateLoadICDebugBreak(masm);
1375 static void Generate_StoreIC_DebugBreak(MacroAssembler* masm) {
1376 DebugCodegen::GenerateStoreICDebugBreak(masm);
1380 static void Generate_KeyedLoadIC_DebugBreak(MacroAssembler* masm) {
1381 DebugCodegen::GenerateKeyedLoadICDebugBreak(masm);
1385 static void Generate_KeyedStoreIC_DebugBreak(MacroAssembler* masm) {
1386 DebugCodegen::GenerateKeyedStoreICDebugBreak(masm);
1390 static void Generate_CompareNilIC_DebugBreak(MacroAssembler* masm) {
1391 DebugCodegen::GenerateCompareNilICDebugBreak(masm);
1395 static void Generate_Return_DebugBreak(MacroAssembler* masm) {
1396 DebugCodegen::GenerateReturnDebugBreak(masm);
1400 static void Generate_CallFunctionStub_DebugBreak(MacroAssembler* masm) {
1401 DebugCodegen::GenerateCallFunctionStubDebugBreak(masm);
1405 static void Generate_CallConstructStub_DebugBreak(MacroAssembler* masm) {
1406 DebugCodegen::GenerateCallConstructStubDebugBreak(masm);
1410 static void Generate_CallConstructStub_Recording_DebugBreak(
1411 MacroAssembler* masm) {
1412 DebugCodegen::GenerateCallConstructStubRecordDebugBreak(masm);
1416 static void Generate_Slot_DebugBreak(MacroAssembler* masm) {
1417 DebugCodegen::GenerateSlotDebugBreak(masm);
1421 static void Generate_PlainReturn_LiveEdit(MacroAssembler* masm) {
1422 DebugCodegen::GeneratePlainReturnLiveEdit(masm);
1426 static void Generate_FrameDropper_LiveEdit(MacroAssembler* masm) {
1427 DebugCodegen::GenerateFrameDropperLiveEdit(masm);
1431 Builtins::Builtins() : initialized_(false) {
1432 memset(builtins_, 0, sizeof(builtins_[0]) * builtin_count);
1433 memset(names_, 0, sizeof(names_[0]) * builtin_count);
1437 Builtins::~Builtins() {
1441 #define DEF_ENUM_C(name, ignore) FUNCTION_ADDR(Builtin_##name),
1442 Address const Builtins::c_functions_[cfunction_count] = {
1443 BUILTIN_LIST_C(DEF_ENUM_C)
1447 #define DEF_JS_NAME(name, ignore) #name,
1448 #define DEF_JS_ARGC(ignore, argc) argc,
1449 const char* const Builtins::javascript_names_[id_count] = {
1450 BUILTINS_LIST_JS(DEF_JS_NAME)
1453 int const Builtins::javascript_argc_[id_count] = {
1454 BUILTINS_LIST_JS(DEF_JS_ARGC)
1459 struct BuiltinDesc {
1462 const char* s_name; // name is only used for generating log information.
1465 BuiltinExtraArguments extra_args;
1468 #define BUILTIN_FUNCTION_TABLE_INIT { V8_ONCE_INIT, {} }
1470 class BuiltinFunctionTable {
1472 BuiltinDesc* functions() {
1473 base::CallOnce(&once_, &Builtins::InitBuiltinFunctionTable);
1477 base::OnceType once_;
1478 BuiltinDesc functions_[Builtins::builtin_count + 1];
1480 friend class Builtins;
1483 static BuiltinFunctionTable builtin_function_table =
1484 BUILTIN_FUNCTION_TABLE_INIT;
1486 // Define array of pointers to generators and C builtin functions.
1487 // We do this in a sort of roundabout way so that we can do the initialization
1488 // within the lexical scope of Builtins:: and within a context where
1489 // Code::Flags names a non-abstract type.
1490 void Builtins::InitBuiltinFunctionTable() {
1491 BuiltinDesc* functions = builtin_function_table.functions_;
1492 functions[builtin_count].generator = NULL;
1493 functions[builtin_count].c_code = NULL;
1494 functions[builtin_count].s_name = NULL;
1495 functions[builtin_count].name = builtin_count;
1496 functions[builtin_count].flags = static_cast<Code::Flags>(0);
1497 functions[builtin_count].extra_args = NO_EXTRA_ARGUMENTS;
1499 #define DEF_FUNCTION_PTR_C(aname, aextra_args) \
1500 functions->generator = FUNCTION_ADDR(Generate_Adaptor); \
1501 functions->c_code = FUNCTION_ADDR(Builtin_##aname); \
1502 functions->s_name = #aname; \
1503 functions->name = c_##aname; \
1504 functions->flags = Code::ComputeFlags(Code::BUILTIN); \
1505 functions->extra_args = aextra_args; \
1508 #define DEF_FUNCTION_PTR_A(aname, kind, state, extra) \
1509 functions->generator = FUNCTION_ADDR(Generate_##aname); \
1510 functions->c_code = NULL; \
1511 functions->s_name = #aname; \
1512 functions->name = k##aname; \
1513 functions->flags = Code::ComputeFlags(Code::kind, \
1516 functions->extra_args = NO_EXTRA_ARGUMENTS; \
1519 #define DEF_FUNCTION_PTR_H(aname, kind) \
1520 functions->generator = FUNCTION_ADDR(Generate_##aname); \
1521 functions->c_code = NULL; \
1522 functions->s_name = #aname; \
1523 functions->name = k##aname; \
1524 functions->flags = Code::ComputeHandlerFlags(Code::kind); \
1525 functions->extra_args = NO_EXTRA_ARGUMENTS; \
1528 BUILTIN_LIST_C(DEF_FUNCTION_PTR_C)
1529 BUILTIN_LIST_A(DEF_FUNCTION_PTR_A)
1530 BUILTIN_LIST_H(DEF_FUNCTION_PTR_H)
1531 BUILTIN_LIST_DEBUG_A(DEF_FUNCTION_PTR_A)
1533 #undef DEF_FUNCTION_PTR_C
1534 #undef DEF_FUNCTION_PTR_A
1538 void Builtins::SetUp(Isolate* isolate, bool create_heap_objects) {
1539 DCHECK(!initialized_);
1541 // Create a scope for the handles in the builtins.
1542 HandleScope scope(isolate);
1544 const BuiltinDesc* functions = builtin_function_table.functions();
1546 // For now we generate builtin adaptor code into a stack-allocated
1547 // buffer, before copying it into individual code objects. Be careful
1548 // with alignment, some platforms don't like unaligned code.
1550 // We can generate a lot of debug code on Arm64.
1551 const size_t buffer_size = 32*KB;
1553 const size_t buffer_size = 8*KB;
1555 union { int force_alignment; byte buffer[buffer_size]; } u;
1557 // Traverse the list of builtins and generate an adaptor in a
1558 // separate code object for each one.
1559 for (int i = 0; i < builtin_count; i++) {
1560 if (create_heap_objects) {
1561 MacroAssembler masm(isolate, u.buffer, sizeof u.buffer);
1562 // Generate the code/adaptor.
1563 typedef void (*Generator)(MacroAssembler*, int, BuiltinExtraArguments);
1564 Generator g = FUNCTION_CAST<Generator>(functions[i].generator);
1565 // We pass all arguments to the generator, but it may not use all of
1566 // them. This works because the first arguments are on top of the
1568 DCHECK(!masm.has_frame());
1569 g(&masm, functions[i].name, functions[i].extra_args);
1570 // Move the code into the object heap.
1572 masm.GetCode(&desc);
1573 Code::Flags flags = functions[i].flags;
1575 isolate->factory()->NewCode(desc, flags, masm.CodeObject());
1576 // Log the event and add the code to the builtins array.
1578 CodeCreateEvent(Logger::BUILTIN_TAG, *code, functions[i].s_name));
1579 builtins_[i] = *code;
1580 code->set_builtin_index(i);
1581 #ifdef ENABLE_DISASSEMBLER
1582 if (FLAG_print_builtin_code) {
1583 CodeTracer::Scope trace_scope(isolate->GetCodeTracer());
1584 OFStream os(trace_scope.file());
1585 os << "Builtin: " << functions[i].s_name << "\n";
1586 code->Disassemble(functions[i].s_name, os);
1591 // Deserializing. The values will be filled in during IterateBuiltins.
1592 builtins_[i] = NULL;
1594 names_[i] = functions[i].s_name;
1597 // Mark as initialized.
1598 initialized_ = true;
1602 void Builtins::TearDown() {
1603 initialized_ = false;
1607 void Builtins::IterateBuiltins(ObjectVisitor* v) {
1608 v->VisitPointers(&builtins_[0], &builtins_[0] + builtin_count);
1612 const char* Builtins::Lookup(byte* pc) {
1613 // may be called during initialization (disassembler!)
1615 for (int i = 0; i < builtin_count; i++) {
1616 Code* entry = Code::cast(builtins_[i]);
1617 if (entry->contains(pc)) {
1626 void Builtins::Generate_InterruptCheck(MacroAssembler* masm) {
1627 masm->TailCallRuntime(Runtime::kInterrupt, 0, 1);
1631 void Builtins::Generate_StackCheck(MacroAssembler* masm) {
1632 masm->TailCallRuntime(Runtime::kStackGuard, 0, 1);
1636 #define DEFINE_BUILTIN_ACCESSOR_C(name, ignore) \
1637 Handle<Code> Builtins::name() { \
1638 Code** code_address = \
1639 reinterpret_cast<Code**>(builtin_address(k##name)); \
1640 return Handle<Code>(code_address); \
1642 #define DEFINE_BUILTIN_ACCESSOR_A(name, kind, state, extra) \
1643 Handle<Code> Builtins::name() { \
1644 Code** code_address = \
1645 reinterpret_cast<Code**>(builtin_address(k##name)); \
1646 return Handle<Code>(code_address); \
1648 #define DEFINE_BUILTIN_ACCESSOR_H(name, kind) \
1649 Handle<Code> Builtins::name() { \
1650 Code** code_address = \
1651 reinterpret_cast<Code**>(builtin_address(k##name)); \
1652 return Handle<Code>(code_address); \
1654 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C)
1655 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A)
1656 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H)
1657 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A)
1658 #undef DEFINE_BUILTIN_ACCESSOR_C
1659 #undef DEFINE_BUILTIN_ACCESSOR_A
1662 } // namespace internal