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.
5 #include "src/builtins.h"
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/cpu-profiler.h"
13 #include "src/elements.h"
14 #include "src/frames-inl.h"
15 #include "src/gdb-jit.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)
94 // ----------------------------------------------------------------------------
95 // Support macro for defining builtins in C++.
96 // ----------------------------------------------------------------------------
98 // A builtin function is defined by writing:
104 // In the body of the builtin function the arguments can be accessed
105 // through the BuiltinArguments object args.
109 #define BUILTIN(name) \
110 MUST_USE_RESULT static Object* Builtin_Impl_##name( \
111 name##ArgumentsType args, Isolate* isolate); \
112 MUST_USE_RESULT static Object* Builtin_##name( \
113 int args_length, Object** args_object, Isolate* isolate) { \
114 name##ArgumentsType args(args_length, args_object); \
116 return Builtin_Impl_##name(args, isolate); \
118 MUST_USE_RESULT static Object* Builtin_Impl_##name( \
119 name##ArgumentsType args, Isolate* isolate)
121 #else // For release mode.
123 #define BUILTIN(name) \
124 static Object* Builtin_impl##name( \
125 name##ArgumentsType args, Isolate* isolate); \
126 static Object* Builtin_##name( \
127 int args_length, Object** args_object, Isolate* isolate) { \
128 name##ArgumentsType args(args_length, args_object); \
129 return Builtin_impl##name(args, isolate); \
131 static Object* Builtin_impl##name( \
132 name##ArgumentsType args, Isolate* isolate)
137 inline bool CalledAsConstructor(Isolate* isolate) {
138 // Calculate the result using a full stack frame iterator and check
139 // that the state of the stack is as we assume it to be in the
141 StackFrameIterator it(isolate);
142 DCHECK(it.frame()->is_exit());
144 StackFrame* frame = it.frame();
145 bool reference_result = frame->is_construct();
146 Address fp = Isolate::c_entry_fp(isolate->thread_local_top());
147 // Because we know fp points to an exit frame we can use the relevant
148 // part of ExitFrame::ComputeCallerState directly.
149 const int kCallerOffset = ExitFrameConstants::kCallerFPOffset;
150 Address caller_fp = Memory::Address_at(fp + kCallerOffset);
151 // This inlines the part of StackFrame::ComputeType that grabs the
152 // type of the current frame. Note that StackFrame::ComputeType
153 // has been specialized for each architecture so if any one of them
154 // changes this code has to be changed as well.
155 const int kMarkerOffset = StandardFrameConstants::kMarkerOffset;
156 const Smi* kConstructMarker = Smi::FromInt(StackFrame::CONSTRUCT);
157 Object* marker = Memory::Object_at(caller_fp + kMarkerOffset);
158 bool result = (marker == kConstructMarker);
159 DCHECK_EQ(result, reference_result);
165 // ----------------------------------------------------------------------------
168 inline bool ClampedToInteger(Object* object, int* out) {
169 // This is an extended version of ECMA-262 7.1.11 handling signed values
170 // Try to convert object to a number and clamp values to [kMinInt, kMaxInt]
171 if (object->IsSmi()) {
172 *out = Smi::cast(object)->value();
174 } else if (object->IsHeapNumber()) {
175 double value = HeapNumber::cast(object)->value();
176 if (std::isnan(value)) {
178 } else if (value > kMaxInt) {
180 } else if (value < kMinInt) {
183 *out = static_cast<int>(value);
186 } else if (object->IsUndefined() || object->IsNull()) {
189 } else if (object->IsBoolean()) {
190 *out = object->IsTrue();
197 void MoveDoubleElements(FixedDoubleArray* dst, int dst_index,
198 FixedDoubleArray* src, int src_index, int len) {
199 if (len == 0) return;
200 MemMove(dst->data_start() + dst_index, src->data_start() + src_index,
205 inline bool GetSloppyArgumentsLength(Isolate* isolate, Handle<JSObject> object,
208 isolate->context()->native_context()->sloppy_arguments_map();
209 if (object->map() != arguments_map || !object->HasFastElements()) {
212 Object* len_obj = object->InObjectPropertyAt(Heap::kArgumentsLengthIndex);
213 if (!len_obj->IsSmi()) {
216 *out = Smi::cast(len_obj)->value();
217 return *out <= object->elements()->length();
221 bool PrototypeHasNoElements(PrototypeIterator* iter) {
222 DisallowHeapAllocation no_gc;
223 for (; !iter->IsAtEnd(); iter->Advance()) {
224 if (iter->GetCurrent()->IsJSProxy()) return false;
225 JSObject* current = JSObject::cast(iter->GetCurrent());
226 if (current->IsAccessCheckNeeded()) return false;
227 if (current->HasIndexedInterceptor()) return false;
228 if (current->elements()->length() != 0) return false;
234 inline bool IsJSArrayFastElementMovingAllowed(Isolate* isolate,
236 DisallowHeapAllocation no_gc;
237 // If the array prototype chain is intact (and free of elements), and if the
238 // receiver's prototype is the array prototype, then we are done.
239 Object* prototype = receiver->map()->prototype();
240 if (prototype->IsJSArray() &&
241 isolate->is_initial_array_prototype(JSArray::cast(prototype)) &&
242 isolate->IsFastArrayConstructorPrototypeChainIntact()) {
247 PrototypeIterator iter(isolate, receiver);
248 return PrototypeHasNoElements(&iter);
252 // Returns empty handle if not applicable.
254 inline MaybeHandle<FixedArrayBase> EnsureJSArrayWithWritableFastElements(
255 Isolate* isolate, Handle<Object> receiver, Arguments* args,
256 int first_added_arg) {
257 if (!receiver->IsJSArray()) return MaybeHandle<FixedArrayBase>();
258 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
259 // If there may be elements accessors in the prototype chain, the fast path
260 // cannot be used if there arguments to add to the array.
261 Heap* heap = isolate->heap();
262 if (args != NULL && !IsJSArrayFastElementMovingAllowed(isolate, *array)) {
263 return MaybeHandle<FixedArrayBase>();
265 if (array->map()->is_observed()) return MaybeHandle<FixedArrayBase>();
266 if (!array->map()->is_extensible()) return MaybeHandle<FixedArrayBase>();
267 Handle<FixedArrayBase> elms(array->elements(), isolate);
268 Map* map = elms->map();
269 if (map == heap->fixed_array_map()) {
270 if (args == NULL || array->HasFastObjectElements()) return elms;
271 } else if (map == heap->fixed_cow_array_map()) {
272 elms = JSObject::EnsureWritableFastElements(array);
273 if (args == NULL || array->HasFastObjectElements()) return elms;
274 } else if (map == heap->fixed_double_array_map()) {
275 if (args == NULL) return elms;
277 return MaybeHandle<FixedArrayBase>();
280 // Adding elements to the array prototype would break code that makes sure
281 // it has no elements. Handle that elsewhere.
282 if (isolate->IsAnyInitialArrayPrototype(array)) {
283 return MaybeHandle<FixedArrayBase>();
286 // Need to ensure that the arguments passed in args can be contained in
288 int args_length = args->length();
289 if (first_added_arg >= args_length) return handle(array->elements(), isolate);
291 ElementsKind origin_kind = array->map()->elements_kind();
292 DCHECK(!IsFastObjectElementsKind(origin_kind));
293 ElementsKind target_kind = origin_kind;
295 DisallowHeapAllocation no_gc;
296 int arg_count = args_length - first_added_arg;
297 Object** arguments = args->arguments() - first_added_arg - (arg_count - 1);
298 for (int i = 0; i < arg_count; i++) {
299 Object* arg = arguments[i];
300 if (arg->IsHeapObject()) {
301 if (arg->IsHeapNumber()) {
302 target_kind = FAST_DOUBLE_ELEMENTS;
304 target_kind = FAST_ELEMENTS;
310 if (target_kind != origin_kind) {
311 JSObject::TransitionElementsKind(array, target_kind);
312 return handle(array->elements(), isolate);
318 MUST_USE_RESULT static Object* CallJsIntrinsic(
319 Isolate* isolate, Handle<JSFunction> function,
320 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
321 HandleScope handleScope(isolate);
322 int argc = args.length() - 1;
323 ScopedVector<Handle<Object> > argv(argc);
324 for (int i = 0; i < argc; ++i) {
325 argv[i] = args.at<Object>(i + 1);
327 Handle<Object> result;
328 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
330 Execution::Call(isolate,
344 return isolate->heap()->undefined_value(); // Make compiler happy.
348 BUILTIN(EmptyFunction) { return isolate->heap()->undefined_value(); }
352 HandleScope scope(isolate);
353 Handle<Object> receiver = args.receiver();
354 MaybeHandle<FixedArrayBase> maybe_elms_obj =
355 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1);
356 Handle<FixedArrayBase> elms_obj;
357 if (!maybe_elms_obj.ToHandle(&elms_obj)) {
358 return CallJsIntrinsic(isolate, isolate->array_push(), args);
360 // Fast Elements Path
361 int push_size = args.length() - 1;
362 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
363 int len = Smi::cast(array->length())->value();
364 if (push_size == 0) {
365 return Smi::FromInt(len);
368 JSArray::WouldChangeReadOnlyLength(array, len + push_size)) {
369 return CallJsIntrinsic(isolate, isolate->array_push(), args);
371 DCHECK(!array->map()->is_observed());
372 ElementsAccessor* accessor = array->GetElementsAccessor();
373 int new_length = accessor->Push(array, elms_obj, &args[1], push_size,
374 ElementsAccessor::kDirectionReverse);
375 return Smi::FromInt(new_length);
380 HandleScope scope(isolate);
381 Handle<Object> receiver = args.receiver();
382 MaybeHandle<FixedArrayBase> maybe_elms_obj =
383 EnsureJSArrayWithWritableFastElements(isolate, receiver, NULL, 0);
384 Handle<FixedArrayBase> elms_obj;
385 if (!maybe_elms_obj.ToHandle(&elms_obj)) {
386 return CallJsIntrinsic(isolate, isolate->array_pop(), args);
389 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
390 DCHECK(!array->map()->is_observed());
392 uint32_t len = static_cast<uint32_t>(Smi::cast(array->length())->value());
393 if (len == 0) return isolate->heap()->undefined_value();
395 if (JSArray::HasReadOnlyLength(array)) {
396 return CallJsIntrinsic(isolate, isolate->array_pop(), args);
399 uint32_t new_length = len - 1;
400 Handle<Object> element;
401 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
402 isolate, element, Object::GetElement(isolate, array, new_length));
404 JSArray::SetLength(array, new_length);
409 BUILTIN(ArrayShift) {
410 HandleScope scope(isolate);
411 Heap* heap = isolate->heap();
412 Handle<Object> receiver = args.receiver();
413 MaybeHandle<FixedArrayBase> maybe_elms_obj =
414 EnsureJSArrayWithWritableFastElements(isolate, receiver, NULL, 0);
415 Handle<FixedArrayBase> elms_obj;
416 if (!maybe_elms_obj.ToHandle(&elms_obj) ||
417 !IsJSArrayFastElementMovingAllowed(isolate, JSArray::cast(*receiver))) {
418 return CallJsIntrinsic(isolate, isolate->array_shift(), args);
420 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
421 DCHECK(!array->map()->is_observed());
423 int len = Smi::cast(array->length())->value();
424 if (len == 0) return heap->undefined_value();
426 if (JSArray::HasReadOnlyLength(array)) {
427 return CallJsIntrinsic(isolate, isolate->array_shift(), args);
431 Handle<Object> first;
432 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, first,
433 Object::GetElement(isolate, array, 0));
435 if (heap->CanMoveObjectStart(*elms_obj)) {
436 array->set_elements(heap->LeftTrimFixedArray(*elms_obj, 1));
438 // Shift the elements.
439 if (elms_obj->IsFixedArray()) {
440 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
441 DisallowHeapAllocation no_gc;
442 heap->MoveElements(*elms, 0, 1, len - 1);
443 elms->set(len - 1, heap->the_hole_value());
445 Handle<FixedDoubleArray> elms = Handle<FixedDoubleArray>::cast(elms_obj);
446 MoveDoubleElements(*elms, 0, *elms, 1, len - 1);
447 elms->set_the_hole(len - 1);
452 array->set_length(Smi::FromInt(len - 1));
458 BUILTIN(ArrayUnshift) {
459 HandleScope scope(isolate);
460 Handle<Object> receiver = args.receiver();
461 MaybeHandle<FixedArrayBase> maybe_elms_obj =
462 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1);
463 Handle<FixedArrayBase> elms_obj;
464 if (!maybe_elms_obj.ToHandle(&elms_obj)) {
465 return CallJsIntrinsic(isolate, isolate->array_unshift(), args);
467 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
468 DCHECK(!array->map()->is_observed());
469 if (!array->HasFastSmiOrObjectElements()) {
470 return CallJsIntrinsic(isolate, isolate->array_unshift(), args);
472 int len = Smi::cast(array->length())->value();
473 int to_add = args.length() - 1;
474 int new_length = len + to_add;
475 // Currently fixed arrays cannot grow too big, so
476 // we should never hit this case.
477 DCHECK(to_add <= (Smi::kMaxValue - len));
479 if (to_add > 0 && JSArray::WouldChangeReadOnlyLength(array, len + to_add)) {
480 return CallJsIntrinsic(isolate, isolate->array_unshift(), args);
483 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
485 if (new_length > elms->length()) {
486 // New backing storage is needed.
487 int capacity = new_length + (new_length >> 1) + 16;
488 Handle<FixedArray> new_elms =
489 isolate->factory()->NewUninitializedFixedArray(capacity);
491 ElementsKind kind = array->GetElementsKind();
492 ElementsAccessor* accessor = array->GetElementsAccessor();
493 accessor->CopyElements(
494 elms, 0, kind, new_elms, to_add,
495 ElementsAccessor::kCopyToEndAndInitializeToHole);
498 array->set_elements(*elms);
500 DisallowHeapAllocation no_gc;
501 Heap* heap = isolate->heap();
502 heap->MoveElements(*elms, to_add, 0, len);
505 // Add the provided values.
506 DisallowHeapAllocation no_gc;
507 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
508 for (int i = 0; i < to_add; i++) {
509 elms->set(i, args[i + 1], mode);
513 array->set_length(Smi::FromInt(new_length));
514 return Smi::FromInt(new_length);
518 BUILTIN(ArraySlice) {
519 HandleScope scope(isolate);
520 Handle<Object> receiver = args.receiver();
521 Handle<JSObject> object;
522 Handle<FixedArrayBase> elms_obj;
524 int relative_start = 0;
525 int relative_end = 0;
526 bool is_sloppy_arguments = false;
528 if (receiver->IsJSArray()) {
529 DisallowHeapAllocation no_gc;
530 JSArray* array = JSArray::cast(*receiver);
531 if (!array->HasFastElements() ||
532 !IsJSArrayFastElementMovingAllowed(isolate, array)) {
533 AllowHeapAllocation allow_allocation;
534 return CallJsIntrinsic(isolate, isolate->array_slice(), args);
536 len = Smi::cast(array->length())->value();
537 object = Handle<JSObject>::cast(receiver);
538 elms_obj = handle(array->elements(), isolate);
539 } else if (receiver->IsJSObject() &&
540 GetSloppyArgumentsLength(isolate, Handle<JSObject>::cast(receiver),
542 // Array.prototype.slice(arguments, ...) is quite a common idiom
543 // (notably more than 50% of invocations in Web apps).
544 // Treat it in C++ as well.
545 is_sloppy_arguments = true;
546 object = Handle<JSObject>::cast(receiver);
547 elms_obj = handle(object->elements(), isolate);
549 AllowHeapAllocation allow_allocation;
550 return CallJsIntrinsic(isolate, isolate->array_slice(), args);
553 int argument_count = args.length() - 1;
554 // Note carefully chosen defaults---if argument is missing,
555 // it's undefined which gets converted to 0 for relative_start
556 // and to len for relative_end.
559 if (argument_count > 0) {
560 DisallowHeapAllocation no_gc;
561 if (!ClampedToInteger(args[1], &relative_start)) {
562 AllowHeapAllocation allow_allocation;
563 return CallJsIntrinsic(isolate, isolate->array_slice(), args);
565 if (argument_count > 1) {
566 Object* end_arg = args[2];
567 // slice handles the end_arg specially
568 if (end_arg->IsUndefined()) {
570 } else if (!ClampedToInteger(end_arg, &relative_end)) {
571 AllowHeapAllocation allow_allocation;
572 return CallJsIntrinsic(isolate, isolate->array_slice(), args);
577 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6.
578 uint32_t actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
579 : Min(relative_start, len);
581 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8.
582 uint32_t actual_end =
583 (relative_end < 0) ? Max(len + relative_end, 0) : Min(relative_end, len);
585 ElementsAccessor* accessor = object->GetElementsAccessor();
586 if (is_sloppy_arguments &&
587 !accessor->IsPacked(object, elms_obj, actual_start, actual_end)) {
588 // Don't deal with arguments with holes in C++
589 AllowHeapAllocation allow_allocation;
590 return CallJsIntrinsic(isolate, isolate->array_slice(), args);
592 Handle<JSArray> result_array =
593 accessor->Slice(object, elms_obj, actual_start, actual_end);
594 return *result_array;
598 BUILTIN(ArraySplice) {
599 HandleScope scope(isolate);
600 Handle<Object> receiver = args.receiver();
601 MaybeHandle<FixedArrayBase> maybe_elms_obj =
602 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3);
603 Handle<FixedArrayBase> elms_obj;
604 if (!maybe_elms_obj.ToHandle(&elms_obj)) {
605 return CallJsIntrinsic(isolate, isolate->array_splice(), args);
607 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
608 DCHECK(!array->map()->is_observed());
610 int argument_count = args.length() - 1;
611 int relative_start = 0;
612 if (argument_count > 0) {
613 DisallowHeapAllocation no_gc;
614 if (!ClampedToInteger(args[1], &relative_start)) {
615 AllowHeapAllocation allow_allocation;
616 return CallJsIntrinsic(isolate, isolate->array_splice(), args);
619 int len = Smi::cast(array->length())->value();
620 // clip relative start to [0, len]
621 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
622 : Min(relative_start, len);
624 int actual_delete_count;
625 if (argument_count == 1) {
626 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
627 // given as a request to delete all the elements from the start.
628 // And it differs from the case of undefined delete count.
629 // This does not follow ECMA-262, but we do the same for compatibility.
630 DCHECK(len - actual_start >= 0);
631 actual_delete_count = len - actual_start;
633 int delete_count = 0;
634 DisallowHeapAllocation no_gc;
635 if (argument_count > 1) {
636 if (!ClampedToInteger(args[2], &delete_count)) {
637 AllowHeapAllocation allow_allocation;
638 return CallJsIntrinsic(isolate, isolate->array_splice(), args);
641 actual_delete_count = Min(Max(delete_count, 0), len - actual_start);
644 int add_count = (argument_count > 1) ? (argument_count - 2) : 0;
645 int new_length = len - actual_delete_count + add_count;
647 if (new_length != len && JSArray::HasReadOnlyLength(array)) {
648 AllowHeapAllocation allow_allocation;
649 return CallJsIntrinsic(isolate, isolate->array_splice(), args);
651 ElementsAccessor* accessor = array->GetElementsAccessor();
652 Handle<JSArray> result_array = accessor->Splice(
653 array, elms_obj, actual_start, actual_delete_count, args, add_count);
654 return *result_array;
658 BUILTIN(ArrayConcat) {
659 HandleScope scope(isolate);
661 int n_arguments = args.length();
663 ElementsKind elements_kind = GetInitialFastElementsKind();
664 bool has_double = false;
666 DisallowHeapAllocation no_gc;
667 Context* native_context = isolate->context()->native_context();
668 Object* array_proto = native_context->array_function()->prototype();
669 PrototypeIterator iter(isolate, array_proto,
670 PrototypeIterator::START_AT_RECEIVER);
671 if (!PrototypeHasNoElements(&iter)) {
672 AllowHeapAllocation allow_allocation;
673 return CallJsIntrinsic(isolate, isolate->array_concat(), args);
676 // Iterate through all the arguments performing checks
677 // and calculating total length.
678 bool is_holey = false;
679 for (int i = 0; i < n_arguments; i++) {
680 Object* arg = args[i];
681 PrototypeIterator iter(isolate, arg);
682 if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastElements() ||
683 iter.GetCurrent() != array_proto) {
684 AllowHeapAllocation allow_allocation;
685 return CallJsIntrinsic(isolate, isolate->array_concat(), args);
687 int len = Smi::cast(JSArray::cast(arg)->length())->value();
689 // We shouldn't overflow when adding another len.
690 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
691 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt);
694 DCHECK(result_len >= 0);
696 if (result_len > FixedDoubleArray::kMaxLength) {
697 AllowHeapAllocation allow_allocation;
698 return CallJsIntrinsic(isolate, isolate->array_concat(), args);
701 ElementsKind arg_kind = JSArray::cast(arg)->map()->elements_kind();
702 has_double = has_double || IsFastDoubleElementsKind(arg_kind);
703 is_holey = is_holey || IsFastHoleyElementsKind(arg_kind);
704 if (IsMoreGeneralElementsKindTransition(elements_kind, arg_kind)) {
705 elements_kind = arg_kind;
708 if (is_holey) elements_kind = GetHoleyElementsKind(elements_kind);
711 // If a double array is concatted into a fast elements array, the fast
712 // elements array needs to be initialized to contain proper holes, since
713 // boxing doubles may cause incremental marking.
714 ArrayStorageAllocationMode mode =
715 has_double && IsFastObjectElementsKind(elements_kind)
716 ? INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE : DONT_INITIALIZE_ARRAY_ELEMENTS;
717 Handle<JSArray> result_array = isolate->factory()->NewJSArray(
718 elements_kind, result_len, result_len, Strength::WEAK, mode);
719 if (result_len == 0) return *result_array;
722 Handle<FixedArrayBase> storage(result_array->elements(), isolate);
723 ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind);
724 for (int i = 0; i < n_arguments; i++) {
725 // It is crucial to keep |array| in a raw pointer form to avoid performance
727 JSArray* array = JSArray::cast(args[i]);
728 int len = Smi::cast(array->length())->value();
730 ElementsKind from_kind = array->GetElementsKind();
731 accessor->CopyElements(array, 0, from_kind, storage, j, len);
736 DCHECK(j == result_len);
738 return *result_array;
742 // -----------------------------------------------------------------------------
743 // Throwers for restricted function properties and strict arguments object
747 BUILTIN(RestrictedFunctionPropertiesThrower) {
748 HandleScope scope(isolate);
749 THROW_NEW_ERROR_RETURN_FAILURE(
750 isolate, NewTypeError(MessageTemplate::kRestrictedFunctionProperties));
754 BUILTIN(RestrictedStrictArgumentsPropertiesThrower) {
755 HandleScope scope(isolate);
756 THROW_NEW_ERROR_RETURN_FAILURE(
757 isolate, NewTypeError(MessageTemplate::kStrictPoisonPill));
761 // -----------------------------------------------------------------------------
765 template <bool is_construct>
766 MUST_USE_RESULT static MaybeHandle<Object> HandleApiCallHelper(
767 Isolate* isolate, BuiltinArguments<NEEDS_CALLED_FUNCTION>& args) {
768 HandleScope scope(isolate);
769 Handle<JSFunction> function = args.called_function();
770 // TODO(ishell): turn this back to a DCHECK.
771 CHECK(function->shared()->IsApiFunction());
773 Handle<FunctionTemplateInfo> fun_data(
774 function->shared()->get_api_func_data(), isolate);
776 ASSIGN_RETURN_ON_EXCEPTION(
778 ApiNatives::ConfigureInstance(isolate, fun_data,
779 Handle<JSObject>::cast(args.receiver())),
783 DCHECK(!args[0]->IsNull());
784 if (args[0]->IsUndefined()) args[0] = function->global_proxy();
786 if (!is_construct && !fun_data->accept_any_receiver()) {
787 Handle<Object> receiver(&args[0]);
788 if (receiver->IsJSObject() && receiver->IsAccessCheckNeeded()) {
789 Handle<JSObject> js_receiver = Handle<JSObject>::cast(receiver);
790 if (!isolate->MayAccess(js_receiver)) {
791 isolate->ReportFailedAccessCheck(js_receiver);
792 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
797 Object* raw_holder = fun_data->GetCompatibleReceiver(isolate, args[0]);
799 if (raw_holder->IsNull()) {
800 // This function cannot be called with the given receiver. Abort!
801 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIllegalInvocation),
805 Object* raw_call_data = fun_data->call_code();
806 if (!raw_call_data->IsUndefined()) {
807 // TODO(ishell): remove this debugging code.
808 CHECK(raw_call_data->IsCallHandlerInfo());
809 CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
810 Object* callback_obj = call_data->callback();
811 v8::FunctionCallback callback =
812 v8::ToCData<v8::FunctionCallback>(callback_obj);
813 Object* data_obj = call_data->data();
815 LOG(isolate, ApiObjectAccess("call", JSObject::cast(*args.receiver())));
816 DCHECK(raw_holder->IsJSObject());
818 FunctionCallbackArguments custom(isolate,
826 v8::Local<v8::Value> value = custom.Call(callback);
827 Handle<Object> result;
828 if (value.IsEmpty()) {
829 result = isolate->factory()->undefined_value();
831 result = v8::Utils::OpenHandle(*value);
832 result->VerifyApiCallResultType();
835 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
836 if (!is_construct || result->IsJSObject()) {
837 return scope.CloseAndEscape(result);
841 return scope.CloseAndEscape(args.receiver());
845 BUILTIN(HandleApiCall) {
846 HandleScope scope(isolate);
847 DCHECK(!CalledAsConstructor(isolate));
848 Handle<Object> result;
849 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
850 HandleApiCallHelper<false>(isolate, args));
855 BUILTIN(HandleApiCallConstruct) {
856 HandleScope scope(isolate);
857 DCHECK(CalledAsConstructor(isolate));
858 Handle<Object> result;
859 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
860 HandleApiCallHelper<true>(isolate, args));
867 class RelocatableArguments : public BuiltinArguments<NEEDS_CALLED_FUNCTION>,
870 RelocatableArguments(Isolate* isolate, int length, Object** arguments)
871 : BuiltinArguments<NEEDS_CALLED_FUNCTION>(length, arguments),
872 Relocatable(isolate) {}
874 virtual inline void IterateInstance(ObjectVisitor* v) {
875 if (length() == 0) return;
876 v->VisitPointers(lowest_address(), highest_address() + 1);
880 DISALLOW_COPY_AND_ASSIGN(RelocatableArguments);
886 MaybeHandle<Object> Builtins::InvokeApiFunction(Handle<JSFunction> function,
887 Handle<Object> receiver,
889 Handle<Object> args[]) {
890 // Construct BuiltinArguments object: function, arguments reversed, receiver.
891 const int kBufferSize = 32;
892 Object* small_argv[kBufferSize];
894 if (argc + 2 <= kBufferSize) {
897 argv = new Object* [argc + 2];
899 argv[argc + 1] = *receiver;
900 for (int i = 0; i < argc; ++i) {
901 argv[argc - i] = *args[i];
904 MaybeHandle<Object> result;
906 auto isolate = function->GetIsolate();
907 RelocatableArguments arguments(isolate, argc + 2, &argv[argc + 1]);
908 result = HandleApiCallHelper<false>(isolate, arguments);
910 if (argv != small_argv) {
917 // Helper function to handle calls to non-function objects created through the
918 // API. The object can be called as either a constructor (using new) or just as
919 // a function (without new).
920 MUST_USE_RESULT static Object* HandleApiCallAsFunctionOrConstructor(
922 bool is_construct_call,
923 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
924 // Non-functions are never called as constructors. Even if this is an object
925 // called as a constructor the delegate call is not a construct call.
926 DCHECK(!CalledAsConstructor(isolate));
927 Heap* heap = isolate->heap();
929 Handle<Object> receiver = args.receiver();
931 // Get the object called.
932 JSObject* obj = JSObject::cast(*receiver);
934 // Get the invocation callback from the function descriptor that was
935 // used to create the called object.
936 DCHECK(obj->map()->has_instance_call_handler());
937 JSFunction* constructor = JSFunction::cast(obj->map()->GetConstructor());
938 // TODO(ishell): turn this back to a DCHECK.
939 CHECK(constructor->shared()->IsApiFunction());
941 constructor->shared()->get_api_func_data()->instance_call_handler();
942 DCHECK(!handler->IsUndefined());
943 // TODO(ishell): remove this debugging code.
944 CHECK(handler->IsCallHandlerInfo());
945 CallHandlerInfo* call_data = CallHandlerInfo::cast(handler);
946 Object* callback_obj = call_data->callback();
947 v8::FunctionCallback callback =
948 v8::ToCData<v8::FunctionCallback>(callback_obj);
950 // Get the data for the call and perform the callback.
953 HandleScope scope(isolate);
954 LOG(isolate, ApiObjectAccess("call non-function", obj));
956 FunctionCallbackArguments custom(isolate,
963 v8::Local<v8::Value> value = custom.Call(callback);
964 if (value.IsEmpty()) {
965 result = heap->undefined_value();
967 result = *reinterpret_cast<Object**>(*value);
968 result->VerifyApiCallResultType();
971 // Check for exceptions and return result.
972 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
977 // Handle calls to non-function objects created through the API. This delegate
978 // function is used when the call is a normal function call.
979 BUILTIN(HandleApiCallAsFunction) {
980 return HandleApiCallAsFunctionOrConstructor(isolate, false, args);
984 // Handle calls to non-function objects created through the API. This delegate
985 // function is used when the call is a construct call.
986 BUILTIN(HandleApiCallAsConstructor) {
987 return HandleApiCallAsFunctionOrConstructor(isolate, true, args);
991 static void Generate_LoadIC_Miss(MacroAssembler* masm) {
992 LoadIC::GenerateMiss(masm);
996 static void Generate_LoadIC_Normal(MacroAssembler* masm) {
997 LoadIC::GenerateNormal(masm, SLOPPY);
1001 static void Generate_LoadIC_Normal_Strong(MacroAssembler* masm) {
1002 LoadIC::GenerateNormal(masm, STRONG);
1006 static void Generate_LoadIC_Getter_ForDeopt(MacroAssembler* masm) {
1007 NamedLoadHandlerCompiler::GenerateLoadViaGetterForDeopt(masm);
1011 static void Generate_LoadIC_Slow(MacroAssembler* masm) {
1012 LoadIC::GenerateRuntimeGetProperty(masm, SLOPPY);
1016 static void Generate_LoadIC_Slow_Strong(MacroAssembler* masm) {
1017 LoadIC::GenerateRuntimeGetProperty(masm, STRONG);
1021 static void Generate_KeyedLoadIC_Slow(MacroAssembler* masm) {
1022 KeyedLoadIC::GenerateRuntimeGetProperty(masm, SLOPPY);
1026 static void Generate_KeyedLoadIC_Slow_Strong(MacroAssembler* masm) {
1027 KeyedLoadIC::GenerateRuntimeGetProperty(masm, STRONG);
1031 static void Generate_KeyedLoadIC_Miss(MacroAssembler* masm) {
1032 KeyedLoadIC::GenerateMiss(masm);
1036 static void Generate_KeyedLoadIC_Megamorphic(MacroAssembler* masm) {
1037 KeyedLoadIC::GenerateMegamorphic(masm, SLOPPY);
1041 static void Generate_KeyedLoadIC_Megamorphic_Strong(MacroAssembler* masm) {
1042 KeyedLoadIC::GenerateMegamorphic(masm, STRONG);
1046 static void Generate_StoreIC_Miss(MacroAssembler* masm) {
1047 StoreIC::GenerateMiss(masm);
1051 static void Generate_StoreIC_Normal(MacroAssembler* masm) {
1052 StoreIC::GenerateNormal(masm);
1056 static void Generate_StoreIC_Slow(MacroAssembler* masm) {
1057 NamedStoreHandlerCompiler::GenerateSlow(masm);
1061 static void Generate_KeyedStoreIC_Slow(MacroAssembler* masm) {
1062 ElementHandlerCompiler::GenerateStoreSlow(masm);
1066 static void Generate_StoreIC_Setter_ForDeopt(MacroAssembler* masm) {
1067 NamedStoreHandlerCompiler::GenerateStoreViaSetterForDeopt(masm);
1071 static void Generate_KeyedStoreIC_Megamorphic(MacroAssembler* masm) {
1072 KeyedStoreIC::GenerateMegamorphic(masm, SLOPPY);
1076 static void Generate_KeyedStoreIC_Megamorphic_Strict(MacroAssembler* masm) {
1077 KeyedStoreIC::GenerateMegamorphic(masm, STRICT);
1081 static void Generate_KeyedStoreIC_Miss(MacroAssembler* masm) {
1082 KeyedStoreIC::GenerateMiss(masm);
1086 static void Generate_KeyedStoreIC_Initialize(MacroAssembler* masm) {
1087 KeyedStoreIC::GenerateInitialize(masm);
1091 static void Generate_KeyedStoreIC_Initialize_Strict(MacroAssembler* masm) {
1092 KeyedStoreIC::GenerateInitialize(masm);
1096 static void Generate_KeyedStoreIC_PreMonomorphic(MacroAssembler* masm) {
1097 KeyedStoreIC::GeneratePreMonomorphic(masm);
1101 static void Generate_KeyedStoreIC_PreMonomorphic_Strict(MacroAssembler* masm) {
1102 KeyedStoreIC::GeneratePreMonomorphic(masm);
1106 static void Generate_Return_DebugBreak(MacroAssembler* masm) {
1107 DebugCodegen::GenerateDebugBreakStub(masm,
1108 DebugCodegen::SAVE_RESULT_REGISTER);
1112 static void Generate_Slot_DebugBreak(MacroAssembler* masm) {
1113 DebugCodegen::GenerateDebugBreakStub(masm,
1114 DebugCodegen::IGNORE_RESULT_REGISTER);
1118 static void Generate_PlainReturn_LiveEdit(MacroAssembler* masm) {
1119 DebugCodegen::GeneratePlainReturnLiveEdit(masm);
1123 static void Generate_FrameDropper_LiveEdit(MacroAssembler* masm) {
1124 DebugCodegen::GenerateFrameDropperLiveEdit(masm);
1128 Builtins::Builtins() : initialized_(false) {
1129 memset(builtins_, 0, sizeof(builtins_[0]) * builtin_count);
1130 memset(names_, 0, sizeof(names_[0]) * builtin_count);
1134 Builtins::~Builtins() {
1138 #define DEF_ENUM_C(name, ignore) FUNCTION_ADDR(Builtin_##name),
1139 Address const Builtins::c_functions_[cfunction_count] = {
1140 BUILTIN_LIST_C(DEF_ENUM_C)
1145 struct BuiltinDesc {
1148 const char* s_name; // name is only used for generating log information.
1151 BuiltinExtraArguments extra_args;
1154 #define BUILTIN_FUNCTION_TABLE_INIT { V8_ONCE_INIT, {} }
1156 class BuiltinFunctionTable {
1158 BuiltinDesc* functions() {
1159 base::CallOnce(&once_, &Builtins::InitBuiltinFunctionTable);
1163 base::OnceType once_;
1164 BuiltinDesc functions_[Builtins::builtin_count + 1];
1166 friend class Builtins;
1169 static BuiltinFunctionTable builtin_function_table =
1170 BUILTIN_FUNCTION_TABLE_INIT;
1172 // Define array of pointers to generators and C builtin functions.
1173 // We do this in a sort of roundabout way so that we can do the initialization
1174 // within the lexical scope of Builtins:: and within a context where
1175 // Code::Flags names a non-abstract type.
1176 void Builtins::InitBuiltinFunctionTable() {
1177 BuiltinDesc* functions = builtin_function_table.functions_;
1178 functions[builtin_count].generator = NULL;
1179 functions[builtin_count].c_code = NULL;
1180 functions[builtin_count].s_name = NULL;
1181 functions[builtin_count].name = builtin_count;
1182 functions[builtin_count].flags = static_cast<Code::Flags>(0);
1183 functions[builtin_count].extra_args = NO_EXTRA_ARGUMENTS;
1185 #define DEF_FUNCTION_PTR_C(aname, aextra_args) \
1186 functions->generator = FUNCTION_ADDR(Generate_Adaptor); \
1187 functions->c_code = FUNCTION_ADDR(Builtin_##aname); \
1188 functions->s_name = #aname; \
1189 functions->name = c_##aname; \
1190 functions->flags = Code::ComputeFlags(Code::BUILTIN); \
1191 functions->extra_args = aextra_args; \
1194 #define DEF_FUNCTION_PTR_A(aname, kind, state, extra) \
1195 functions->generator = FUNCTION_ADDR(Generate_##aname); \
1196 functions->c_code = NULL; \
1197 functions->s_name = #aname; \
1198 functions->name = k##aname; \
1199 functions->flags = Code::ComputeFlags(Code::kind, \
1202 functions->extra_args = NO_EXTRA_ARGUMENTS; \
1205 #define DEF_FUNCTION_PTR_H(aname, kind) \
1206 functions->generator = FUNCTION_ADDR(Generate_##aname); \
1207 functions->c_code = NULL; \
1208 functions->s_name = #aname; \
1209 functions->name = k##aname; \
1210 functions->flags = Code::ComputeHandlerFlags(Code::kind); \
1211 functions->extra_args = NO_EXTRA_ARGUMENTS; \
1214 BUILTIN_LIST_C(DEF_FUNCTION_PTR_C)
1215 BUILTIN_LIST_A(DEF_FUNCTION_PTR_A)
1216 BUILTIN_LIST_H(DEF_FUNCTION_PTR_H)
1217 BUILTIN_LIST_DEBUG_A(DEF_FUNCTION_PTR_A)
1219 #undef DEF_FUNCTION_PTR_C
1220 #undef DEF_FUNCTION_PTR_A
1224 void Builtins::SetUp(Isolate* isolate, bool create_heap_objects) {
1225 DCHECK(!initialized_);
1227 // Create a scope for the handles in the builtins.
1228 HandleScope scope(isolate);
1230 const BuiltinDesc* functions = builtin_function_table.functions();
1232 // For now we generate builtin adaptor code into a stack-allocated
1233 // buffer, before copying it into individual code objects. Be careful
1234 // with alignment, some platforms don't like unaligned code.
1236 // We can generate a lot of debug code on Arm64.
1237 const size_t buffer_size = 32*KB;
1239 const size_t buffer_size = 8*KB;
1241 union { int force_alignment; byte buffer[buffer_size]; } u;
1243 // Traverse the list of builtins and generate an adaptor in a
1244 // separate code object for each one.
1245 for (int i = 0; i < builtin_count; i++) {
1246 if (create_heap_objects) {
1247 MacroAssembler masm(isolate, u.buffer, sizeof u.buffer);
1248 // Generate the code/adaptor.
1249 typedef void (*Generator)(MacroAssembler*, int, BuiltinExtraArguments);
1250 Generator g = FUNCTION_CAST<Generator>(functions[i].generator);
1251 // We pass all arguments to the generator, but it may not use all of
1252 // them. This works because the first arguments are on top of the
1254 DCHECK(!masm.has_frame());
1255 g(&masm, functions[i].name, functions[i].extra_args);
1256 // Move the code into the object heap.
1258 masm.GetCode(&desc);
1259 Code::Flags flags = functions[i].flags;
1261 isolate->factory()->NewCode(desc, flags, masm.CodeObject());
1262 // Log the event and add the code to the builtins array.
1264 CodeCreateEvent(Logger::BUILTIN_TAG, *code, functions[i].s_name));
1265 builtins_[i] = *code;
1266 code->set_builtin_index(i);
1267 #ifdef ENABLE_DISASSEMBLER
1268 if (FLAG_print_builtin_code) {
1269 CodeTracer::Scope trace_scope(isolate->GetCodeTracer());
1270 OFStream os(trace_scope.file());
1271 os << "Builtin: " << functions[i].s_name << "\n";
1272 code->Disassemble(functions[i].s_name, os);
1277 // Deserializing. The values will be filled in during IterateBuiltins.
1278 builtins_[i] = NULL;
1280 names_[i] = functions[i].s_name;
1283 // Mark as initialized.
1284 initialized_ = true;
1288 void Builtins::TearDown() {
1289 initialized_ = false;
1293 void Builtins::IterateBuiltins(ObjectVisitor* v) {
1294 v->VisitPointers(&builtins_[0], &builtins_[0] + builtin_count);
1298 const char* Builtins::Lookup(byte* pc) {
1299 // may be called during initialization (disassembler!)
1301 for (int i = 0; i < builtin_count; i++) {
1302 Code* entry = Code::cast(builtins_[i]);
1303 if (entry->contains(pc)) {
1312 void Builtins::Generate_InterruptCheck(MacroAssembler* masm) {
1313 masm->TailCallRuntime(Runtime::kInterrupt, 0, 1);
1317 void Builtins::Generate_StackCheck(MacroAssembler* masm) {
1318 masm->TailCallRuntime(Runtime::kStackGuard, 0, 1);
1322 #define DEFINE_BUILTIN_ACCESSOR_C(name, ignore) \
1323 Handle<Code> Builtins::name() { \
1324 Code** code_address = \
1325 reinterpret_cast<Code**>(builtin_address(k##name)); \
1326 return Handle<Code>(code_address); \
1328 #define DEFINE_BUILTIN_ACCESSOR_A(name, kind, state, extra) \
1329 Handle<Code> Builtins::name() { \
1330 Code** code_address = \
1331 reinterpret_cast<Code**>(builtin_address(k##name)); \
1332 return Handle<Code>(code_address); \
1334 #define DEFINE_BUILTIN_ACCESSOR_H(name, kind) \
1335 Handle<Code> Builtins::name() { \
1336 Code** code_address = \
1337 reinterpret_cast<Code**>(builtin_address(k##name)); \
1338 return Handle<Code>(code_address); \
1340 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C)
1341 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A)
1342 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H)
1343 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A)
1344 #undef DEFINE_BUILTIN_ACCESSOR_C
1345 #undef DEFINE_BUILTIN_ACCESSOR_A
1348 } // namespace internal