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.
4
5 #include "src/v8.h"
6
7 #include "src/api.h"
8 #include "src/arguments.h"
9 #include "src/base/once.h"
10 #include "src/bootstrapper.h"
11 #include "src/builtins.h"
12 #include "src/cpu-profiler.h"
13 #include "src/gdb-jit.h"
14 #include "src/ic-inl.h"
15 #include "src/heap-profiler.h"
16 #include "src/mark-compact.h"
17 #include "src/stub-cache.h"
18 #include "src/vm-state-inl.h"
19
20 namespace v8 {
21 namespace internal {
22
23 namespace {
24
25 // Arguments object passed to C++ builtins.
26 template <BuiltinExtraArguments extra_args>
27 class BuiltinArguments : public Arguments {
28 public:
BuiltinArguments(int length,Object ** arguments)29 BuiltinArguments(int length, Object** arguments)
30 : Arguments(length, arguments) { }
31
operator [](int index)32 Object*& operator[] (int index) {
33 ASSERT(index < length());
34 return Arguments::operator[](index);
35 }
36
at(int index)37 template <class S> Handle<S> at(int index) {
38 ASSERT(index < length());
39 return Arguments::at<S>(index);
40 }
41
receiver()42 Handle<Object> receiver() {
43 return Arguments::at<Object>(0);
44 }
45
called_function()46 Handle<JSFunction> called_function() {
47 STATIC_ASSERT(extra_args == NEEDS_CALLED_FUNCTION);
48 return Arguments::at<JSFunction>(Arguments::length() - 1);
49 }
50
51 // Gets the total number of arguments including the receiver (but
52 // excluding extra arguments).
length() const53 int length() const {
54 STATIC_ASSERT(extra_args == NO_EXTRA_ARGUMENTS);
55 return Arguments::length();
56 }
57
58 #ifdef DEBUG
Verify()59 void Verify() {
60 // Check we have at least the receiver.
61 ASSERT(Arguments::length() >= 1);
62 }
63 #endif
64 };
65
66
67 // Specialize BuiltinArguments for the called function extra argument.
68
69 template <>
length() const70 int BuiltinArguments<NEEDS_CALLED_FUNCTION>::length() const {
71 return Arguments::length() - 1;
72 }
73
74 #ifdef DEBUG
75 template <>
Verify()76 void BuiltinArguments<NEEDS_CALLED_FUNCTION>::Verify() {
77 // Check we have at least the receiver and the called function.
78 ASSERT(Arguments::length() >= 2);
79 // Make sure cast to JSFunction succeeds.
80 called_function();
81 }
82 #endif
83
84
85 #define DEF_ARG_TYPE(name, spec) \
86 typedef BuiltinArguments<spec> name##ArgumentsType;
87 BUILTIN_LIST_C(DEF_ARG_TYPE)
88 #undef DEF_ARG_TYPE
89
90 } // namespace
91
92 // ----------------------------------------------------------------------------
93 // Support macro for defining builtins in C++.
94 // ----------------------------------------------------------------------------
95 //
96 // A builtin function is defined by writing:
97 //
98 // BUILTIN(name) {
99 // ...
100 // }
101 //
102 // In the body of the builtin function the arguments can be accessed
103 // through the BuiltinArguments object args.
104
105 #ifdef DEBUG
106
107 #define BUILTIN(name) \
108 MUST_USE_RESULT static Object* Builtin_Impl_##name( \
109 name##ArgumentsType args, Isolate* isolate); \
110 MUST_USE_RESULT static Object* Builtin_##name( \
111 int args_length, Object** args_object, Isolate* isolate) { \
112 name##ArgumentsType args(args_length, args_object); \
113 args.Verify(); \
114 return Builtin_Impl_##name(args, isolate); \
115 } \
116 MUST_USE_RESULT static Object* Builtin_Impl_##name( \
117 name##ArgumentsType args, Isolate* isolate)
118
119 #else // For release mode.
120
121 #define BUILTIN(name) \
122 static Object* Builtin_impl##name( \
123 name##ArgumentsType args, Isolate* isolate); \
124 static Object* Builtin_##name( \
125 int args_length, Object** args_object, Isolate* isolate) { \
126 name##ArgumentsType args(args_length, args_object); \
127 return Builtin_impl##name(args, isolate); \
128 } \
129 static Object* Builtin_impl##name( \
130 name##ArgumentsType args, Isolate* isolate)
131 #endif
132
133
134 #ifdef DEBUG
CalledAsConstructor(Isolate * isolate)135 static inline bool CalledAsConstructor(Isolate* isolate) {
136 // Calculate the result using a full stack frame iterator and check
137 // that the state of the stack is as we assume it to be in the
138 // code below.
139 StackFrameIterator it(isolate);
140 ASSERT(it.frame()->is_exit());
141 it.Advance();
142 StackFrame* frame = it.frame();
143 bool reference_result = frame->is_construct();
144 Address fp = Isolate::c_entry_fp(isolate->thread_local_top());
145 // Because we know fp points to an exit frame we can use the relevant
146 // part of ExitFrame::ComputeCallerState directly.
147 const int kCallerOffset = ExitFrameConstants::kCallerFPOffset;
148 Address caller_fp = Memory::Address_at(fp + kCallerOffset);
149 // This inlines the part of StackFrame::ComputeType that grabs the
150 // type of the current frame. Note that StackFrame::ComputeType
151 // has been specialized for each architecture so if any one of them
152 // changes this code has to be changed as well.
153 const int kMarkerOffset = StandardFrameConstants::kMarkerOffset;
154 const Smi* kConstructMarker = Smi::FromInt(StackFrame::CONSTRUCT);
155 Object* marker = Memory::Object_at(caller_fp + kMarkerOffset);
156 bool result = (marker == kConstructMarker);
157 ASSERT_EQ(result, reference_result);
158 return result;
159 }
160 #endif
161
162
163 // ----------------------------------------------------------------------------
164
BUILTIN(Illegal)165 BUILTIN(Illegal) {
166 UNREACHABLE();
167 return isolate->heap()->undefined_value(); // Make compiler happy.
168 }
169
170
BUILTIN(EmptyFunction)171 BUILTIN(EmptyFunction) {
172 return isolate->heap()->undefined_value();
173 }
174
175
MoveDoubleElements(FixedDoubleArray * dst,int dst_index,FixedDoubleArray * src,int src_index,int len)176 static void MoveDoubleElements(FixedDoubleArray* dst, int dst_index,
177 FixedDoubleArray* src, int src_index, int len) {
178 if (len == 0) return;
179 MemMove(dst->data_start() + dst_index, src->data_start() + src_index,
180 len * kDoubleSize);
181 }
182
183
LeftTrimFixedArray(Heap * heap,FixedArrayBase * elms,int to_trim)184 static FixedArrayBase* LeftTrimFixedArray(Heap* heap,
185 FixedArrayBase* elms,
186 int to_trim) {
187 ASSERT(heap->CanMoveObjectStart(elms));
188
189 Map* map = elms->map();
190 int entry_size;
191 if (elms->IsFixedArray()) {
192 entry_size = kPointerSize;
193 } else {
194 entry_size = kDoubleSize;
195 }
196 ASSERT(elms->map() != heap->fixed_cow_array_map());
197 // For now this trick is only applied to fixed arrays in new and paged space.
198 // In large object space the object's start must coincide with chunk
199 // and thus the trick is just not applicable.
200 ASSERT(!heap->lo_space()->Contains(elms));
201
202 STATIC_ASSERT(FixedArrayBase::kMapOffset == 0);
203 STATIC_ASSERT(FixedArrayBase::kLengthOffset == kPointerSize);
204 STATIC_ASSERT(FixedArrayBase::kHeaderSize == 2 * kPointerSize);
205
206 Object** former_start = HeapObject::RawField(elms, 0);
207
208 const int len = elms->length();
209
210 if (to_trim * entry_size > FixedArrayBase::kHeaderSize &&
211 elms->IsFixedArray() &&
212 !heap->new_space()->Contains(elms)) {
213 // If we are doing a big trim in old space then we zap the space that was
214 // formerly part of the array so that the GC (aided by the card-based
215 // remembered set) won't find pointers to new-space there.
216 Object** zap = reinterpret_cast<Object**>(elms->address());
217 zap++; // Header of filler must be at least one word so skip that.
218 for (int i = 1; i < to_trim; i++) {
219 *zap++ = Smi::FromInt(0);
220 }
221 }
222 // Technically in new space this write might be omitted (except for
223 // debug mode which iterates through the heap), but to play safer
224 // we still do it.
225 // Since left trimming is only performed on pages which are not concurrently
226 // swept creating a filler object does not require synchronization.
227 heap->CreateFillerObjectAt(elms->address(), to_trim * entry_size);
228
229 int new_start_index = to_trim * (entry_size / kPointerSize);
230 former_start[new_start_index] = map;
231 former_start[new_start_index + 1] = Smi::FromInt(len - to_trim);
232
233 // Maintain marking consistency for HeapObjectIterator and
234 // IncrementalMarking.
235 int size_delta = to_trim * entry_size;
236 Address new_start = elms->address() + size_delta;
237 heap->marking()->TransferMark(elms->address(), new_start);
238 heap->AdjustLiveBytes(new_start, -size_delta, Heap::FROM_MUTATOR);
239
240 FixedArrayBase* new_elms =
241 FixedArrayBase::cast(HeapObject::FromAddress(new_start));
242 HeapProfiler* profiler = heap->isolate()->heap_profiler();
243 if (profiler->is_tracking_object_moves()) {
244 profiler->ObjectMoveEvent(elms->address(),
245 new_elms->address(),
246 new_elms->Size());
247 }
248 return new_elms;
249 }
250
251
ArrayPrototypeHasNoElements(Heap * heap,Context * native_context,JSObject * array_proto)252 static bool ArrayPrototypeHasNoElements(Heap* heap,
253 Context* native_context,
254 JSObject* array_proto) {
255 DisallowHeapAllocation no_gc;
256 // This method depends on non writability of Object and Array prototype
257 // fields.
258 if (array_proto->elements() != heap->empty_fixed_array()) return false;
259 // Object.prototype
260 Object* proto = array_proto->GetPrototype();
261 if (proto == heap->null_value()) return false;
262 array_proto = JSObject::cast(proto);
263 if (array_proto != native_context->initial_object_prototype()) return false;
264 if (array_proto->elements() != heap->empty_fixed_array()) return false;
265 return array_proto->GetPrototype()->IsNull();
266 }
267
268
269 // Returns empty handle if not applicable.
270 MUST_USE_RESULT
EnsureJSArrayWithWritableFastElements(Isolate * isolate,Handle<Object> receiver,Arguments * args,int first_added_arg)271 static inline MaybeHandle<FixedArrayBase> EnsureJSArrayWithWritableFastElements(
272 Isolate* isolate,
273 Handle<Object> receiver,
274 Arguments* args,
275 int first_added_arg) {
276 if (!receiver->IsJSArray()) return MaybeHandle<FixedArrayBase>();
277 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
278 // If there may be elements accessors in the prototype chain, the fast path
279 // cannot be used if there arguments to add to the array.
280 if (args != NULL && array->map()->DictionaryElementsInPrototypeChainOnly()) {
281 return MaybeHandle<FixedArrayBase>();
282 }
283 if (array->map()->is_observed()) return MaybeHandle<FixedArrayBase>();
284 if (!array->map()->is_extensible()) return MaybeHandle<FixedArrayBase>();
285 Handle<FixedArrayBase> elms(array->elements(), isolate);
286 Heap* heap = isolate->heap();
287 Map* map = elms->map();
288 if (map == heap->fixed_array_map()) {
289 if (args == NULL || array->HasFastObjectElements()) return elms;
290 } else if (map == heap->fixed_cow_array_map()) {
291 elms = JSObject::EnsureWritableFastElements(array);
292 if (args == NULL || array->HasFastObjectElements()) return elms;
293 } else if (map == heap->fixed_double_array_map()) {
294 if (args == NULL) return elms;
295 } else {
296 return MaybeHandle<FixedArrayBase>();
297 }
298
299 // Need to ensure that the arguments passed in args can be contained in
300 // the array.
301 int args_length = args->length();
302 if (first_added_arg >= args_length) return handle(array->elements(), isolate);
303
304 ElementsKind origin_kind = array->map()->elements_kind();
305 ASSERT(!IsFastObjectElementsKind(origin_kind));
306 ElementsKind target_kind = origin_kind;
307 {
308 DisallowHeapAllocation no_gc;
309 int arg_count = args->length() - first_added_arg;
310 Object** arguments = args->arguments() - first_added_arg - (arg_count - 1);
311 for (int i = 0; i < arg_count; i++) {
312 Object* arg = arguments[i];
313 if (arg->IsHeapObject()) {
314 if (arg->IsHeapNumber()) {
315 target_kind = FAST_DOUBLE_ELEMENTS;
316 } else {
317 target_kind = FAST_ELEMENTS;
318 break;
319 }
320 }
321 }
322 }
323 if (target_kind != origin_kind) {
324 JSObject::TransitionElementsKind(array, target_kind);
325 return handle(array->elements(), isolate);
326 }
327 return elms;
328 }
329
330
IsJSArrayFastElementMovingAllowed(Heap * heap,JSArray * receiver)331 static inline bool IsJSArrayFastElementMovingAllowed(Heap* heap,
332 JSArray* receiver) {
333 if (!FLAG_clever_optimizations) return false;
334 DisallowHeapAllocation no_gc;
335 Context* native_context = heap->isolate()->context()->native_context();
336 JSObject* array_proto =
337 JSObject::cast(native_context->array_function()->prototype());
338 return receiver->GetPrototype() == array_proto &&
339 ArrayPrototypeHasNoElements(heap, native_context, array_proto);
340 }
341
342
CallJsBuiltin(Isolate * isolate,const char * name,BuiltinArguments<NO_EXTRA_ARGUMENTS> args)343 MUST_USE_RESULT static Object* CallJsBuiltin(
344 Isolate* isolate,
345 const char* name,
346 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
347 HandleScope handleScope(isolate);
348
349 Handle<Object> js_builtin = Object::GetProperty(
350 isolate,
351 handle(isolate->native_context()->builtins(), isolate),
352 name).ToHandleChecked();
353 Handle<JSFunction> function = Handle<JSFunction>::cast(js_builtin);
354 int argc = args.length() - 1;
355 ScopedVector<Handle<Object> > argv(argc);
356 for (int i = 0; i < argc; ++i) {
357 argv[i] = args.at<Object>(i + 1);
358 }
359 Handle<Object> result;
360 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
361 isolate, result,
362 Execution::Call(isolate,
363 function,
364 args.receiver(),
365 argc,
366 argv.start()));
367 return *result;
368 }
369
370
BUILTIN(ArrayPush)371 BUILTIN(ArrayPush) {
372 HandleScope scope(isolate);
373 Handle<Object> receiver = args.receiver();
374 MaybeHandle<FixedArrayBase> maybe_elms_obj =
375 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1);
376 Handle<FixedArrayBase> elms_obj;
377 if (!maybe_elms_obj.ToHandle(&elms_obj)) {
378 return CallJsBuiltin(isolate, "ArrayPush", args);
379 }
380
381 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
382 int len = Smi::cast(array->length())->value();
383 int to_add = args.length() - 1;
384 if (to_add > 0 && JSArray::WouldChangeReadOnlyLength(array, len + to_add)) {
385 return CallJsBuiltin(isolate, "ArrayPush", args);
386 }
387 ASSERT(!array->map()->is_observed());
388
389 ElementsKind kind = array->GetElementsKind();
390
391 if (IsFastSmiOrObjectElementsKind(kind)) {
392 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
393 if (to_add == 0) {
394 return Smi::FromInt(len);
395 }
396 // Currently fixed arrays cannot grow too big, so
397 // we should never hit this case.
398 ASSERT(to_add <= (Smi::kMaxValue - len));
399
400 int new_length = len + to_add;
401
402 if (new_length > elms->length()) {
403 // New backing storage is needed.
404 int capacity = new_length + (new_length >> 1) + 16;
405 Handle<FixedArray> new_elms =
406 isolate->factory()->NewUninitializedFixedArray(capacity);
407
408 ElementsAccessor* accessor = array->GetElementsAccessor();
409 accessor->CopyElements(
410 elms_obj, 0, kind, new_elms, 0,
411 ElementsAccessor::kCopyToEndAndInitializeToHole);
412
413 elms = new_elms;
414 }
415
416 // Add the provided values.
417 DisallowHeapAllocation no_gc;
418 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
419 for (int index = 0; index < to_add; index++) {
420 elms->set(index + len, args[index + 1], mode);
421 }
422
423 if (*elms != array->elements()) {
424 array->set_elements(*elms);
425 }
426
427 // Set the length.
428 array->set_length(Smi::FromInt(new_length));
429 return Smi::FromInt(new_length);
430 } else {
431 int elms_len = elms_obj->length();
432 if (to_add == 0) {
433 return Smi::FromInt(len);
434 }
435 // Currently fixed arrays cannot grow too big, so
436 // we should never hit this case.
437 ASSERT(to_add <= (Smi::kMaxValue - len));
438
439 int new_length = len + to_add;
440
441 Handle<FixedDoubleArray> new_elms;
442
443 if (new_length > elms_len) {
444 // New backing storage is needed.
445 int capacity = new_length + (new_length >> 1) + 16;
446 // Create new backing store; since capacity > 0, we can
447 // safely cast to FixedDoubleArray.
448 new_elms = Handle<FixedDoubleArray>::cast(
449 isolate->factory()->NewFixedDoubleArray(capacity));
450
451 ElementsAccessor* accessor = array->GetElementsAccessor();
452 accessor->CopyElements(
453 elms_obj, 0, kind, new_elms, 0,
454 ElementsAccessor::kCopyToEndAndInitializeToHole);
455
456 } else {
457 // to_add is > 0 and new_length <= elms_len, so elms_obj cannot be the
458 // empty_fixed_array.
459 new_elms = Handle<FixedDoubleArray>::cast(elms_obj);
460 }
461
462 // Add the provided values.
463 DisallowHeapAllocation no_gc;
464 int index;
465 for (index = 0; index < to_add; index++) {
466 Object* arg = args[index + 1];
467 new_elms->set(index + len, arg->Number());
468 }
469
470 if (*new_elms != array->elements()) {
471 array->set_elements(*new_elms);
472 }
473
474 // Set the length.
475 array->set_length(Smi::FromInt(new_length));
476 return Smi::FromInt(new_length);
477 }
478 }
479
480
BUILTIN(ArrayPop)481 BUILTIN(ArrayPop) {
482 HandleScope scope(isolate);
483 Handle<Object> receiver = args.receiver();
484 MaybeHandle<FixedArrayBase> maybe_elms_obj =
485 EnsureJSArrayWithWritableFastElements(isolate, receiver, NULL, 0);
486 Handle<FixedArrayBase> elms_obj;
487 if (!maybe_elms_obj.ToHandle(&elms_obj)) {
488 return CallJsBuiltin(isolate, "ArrayPop", args);
489 }
490
491 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
492 ASSERT(!array->map()->is_observed());
493
494 int len = Smi::cast(array->length())->value();
495 if (len == 0) return isolate->heap()->undefined_value();
496
497 ElementsAccessor* accessor = array->GetElementsAccessor();
498 int new_length = len - 1;
499 Handle<Object> element =
500 accessor->Get(array, array, new_length, elms_obj).ToHandleChecked();
501 if (element->IsTheHole()) {
502 return CallJsBuiltin(isolate, "ArrayPop", args);
503 }
504 RETURN_FAILURE_ON_EXCEPTION(
505 isolate,
506 accessor->SetLength(array, handle(Smi::FromInt(new_length), isolate)));
507 return *element;
508 }
509
510
BUILTIN(ArrayShift)511 BUILTIN(ArrayShift) {
512 HandleScope scope(isolate);
513 Heap* heap = isolate->heap();
514 Handle<Object> receiver = args.receiver();
515 MaybeHandle<FixedArrayBase> maybe_elms_obj =
516 EnsureJSArrayWithWritableFastElements(isolate, receiver, NULL, 0);
517 Handle<FixedArrayBase> elms_obj;
518 if (!maybe_elms_obj.ToHandle(&elms_obj) ||
519 !IsJSArrayFastElementMovingAllowed(heap,
520 *Handle<JSArray>::cast(receiver))) {
521 return CallJsBuiltin(isolate, "ArrayShift", args);
522 }
523 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
524 ASSERT(!array->map()->is_observed());
525
526 int len = Smi::cast(array->length())->value();
527 if (len == 0) return heap->undefined_value();
528
529 // Get first element
530 ElementsAccessor* accessor = array->GetElementsAccessor();
531 Handle<Object> first =
532 accessor->Get(array, array, 0, elms_obj).ToHandleChecked();
533 if (first->IsTheHole()) {
534 return CallJsBuiltin(isolate, "ArrayShift", args);
535 }
536
537 if (heap->CanMoveObjectStart(*elms_obj)) {
538 array->set_elements(LeftTrimFixedArray(heap, *elms_obj, 1));
539 } else {
540 // Shift the elements.
541 if (elms_obj->IsFixedArray()) {
542 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
543 DisallowHeapAllocation no_gc;
544 heap->MoveElements(*elms, 0, 1, len - 1);
545 elms->set(len - 1, heap->the_hole_value());
546 } else {
547 Handle<FixedDoubleArray> elms = Handle<FixedDoubleArray>::cast(elms_obj);
548 MoveDoubleElements(*elms, 0, *elms, 1, len - 1);
549 elms->set_the_hole(len - 1);
550 }
551 }
552
553 // Set the length.
554 array->set_length(Smi::FromInt(len - 1));
555
556 return *first;
557 }
558
559
BUILTIN(ArrayUnshift)560 BUILTIN(ArrayUnshift) {
561 HandleScope scope(isolate);
562 Heap* heap = isolate->heap();
563 Handle<Object> receiver = args.receiver();
564 MaybeHandle<FixedArrayBase> maybe_elms_obj =
565 EnsureJSArrayWithWritableFastElements(isolate, receiver, NULL, 0);
566 Handle<FixedArrayBase> elms_obj;
567 if (!maybe_elms_obj.ToHandle(&elms_obj) ||
568 !IsJSArrayFastElementMovingAllowed(heap,
569 *Handle<JSArray>::cast(receiver))) {
570 return CallJsBuiltin(isolate, "ArrayUnshift", args);
571 }
572 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
573 ASSERT(!array->map()->is_observed());
574 if (!array->HasFastSmiOrObjectElements()) {
575 return CallJsBuiltin(isolate, "ArrayUnshift", args);
576 }
577 int len = Smi::cast(array->length())->value();
578 int to_add = args.length() - 1;
579 int new_length = len + to_add;
580 // Currently fixed arrays cannot grow too big, so
581 // we should never hit this case.
582 ASSERT(to_add <= (Smi::kMaxValue - len));
583
584 if (to_add > 0 && JSArray::WouldChangeReadOnlyLength(array, len + to_add)) {
585 return CallJsBuiltin(isolate, "ArrayUnshift", args);
586 }
587
588 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
589
590 JSObject::EnsureCanContainElements(array, &args, 1, to_add,
591 DONT_ALLOW_DOUBLE_ELEMENTS);
592
593 if (new_length > elms->length()) {
594 // New backing storage is needed.
595 int capacity = new_length + (new_length >> 1) + 16;
596 Handle<FixedArray> new_elms =
597 isolate->factory()->NewUninitializedFixedArray(capacity);
598
599 ElementsKind kind = array->GetElementsKind();
600 ElementsAccessor* accessor = array->GetElementsAccessor();
601 accessor->CopyElements(
602 elms, 0, kind, new_elms, to_add,
603 ElementsAccessor::kCopyToEndAndInitializeToHole);
604
605 elms = new_elms;
606 array->set_elements(*elms);
607 } else {
608 DisallowHeapAllocation no_gc;
609 heap->MoveElements(*elms, to_add, 0, len);
610 }
611
612 // Add the provided values.
613 DisallowHeapAllocation no_gc;
614 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
615 for (int i = 0; i < to_add; i++) {
616 elms->set(i, args[i + 1], mode);
617 }
618
619 // Set the length.
620 array->set_length(Smi::FromInt(new_length));
621 return Smi::FromInt(new_length);
622 }
623
624
BUILTIN(ArraySlice)625 BUILTIN(ArraySlice) {
626 HandleScope scope(isolate);
627 Heap* heap = isolate->heap();
628 Handle<Object> receiver = args.receiver();
629 int len = -1;
630 int relative_start = 0;
631 int relative_end = 0;
632 {
633 DisallowHeapAllocation no_gc;
634 if (receiver->IsJSArray()) {
635 JSArray* array = JSArray::cast(*receiver);
636 if (!IsJSArrayFastElementMovingAllowed(heap, array)) {
637 AllowHeapAllocation allow_allocation;
638 return CallJsBuiltin(isolate, "ArraySlice", args);
639 }
640
641 if (!array->HasFastElements()) {
642 AllowHeapAllocation allow_allocation;
643 return CallJsBuiltin(isolate, "ArraySlice", args);
644 }
645
646 len = Smi::cast(array->length())->value();
647 } else {
648 // Array.slice(arguments, ...) is quite a common idiom (notably more
649 // than 50% of invocations in Web apps). Treat it in C++ as well.
650 Map* arguments_map = isolate->context()->native_context()->
651 sloppy_arguments_boilerplate()->map();
652
653 bool is_arguments_object_with_fast_elements =
654 receiver->IsJSObject() &&
655 JSObject::cast(*receiver)->map() == arguments_map;
656 if (!is_arguments_object_with_fast_elements) {
657 AllowHeapAllocation allow_allocation;
658 return CallJsBuiltin(isolate, "ArraySlice", args);
659 }
660 JSObject* object = JSObject::cast(*receiver);
661
662 if (!object->HasFastElements()) {
663 AllowHeapAllocation allow_allocation;
664 return CallJsBuiltin(isolate, "ArraySlice", args);
665 }
666
667 Object* len_obj = object->InObjectPropertyAt(Heap::kArgumentsLengthIndex);
668 if (!len_obj->IsSmi()) {
669 AllowHeapAllocation allow_allocation;
670 return CallJsBuiltin(isolate, "ArraySlice", args);
671 }
672 len = Smi::cast(len_obj)->value();
673 if (len > object->elements()->length()) {
674 AllowHeapAllocation allow_allocation;
675 return CallJsBuiltin(isolate, "ArraySlice", args);
676 }
677 }
678
679 ASSERT(len >= 0);
680 int n_arguments = args.length() - 1;
681
682 // Note carefully choosen defaults---if argument is missing,
683 // it's undefined which gets converted to 0 for relative_start
684 // and to len for relative_end.
685 relative_start = 0;
686 relative_end = len;
687 if (n_arguments > 0) {
688 Object* arg1 = args[1];
689 if (arg1->IsSmi()) {
690 relative_start = Smi::cast(arg1)->value();
691 } else if (arg1->IsHeapNumber()) {
692 double start = HeapNumber::cast(arg1)->value();
693 if (start < kMinInt || start > kMaxInt) {
694 AllowHeapAllocation allow_allocation;
695 return CallJsBuiltin(isolate, "ArraySlice", args);
696 }
697 relative_start = std::isnan(start) ? 0 : static_cast<int>(start);
698 } else if (!arg1->IsUndefined()) {
699 AllowHeapAllocation allow_allocation;
700 return CallJsBuiltin(isolate, "ArraySlice", args);
701 }
702 if (n_arguments > 1) {
703 Object* arg2 = args[2];
704 if (arg2->IsSmi()) {
705 relative_end = Smi::cast(arg2)->value();
706 } else if (arg2->IsHeapNumber()) {
707 double end = HeapNumber::cast(arg2)->value();
708 if (end < kMinInt || end > kMaxInt) {
709 AllowHeapAllocation allow_allocation;
710 return CallJsBuiltin(isolate, "ArraySlice", args);
711 }
712 relative_end = std::isnan(end) ? 0 : static_cast<int>(end);
713 } else if (!arg2->IsUndefined()) {
714 AllowHeapAllocation allow_allocation;
715 return CallJsBuiltin(isolate, "ArraySlice", args);
716 }
717 }
718 }
719 }
720
721 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6.
722 int k = (relative_start < 0) ? Max(len + relative_start, 0)
723 : Min(relative_start, len);
724
725 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8.
726 int final = (relative_end < 0) ? Max(len + relative_end, 0)
727 : Min(relative_end, len);
728
729 // Calculate the length of result array.
730 int result_len = Max(final - k, 0);
731
732 Handle<JSObject> object = Handle<JSObject>::cast(receiver);
733 Handle<FixedArrayBase> elms(object->elements(), isolate);
734
735 ElementsKind kind = object->GetElementsKind();
736 if (IsHoleyElementsKind(kind)) {
737 DisallowHeapAllocation no_gc;
738 bool packed = true;
739 ElementsAccessor* accessor = ElementsAccessor::ForKind(kind);
740 for (int i = k; i < final; i++) {
741 if (!accessor->HasElement(object, object, i, elms)) {
742 packed = false;
743 break;
744 }
745 }
746 if (packed) {
747 kind = GetPackedElementsKind(kind);
748 } else if (!receiver->IsJSArray()) {
749 AllowHeapAllocation allow_allocation;
750 return CallJsBuiltin(isolate, "ArraySlice", args);
751 }
752 }
753
754 Handle<JSArray> result_array =
755 isolate->factory()->NewJSArray(kind, result_len, result_len);
756
757 DisallowHeapAllocation no_gc;
758 if (result_len == 0) return *result_array;
759
760 ElementsAccessor* accessor = object->GetElementsAccessor();
761 accessor->CopyElements(
762 elms, k, kind, handle(result_array->elements(), isolate), 0, result_len);
763 return *result_array;
764 }
765
766
BUILTIN(ArraySplice)767 BUILTIN(ArraySplice) {
768 HandleScope scope(isolate);
769 Heap* heap = isolate->heap();
770 Handle<Object> receiver = args.receiver();
771 MaybeHandle<FixedArrayBase> maybe_elms_obj =
772 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3);
773 Handle<FixedArrayBase> elms_obj;
774 if (!maybe_elms_obj.ToHandle(&elms_obj) ||
775 !IsJSArrayFastElementMovingAllowed(heap,
776 *Handle<JSArray>::cast(receiver))) {
777 return CallJsBuiltin(isolate, "ArraySplice", args);
778 }
779 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
780 ASSERT(!array->map()->is_observed());
781
782 int len = Smi::cast(array->length())->value();
783
784 int n_arguments = args.length() - 1;
785
786 int relative_start = 0;
787 if (n_arguments > 0) {
788 DisallowHeapAllocation no_gc;
789 Object* arg1 = args[1];
790 if (arg1->IsSmi()) {
791 relative_start = Smi::cast(arg1)->value();
792 } else if (arg1->IsHeapNumber()) {
793 double start = HeapNumber::cast(arg1)->value();
794 if (start < kMinInt || start > kMaxInt) {
795 AllowHeapAllocation allow_allocation;
796 return CallJsBuiltin(isolate, "ArraySplice", args);
797 }
798 relative_start = std::isnan(start) ? 0 : static_cast<int>(start);
799 } else if (!arg1->IsUndefined()) {
800 AllowHeapAllocation allow_allocation;
801 return CallJsBuiltin(isolate, "ArraySplice", args);
802 }
803 }
804 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
805 : Min(relative_start, len);
806
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
811 // compatibility.
812 int actual_delete_count;
813 if (n_arguments == 1) {
814 ASSERT(len - actual_start >= 0);
815 actual_delete_count = len - actual_start;
816 } else {
817 int value = 0; // ToInteger(undefined) == 0
818 if (n_arguments > 1) {
819 DisallowHeapAllocation no_gc;
820 Object* arg2 = args[2];
821 if (arg2->IsSmi()) {
822 value = Smi::cast(arg2)->value();
823 } else {
824 AllowHeapAllocation allow_allocation;
825 return CallJsBuiltin(isolate, "ArraySplice", args);
826 }
827 }
828 actual_delete_count = Min(Max(value, 0), len - actual_start);
829 }
830
831 ElementsKind elements_kind = array->GetElementsKind();
832
833 int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0;
834 int new_length = len - actual_delete_count + item_count;
835
836 // For double mode we do not support changing the length.
837 if (new_length > len && IsFastDoubleElementsKind(elements_kind)) {
838 return CallJsBuiltin(isolate, "ArraySplice", args);
839 }
840
841 if (new_length == 0) {
842 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(
843 elms_obj, elements_kind, actual_delete_count);
844 array->set_elements(heap->empty_fixed_array());
845 array->set_length(Smi::FromInt(0));
846 return *result;
847 }
848
849 Handle<JSArray> result_array =
850 isolate->factory()->NewJSArray(elements_kind,
851 actual_delete_count,
852 actual_delete_count);
853
854 if (actual_delete_count > 0) {
855 DisallowHeapAllocation no_gc;
856 ElementsAccessor* accessor = array->GetElementsAccessor();
857 accessor->CopyElements(
858 elms_obj, actual_start, elements_kind,
859 handle(result_array->elements(), isolate), 0, actual_delete_count);
860 }
861
862 bool elms_changed = false;
863 if (item_count < actual_delete_count) {
864 // Shrink the array.
865 const bool trim_array = !heap->lo_space()->Contains(*elms_obj) &&
866 ((actual_start + item_count) <
867 (len - actual_delete_count - actual_start));
868 if (trim_array) {
869 const int delta = actual_delete_count - item_count;
870
871 if (elms_obj->IsFixedDoubleArray()) {
872 Handle<FixedDoubleArray> elms =
873 Handle<FixedDoubleArray>::cast(elms_obj);
874 MoveDoubleElements(*elms, delta, *elms, 0, actual_start);
875 } else {
876 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
877 DisallowHeapAllocation no_gc;
878 heap->MoveElements(*elms, delta, 0, actual_start);
879 }
880
881 if (heap->CanMoveObjectStart(*elms_obj)) {
882 // On the fast path we move the start of the object in memory.
883 elms_obj = handle(LeftTrimFixedArray(heap, *elms_obj, delta), isolate);
884 } else {
885 // This is the slow path. We are going to move the elements to the left
886 // by copying them. For trimmed values we store the hole.
887 if (elms_obj->IsFixedDoubleArray()) {
888 Handle<FixedDoubleArray> elms =
889 Handle<FixedDoubleArray>::cast(elms_obj);
890 MoveDoubleElements(*elms, 0, *elms, delta, len - delta);
891 elms->FillWithHoles(len - delta, len);
892 } else {
893 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
894 DisallowHeapAllocation no_gc;
895 heap->MoveElements(*elms, 0, delta, len - delta);
896 elms->FillWithHoles(len - delta, len);
897 }
898 }
899 elms_changed = true;
900 } else {
901 if (elms_obj->IsFixedDoubleArray()) {
902 Handle<FixedDoubleArray> elms =
903 Handle<FixedDoubleArray>::cast(elms_obj);
904 MoveDoubleElements(*elms, actual_start + item_count,
905 *elms, actual_start + actual_delete_count,
906 (len - actual_delete_count - actual_start));
907 elms->FillWithHoles(new_length, len);
908 } else {
909 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
910 DisallowHeapAllocation no_gc;
911 heap->MoveElements(*elms, actual_start + item_count,
912 actual_start + actual_delete_count,
913 (len - actual_delete_count - actual_start));
914 elms->FillWithHoles(new_length, len);
915 }
916 }
917 } else if (item_count > actual_delete_count) {
918 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
919 // Currently fixed arrays cannot grow too big, so
920 // we should never hit this case.
921 ASSERT((item_count - actual_delete_count) <= (Smi::kMaxValue - len));
922
923 // Check if array need to grow.
924 if (new_length > elms->length()) {
925 // New backing storage is needed.
926 int capacity = new_length + (new_length >> 1) + 16;
927 Handle<FixedArray> new_elms =
928 isolate->factory()->NewUninitializedFixedArray(capacity);
929
930 DisallowHeapAllocation no_gc;
931
932 ElementsKind kind = array->GetElementsKind();
933 ElementsAccessor* accessor = array->GetElementsAccessor();
934 if (actual_start > 0) {
935 // Copy the part before actual_start as is.
936 accessor->CopyElements(
937 elms, 0, kind, new_elms, 0, actual_start);
938 }
939 accessor->CopyElements(
940 elms, actual_start + actual_delete_count, kind,
941 new_elms, actual_start + item_count,
942 ElementsAccessor::kCopyToEndAndInitializeToHole);
943
944 elms_obj = new_elms;
945 elms_changed = true;
946 } else {
947 DisallowHeapAllocation no_gc;
948 heap->MoveElements(*elms, actual_start + item_count,
949 actual_start + actual_delete_count,
950 (len - actual_delete_count - actual_start));
951 }
952 }
953
954 if (IsFastDoubleElementsKind(elements_kind)) {
955 Handle<FixedDoubleArray> elms = Handle<FixedDoubleArray>::cast(elms_obj);
956 for (int k = actual_start; k < actual_start + item_count; k++) {
957 Object* arg = args[3 + k - actual_start];
958 if (arg->IsSmi()) {
959 elms->set(k, Smi::cast(arg)->value());
960 } else {
961 elms->set(k, HeapNumber::cast(arg)->value());
962 }
963 }
964 } else {
965 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
966 DisallowHeapAllocation no_gc;
967 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
968 for (int k = actual_start; k < actual_start + item_count; k++) {
969 elms->set(k, args[3 + k - actual_start], mode);
970 }
971 }
972
973 if (elms_changed) {
974 array->set_elements(*elms_obj);
975 }
976 // Set the length.
977 array->set_length(Smi::FromInt(new_length));
978
979 return *result_array;
980 }
981
982
BUILTIN(ArrayConcat)983 BUILTIN(ArrayConcat) {
984 HandleScope scope(isolate);
985
986 int n_arguments = args.length();
987 int result_len = 0;
988 ElementsKind elements_kind = GetInitialFastElementsKind();
989 bool has_double = false;
990 {
991 DisallowHeapAllocation no_gc;
992 Heap* heap = isolate->heap();
993 Context* native_context = isolate->context()->native_context();
994 JSObject* array_proto =
995 JSObject::cast(native_context->array_function()->prototype());
996 if (!ArrayPrototypeHasNoElements(heap, native_context, array_proto)) {
997 AllowHeapAllocation allow_allocation;
998 return CallJsBuiltin(isolate, "ArrayConcatJS", args);
999 }
1000
1001 // Iterate through all the arguments performing checks
1002 // and calculating total length.
1003 bool is_holey = false;
1004 for (int i = 0; i < n_arguments; i++) {
1005 Object* arg = args[i];
1006 if (!arg->IsJSArray() ||
1007 !JSArray::cast(arg)->HasFastElements() ||
1008 JSArray::cast(arg)->GetPrototype() != array_proto) {
1009 AllowHeapAllocation allow_allocation;
1010 return CallJsBuiltin(isolate, "ArrayConcatJS", args);
1011 }
1012 int len = Smi::cast(JSArray::cast(arg)->length())->value();
1013
1014 // We shouldn't overflow when adding another len.
1015 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
1016 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt);
1017 USE(kHalfOfMaxInt);
1018 result_len += len;
1019 ASSERT(result_len >= 0);
1020
1021 if (result_len > FixedDoubleArray::kMaxLength) {
1022 AllowHeapAllocation allow_allocation;
1023 return CallJsBuiltin(isolate, "ArrayConcatJS", args);
1024 }
1025
1026 ElementsKind arg_kind = JSArray::cast(arg)->map()->elements_kind();
1027 has_double = has_double || IsFastDoubleElementsKind(arg_kind);
1028 is_holey = is_holey || IsFastHoleyElementsKind(arg_kind);
1029 if (IsMoreGeneralElementsKindTransition(elements_kind, arg_kind)) {
1030 elements_kind = arg_kind;
1031 }
1032 }
1033 if (is_holey) elements_kind = GetHoleyElementsKind(elements_kind);
1034 }
1035
1036 // If a double array is concatted into a fast elements array, the fast
1037 // elements array needs to be initialized to contain proper holes, since
1038 // boxing doubles may cause incremental marking.
1039 ArrayStorageAllocationMode mode =
1040 has_double && IsFastObjectElementsKind(elements_kind)
1041 ? INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE : DONT_INITIALIZE_ARRAY_ELEMENTS;
1042 Handle<JSArray> result_array =
1043 isolate->factory()->NewJSArray(elements_kind,
1044 result_len,
1045 result_len,
1046 mode);
1047 if (result_len == 0) return *result_array;
1048
1049 int j = 0;
1050 Handle<FixedArrayBase> storage(result_array->elements(), isolate);
1051 ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind);
1052 for (int i = 0; i < n_arguments; i++) {
1053 // TODO(ishell): It is crucial to keep |array| as a raw pointer to avoid
1054 // performance degradation. Revisit this later.
1055 JSArray* array = JSArray::cast(args[i]);
1056 int len = Smi::cast(array->length())->value();
1057 ElementsKind from_kind = array->GetElementsKind();
1058 if (len > 0) {
1059 accessor->CopyElements(array, 0, from_kind, storage, j, len);
1060 j += len;
1061 }
1062 }
1063
1064 ASSERT(j == result_len);
1065
1066 return *result_array;
1067 }
1068
1069
1070 // -----------------------------------------------------------------------------
1071 // Generator and strict mode poison pills
1072
1073
BUILTIN(StrictModePoisonPill)1074 BUILTIN(StrictModePoisonPill) {
1075 HandleScope scope(isolate);
1076 return isolate->Throw(*isolate->factory()->NewTypeError(
1077 "strict_poison_pill", HandleVector<Object>(NULL, 0)));
1078 }
1079
1080
BUILTIN(GeneratorPoisonPill)1081 BUILTIN(GeneratorPoisonPill) {
1082 HandleScope scope(isolate);
1083 return isolate->Throw(*isolate->factory()->NewTypeError(
1084 "generator_poison_pill", HandleVector<Object>(NULL, 0)));
1085 }
1086
1087
1088 // -----------------------------------------------------------------------------
1089 //
1090
1091
1092 // Searches the hidden prototype chain of the given object for the first
1093 // object that is an instance of the given type. If no such object can
1094 // be found then Heap::null_value() is returned.
FindHidden(Heap * heap,Object * object,FunctionTemplateInfo * type)1095 static inline Object* FindHidden(Heap* heap,
1096 Object* object,
1097 FunctionTemplateInfo* type) {
1098 if (type->IsTemplateFor(object)) return object;
1099 Object* proto = object->GetPrototype(heap->isolate());
1100 if (proto->IsJSObject() &&
1101 JSObject::cast(proto)->map()->is_hidden_prototype()) {
1102 return FindHidden(heap, proto, type);
1103 }
1104 return heap->null_value();
1105 }
1106
1107
1108 // Returns the holder JSObject if the function can legally be called
1109 // with this receiver. Returns Heap::null_value() if the call is
1110 // illegal. Any arguments that don't fit the expected type is
1111 // overwritten with undefined. Note that holder and the arguments are
1112 // implicitly rewritten with the first object in the hidden prototype
1113 // chain that actually has the expected type.
TypeCheck(Heap * heap,int argc,Object ** argv,FunctionTemplateInfo * info)1114 static inline Object* TypeCheck(Heap* heap,
1115 int argc,
1116 Object** argv,
1117 FunctionTemplateInfo* info) {
1118 Object* recv = argv[0];
1119 // API calls are only supported with JSObject receivers.
1120 if (!recv->IsJSObject()) return heap->null_value();
1121 Object* sig_obj = info->signature();
1122 if (sig_obj->IsUndefined()) return recv;
1123 SignatureInfo* sig = SignatureInfo::cast(sig_obj);
1124 // If necessary, check the receiver
1125 Object* recv_type = sig->receiver();
1126 Object* holder = recv;
1127 if (!recv_type->IsUndefined()) {
1128 holder = FindHidden(heap, holder, FunctionTemplateInfo::cast(recv_type));
1129 if (holder == heap->null_value()) return heap->null_value();
1130 }
1131 Object* args_obj = sig->args();
1132 // If there is no argument signature we're done
1133 if (args_obj->IsUndefined()) return holder;
1134 FixedArray* args = FixedArray::cast(args_obj);
1135 int length = args->length();
1136 if (argc <= length) length = argc - 1;
1137 for (int i = 0; i < length; i++) {
1138 Object* argtype = args->get(i);
1139 if (argtype->IsUndefined()) continue;
1140 Object** arg = &argv[-1 - i];
1141 Object* current = *arg;
1142 current = FindHidden(heap, current, FunctionTemplateInfo::cast(argtype));
1143 if (current == heap->null_value()) current = heap->undefined_value();
1144 *arg = current;
1145 }
1146 return holder;
1147 }
1148
1149
1150 template <bool is_construct>
HandleApiCallHelper(BuiltinArguments<NEEDS_CALLED_FUNCTION> args,Isolate * isolate)1151 MUST_USE_RESULT static Object* HandleApiCallHelper(
1152 BuiltinArguments<NEEDS_CALLED_FUNCTION> args, Isolate* isolate) {
1153 ASSERT(is_construct == CalledAsConstructor(isolate));
1154 Heap* heap = isolate->heap();
1155
1156 HandleScope scope(isolate);
1157 Handle<JSFunction> function = args.called_function();
1158 ASSERT(function->shared()->IsApiFunction());
1159
1160 Handle<FunctionTemplateInfo> fun_data(
1161 function->shared()->get_api_func_data(), isolate);
1162 if (is_construct) {
1163 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1164 isolate, fun_data,
1165 isolate->factory()->ConfigureInstance(
1166 fun_data, Handle<JSObject>::cast(args.receiver())));
1167 }
1168
1169 SharedFunctionInfo* shared = function->shared();
1170 if (shared->strict_mode() == SLOPPY && !shared->native()) {
1171 Object* recv = args[0];
1172 ASSERT(!recv->IsNull());
1173 if (recv->IsUndefined()) {
1174 args[0] = function->context()->global_object()->global_receiver();
1175 }
1176 }
1177
1178 Object* raw_holder = TypeCheck(heap, args.length(), &args[0], *fun_data);
1179
1180 if (raw_holder->IsNull()) {
1181 // This function cannot be called with the given receiver. Abort!
1182 Handle<Object> obj =
1183 isolate->factory()->NewTypeError(
1184 "illegal_invocation", HandleVector(&function, 1));
1185 return isolate->Throw(*obj);
1186 }
1187
1188 Object* raw_call_data = fun_data->call_code();
1189 if (!raw_call_data->IsUndefined()) {
1190 CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
1191 Object* callback_obj = call_data->callback();
1192 v8::FunctionCallback callback =
1193 v8::ToCData<v8::FunctionCallback>(callback_obj);
1194 Object* data_obj = call_data->data();
1195 Object* result;
1196
1197 LOG(isolate, ApiObjectAccess("call", JSObject::cast(*args.receiver())));
1198 ASSERT(raw_holder->IsJSObject());
1199
1200 FunctionCallbackArguments custom(isolate,
1201 data_obj,
1202 *function,
1203 raw_holder,
1204 &args[0] - 1,
1205 args.length() - 1,
1206 is_construct);
1207
1208 v8::Handle<v8::Value> value = custom.Call(callback);
1209 if (value.IsEmpty()) {
1210 result = heap->undefined_value();
1211 } else {
1212 result = *reinterpret_cast<Object**>(*value);
1213 result->VerifyApiCallResultType();
1214 }
1215
1216 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
1217 if (!is_construct || result->IsJSObject()) return result;
1218 }
1219
1220 return *args.receiver();
1221 }
1222
1223
BUILTIN(HandleApiCall)1224 BUILTIN(HandleApiCall) {
1225 return HandleApiCallHelper<false>(args, isolate);
1226 }
1227
1228
BUILTIN(HandleApiCallConstruct)1229 BUILTIN(HandleApiCallConstruct) {
1230 return HandleApiCallHelper<true>(args, isolate);
1231 }
1232
1233
1234 // Helper function to handle calls to non-function objects created through the
1235 // API. The object can be called as either a constructor (using new) or just as
1236 // a function (without new).
HandleApiCallAsFunctionOrConstructor(Isolate * isolate,bool is_construct_call,BuiltinArguments<NO_EXTRA_ARGUMENTS> args)1237 MUST_USE_RESULT static Object* HandleApiCallAsFunctionOrConstructor(
1238 Isolate* isolate,
1239 bool is_construct_call,
1240 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
1241 // Non-functions are never called as constructors. Even if this is an object
1242 // called as a constructor the delegate call is not a construct call.
1243 ASSERT(!CalledAsConstructor(isolate));
1244 Heap* heap = isolate->heap();
1245
1246 Handle<Object> receiver = args.receiver();
1247
1248 // Get the object called.
1249 JSObject* obj = JSObject::cast(*receiver);
1250
1251 // Get the invocation callback from the function descriptor that was
1252 // used to create the called object.
1253 ASSERT(obj->map()->has_instance_call_handler());
1254 JSFunction* constructor = JSFunction::cast(obj->map()->constructor());
1255 ASSERT(constructor->shared()->IsApiFunction());
1256 Object* handler =
1257 constructor->shared()->get_api_func_data()->instance_call_handler();
1258 ASSERT(!handler->IsUndefined());
1259 CallHandlerInfo* call_data = CallHandlerInfo::cast(handler);
1260 Object* callback_obj = call_data->callback();
1261 v8::FunctionCallback callback =
1262 v8::ToCData<v8::FunctionCallback>(callback_obj);
1263
1264 // Get the data for the call and perform the callback.
1265 Object* result;
1266 {
1267 HandleScope scope(isolate);
1268 LOG(isolate, ApiObjectAccess("call non-function", obj));
1269
1270 FunctionCallbackArguments custom(isolate,
1271 call_data->data(),
1272 constructor,
1273 obj,
1274 &args[0] - 1,
1275 args.length() - 1,
1276 is_construct_call);
1277 v8::Handle<v8::Value> value = custom.Call(callback);
1278 if (value.IsEmpty()) {
1279 result = heap->undefined_value();
1280 } else {
1281 result = *reinterpret_cast<Object**>(*value);
1282 result->VerifyApiCallResultType();
1283 }
1284 }
1285 // Check for exceptions and return result.
1286 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
1287 return result;
1288 }
1289
1290
1291 // Handle calls to non-function objects created through the API. This delegate
1292 // function is used when the call is a normal function call.
BUILTIN(HandleApiCallAsFunction)1293 BUILTIN(HandleApiCallAsFunction) {
1294 return HandleApiCallAsFunctionOrConstructor(isolate, false, args);
1295 }
1296
1297
1298 // Handle calls to non-function objects created through the API. This delegate
1299 // function is used when the call is a construct call.
BUILTIN(HandleApiCallAsConstructor)1300 BUILTIN(HandleApiCallAsConstructor) {
1301 return HandleApiCallAsFunctionOrConstructor(isolate, true, args);
1302 }
1303
1304
Generate_LoadIC_Miss(MacroAssembler * masm)1305 static void Generate_LoadIC_Miss(MacroAssembler* masm) {
1306 LoadIC::GenerateMiss(masm);
1307 }
1308
1309
Generate_LoadIC_Normal(MacroAssembler * masm)1310 static void Generate_LoadIC_Normal(MacroAssembler* masm) {
1311 LoadIC::GenerateNormal(masm);
1312 }
1313
1314
Generate_LoadIC_Getter_ForDeopt(MacroAssembler * masm)1315 static void Generate_LoadIC_Getter_ForDeopt(MacroAssembler* masm) {
1316 LoadStubCompiler::GenerateLoadViaGetterForDeopt(masm);
1317 }
1318
1319
Generate_LoadIC_Slow(MacroAssembler * masm)1320 static void Generate_LoadIC_Slow(MacroAssembler* masm) {
1321 LoadIC::GenerateRuntimeGetProperty(masm);
1322 }
1323
1324
Generate_KeyedLoadIC_Initialize(MacroAssembler * masm)1325 static void Generate_KeyedLoadIC_Initialize(MacroAssembler* masm) {
1326 KeyedLoadIC::GenerateInitialize(masm);
1327 }
1328
1329
Generate_KeyedLoadIC_Slow(MacroAssembler * masm)1330 static void Generate_KeyedLoadIC_Slow(MacroAssembler* masm) {
1331 KeyedLoadIC::GenerateRuntimeGetProperty(masm);
1332 }
1333
1334
Generate_KeyedLoadIC_Miss(MacroAssembler * masm)1335 static void Generate_KeyedLoadIC_Miss(MacroAssembler* masm) {
1336 KeyedLoadIC::GenerateMiss(masm);
1337 }
1338
1339
Generate_KeyedLoadIC_Generic(MacroAssembler * masm)1340 static void Generate_KeyedLoadIC_Generic(MacroAssembler* masm) {
1341 KeyedLoadIC::GenerateGeneric(masm);
1342 }
1343
1344
Generate_KeyedLoadIC_String(MacroAssembler * masm)1345 static void Generate_KeyedLoadIC_String(MacroAssembler* masm) {
1346 KeyedLoadIC::GenerateString(masm);
1347 }
1348
1349
Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler * masm)1350 static void Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler* masm) {
1351 KeyedLoadIC::GeneratePreMonomorphic(masm);
1352 }
1353
1354
Generate_KeyedLoadIC_IndexedInterceptor(MacroAssembler * masm)1355 static void Generate_KeyedLoadIC_IndexedInterceptor(MacroAssembler* masm) {
1356 KeyedLoadIC::GenerateIndexedInterceptor(masm);
1357 }
1358
1359
Generate_KeyedLoadIC_SloppyArguments(MacroAssembler * masm)1360 static void Generate_KeyedLoadIC_SloppyArguments(MacroAssembler* masm) {
1361 KeyedLoadIC::GenerateSloppyArguments(masm);
1362 }
1363
1364
Generate_StoreIC_Slow(MacroAssembler * masm)1365 static void Generate_StoreIC_Slow(MacroAssembler* masm) {
1366 StoreIC::GenerateSlow(masm);
1367 }
1368
1369
Generate_StoreIC_Miss(MacroAssembler * masm)1370 static void Generate_StoreIC_Miss(MacroAssembler* masm) {
1371 StoreIC::GenerateMiss(masm);
1372 }
1373
1374
Generate_StoreIC_Normal(MacroAssembler * masm)1375 static void Generate_StoreIC_Normal(MacroAssembler* masm) {
1376 StoreIC::GenerateNormal(masm);
1377 }
1378
1379
Generate_StoreIC_Setter_ForDeopt(MacroAssembler * masm)1380 static void Generate_StoreIC_Setter_ForDeopt(MacroAssembler* masm) {
1381 StoreStubCompiler::GenerateStoreViaSetterForDeopt(masm);
1382 }
1383
1384
Generate_KeyedStoreIC_Generic(MacroAssembler * masm)1385 static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) {
1386 KeyedStoreIC::GenerateGeneric(masm, SLOPPY);
1387 }
1388
1389
Generate_KeyedStoreIC_Generic_Strict(MacroAssembler * masm)1390 static void Generate_KeyedStoreIC_Generic_Strict(MacroAssembler* masm) {
1391 KeyedStoreIC::GenerateGeneric(masm, STRICT);
1392 }
1393
1394
Generate_KeyedStoreIC_Miss(MacroAssembler * masm)1395 static void Generate_KeyedStoreIC_Miss(MacroAssembler* masm) {
1396 KeyedStoreIC::GenerateMiss(masm);
1397 }
1398
1399
Generate_KeyedStoreIC_Slow(MacroAssembler * masm)1400 static void Generate_KeyedStoreIC_Slow(MacroAssembler* masm) {
1401 KeyedStoreIC::GenerateSlow(masm);
1402 }
1403
1404
Generate_KeyedStoreIC_Initialize(MacroAssembler * masm)1405 static void Generate_KeyedStoreIC_Initialize(MacroAssembler* masm) {
1406 KeyedStoreIC::GenerateInitialize(masm);
1407 }
1408
1409
Generate_KeyedStoreIC_Initialize_Strict(MacroAssembler * masm)1410 static void Generate_KeyedStoreIC_Initialize_Strict(MacroAssembler* masm) {
1411 KeyedStoreIC::GenerateInitialize(masm);
1412 }
1413
1414
Generate_KeyedStoreIC_PreMonomorphic(MacroAssembler * masm)1415 static void Generate_KeyedStoreIC_PreMonomorphic(MacroAssembler* masm) {
1416 KeyedStoreIC::GeneratePreMonomorphic(masm);
1417 }
1418
1419
Generate_KeyedStoreIC_PreMonomorphic_Strict(MacroAssembler * masm)1420 static void Generate_KeyedStoreIC_PreMonomorphic_Strict(MacroAssembler* masm) {
1421 KeyedStoreIC::GeneratePreMonomorphic(masm);
1422 }
1423
1424
Generate_KeyedStoreIC_SloppyArguments(MacroAssembler * masm)1425 static void Generate_KeyedStoreIC_SloppyArguments(MacroAssembler* masm) {
1426 KeyedStoreIC::GenerateSloppyArguments(masm);
1427 }
1428
1429
Generate_CallICStub_DebugBreak(MacroAssembler * masm)1430 static void Generate_CallICStub_DebugBreak(MacroAssembler* masm) {
1431 DebugCodegen::GenerateCallICStubDebugBreak(masm);
1432 }
1433
1434
Generate_LoadIC_DebugBreak(MacroAssembler * masm)1435 static void Generate_LoadIC_DebugBreak(MacroAssembler* masm) {
1436 DebugCodegen::GenerateLoadICDebugBreak(masm);
1437 }
1438
1439
Generate_StoreIC_DebugBreak(MacroAssembler * masm)1440 static void Generate_StoreIC_DebugBreak(MacroAssembler* masm) {
1441 DebugCodegen::GenerateStoreICDebugBreak(masm);
1442 }
1443
1444
Generate_KeyedLoadIC_DebugBreak(MacroAssembler * masm)1445 static void Generate_KeyedLoadIC_DebugBreak(MacroAssembler* masm) {
1446 DebugCodegen::GenerateKeyedLoadICDebugBreak(masm);
1447 }
1448
1449
Generate_KeyedStoreIC_DebugBreak(MacroAssembler * masm)1450 static void Generate_KeyedStoreIC_DebugBreak(MacroAssembler* masm) {
1451 DebugCodegen::GenerateKeyedStoreICDebugBreak(masm);
1452 }
1453
1454
Generate_CompareNilIC_DebugBreak(MacroAssembler * masm)1455 static void Generate_CompareNilIC_DebugBreak(MacroAssembler* masm) {
1456 DebugCodegen::GenerateCompareNilICDebugBreak(masm);
1457 }
1458
1459
Generate_Return_DebugBreak(MacroAssembler * masm)1460 static void Generate_Return_DebugBreak(MacroAssembler* masm) {
1461 DebugCodegen::GenerateReturnDebugBreak(masm);
1462 }
1463
1464
Generate_CallFunctionStub_DebugBreak(MacroAssembler * masm)1465 static void Generate_CallFunctionStub_DebugBreak(MacroAssembler* masm) {
1466 DebugCodegen::GenerateCallFunctionStubDebugBreak(masm);
1467 }
1468
1469
Generate_CallConstructStub_DebugBreak(MacroAssembler * masm)1470 static void Generate_CallConstructStub_DebugBreak(MacroAssembler* masm) {
1471 DebugCodegen::GenerateCallConstructStubDebugBreak(masm);
1472 }
1473
1474
Generate_CallConstructStub_Recording_DebugBreak(MacroAssembler * masm)1475 static void Generate_CallConstructStub_Recording_DebugBreak(
1476 MacroAssembler* masm) {
1477 DebugCodegen::GenerateCallConstructStubRecordDebugBreak(masm);
1478 }
1479
1480
Generate_Slot_DebugBreak(MacroAssembler * masm)1481 static void Generate_Slot_DebugBreak(MacroAssembler* masm) {
1482 DebugCodegen::GenerateSlotDebugBreak(masm);
1483 }
1484
1485
Generate_PlainReturn_LiveEdit(MacroAssembler * masm)1486 static void Generate_PlainReturn_LiveEdit(MacroAssembler* masm) {
1487 DebugCodegen::GeneratePlainReturnLiveEdit(masm);
1488 }
1489
1490
Generate_FrameDropper_LiveEdit(MacroAssembler * masm)1491 static void Generate_FrameDropper_LiveEdit(MacroAssembler* masm) {
1492 DebugCodegen::GenerateFrameDropperLiveEdit(masm);
1493 }
1494
1495
Builtins()1496 Builtins::Builtins() : initialized_(false) {
1497 memset(builtins_, 0, sizeof(builtins_[0]) * builtin_count);
1498 memset(names_, 0, sizeof(names_[0]) * builtin_count);
1499 }
1500
1501
~Builtins()1502 Builtins::~Builtins() {
1503 }
1504
1505
1506 #define DEF_ENUM_C(name, ignore) FUNCTION_ADDR(Builtin_##name),
1507 Address const Builtins::c_functions_[cfunction_count] = {
1508 BUILTIN_LIST_C(DEF_ENUM_C)
1509 };
1510 #undef DEF_ENUM_C
1511
1512 #define DEF_JS_NAME(name, ignore) #name,
1513 #define DEF_JS_ARGC(ignore, argc) argc,
1514 const char* const Builtins::javascript_names_[id_count] = {
1515 BUILTINS_LIST_JS(DEF_JS_NAME)
1516 };
1517
1518 int const Builtins::javascript_argc_[id_count] = {
1519 BUILTINS_LIST_JS(DEF_JS_ARGC)
1520 };
1521 #undef DEF_JS_NAME
1522 #undef DEF_JS_ARGC
1523
1524 struct BuiltinDesc {
1525 byte* generator;
1526 byte* c_code;
1527 const char* s_name; // name is only used for generating log information.
1528 int name;
1529 Code::Flags flags;
1530 BuiltinExtraArguments extra_args;
1531 };
1532
1533 #define BUILTIN_FUNCTION_TABLE_INIT { V8_ONCE_INIT, {} }
1534
1535 class BuiltinFunctionTable {
1536 public:
functions()1537 BuiltinDesc* functions() {
1538 base::CallOnce(&once_, &Builtins::InitBuiltinFunctionTable);
1539 return functions_;
1540 }
1541
1542 base::OnceType once_;
1543 BuiltinDesc functions_[Builtins::builtin_count + 1];
1544
1545 friend class Builtins;
1546 };
1547
1548 static BuiltinFunctionTable builtin_function_table =
1549 BUILTIN_FUNCTION_TABLE_INIT;
1550
1551 // Define array of pointers to generators and C builtin functions.
1552 // We do this in a sort of roundabout way so that we can do the initialization
1553 // within the lexical scope of Builtins:: and within a context where
1554 // Code::Flags names a non-abstract type.
InitBuiltinFunctionTable()1555 void Builtins::InitBuiltinFunctionTable() {
1556 BuiltinDesc* functions = builtin_function_table.functions_;
1557 functions[builtin_count].generator = NULL;
1558 functions[builtin_count].c_code = NULL;
1559 functions[builtin_count].s_name = NULL;
1560 functions[builtin_count].name = builtin_count;
1561 functions[builtin_count].flags = static_cast<Code::Flags>(0);
1562 functions[builtin_count].extra_args = NO_EXTRA_ARGUMENTS;
1563
1564 #define DEF_FUNCTION_PTR_C(aname, aextra_args) \
1565 functions->generator = FUNCTION_ADDR(Generate_Adaptor); \
1566 functions->c_code = FUNCTION_ADDR(Builtin_##aname); \
1567 functions->s_name = #aname; \
1568 functions->name = c_##aname; \
1569 functions->flags = Code::ComputeFlags(Code::BUILTIN); \
1570 functions->extra_args = aextra_args; \
1571 ++functions;
1572
1573 #define DEF_FUNCTION_PTR_A(aname, kind, state, extra) \
1574 functions->generator = FUNCTION_ADDR(Generate_##aname); \
1575 functions->c_code = NULL; \
1576 functions->s_name = #aname; \
1577 functions->name = k##aname; \
1578 functions->flags = Code::ComputeFlags(Code::kind, \
1579 state, \
1580 extra); \
1581 functions->extra_args = NO_EXTRA_ARGUMENTS; \
1582 ++functions;
1583
1584 #define DEF_FUNCTION_PTR_H(aname, kind) \
1585 functions->generator = FUNCTION_ADDR(Generate_##aname); \
1586 functions->c_code = NULL; \
1587 functions->s_name = #aname; \
1588 functions->name = k##aname; \
1589 functions->flags = Code::ComputeHandlerFlags(Code::kind); \
1590 functions->extra_args = NO_EXTRA_ARGUMENTS; \
1591 ++functions;
1592
1593 BUILTIN_LIST_C(DEF_FUNCTION_PTR_C)
1594 BUILTIN_LIST_A(DEF_FUNCTION_PTR_A)
1595 BUILTIN_LIST_H(DEF_FUNCTION_PTR_H)
1596 BUILTIN_LIST_DEBUG_A(DEF_FUNCTION_PTR_A)
1597
1598 #undef DEF_FUNCTION_PTR_C
1599 #undef DEF_FUNCTION_PTR_A
1600 }
1601
1602
SetUp(Isolate * isolate,bool create_heap_objects)1603 void Builtins::SetUp(Isolate* isolate, bool create_heap_objects) {
1604 ASSERT(!initialized_);
1605
1606 // Create a scope for the handles in the builtins.
1607 HandleScope scope(isolate);
1608
1609 const BuiltinDesc* functions = builtin_function_table.functions();
1610
1611 // For now we generate builtin adaptor code into a stack-allocated
1612 // buffer, before copying it into individual code objects. Be careful
1613 // with alignment, some platforms don't like unaligned code.
1614 #ifdef DEBUG
1615 // We can generate a lot of debug code on Arm64.
1616 const size_t buffer_size = 32*KB;
1617 #else
1618 const size_t buffer_size = 8*KB;
1619 #endif
1620 union { int force_alignment; byte buffer[buffer_size]; } u;
1621
1622 // Traverse the list of builtins and generate an adaptor in a
1623 // separate code object for each one.
1624 for (int i = 0; i < builtin_count; i++) {
1625 if (create_heap_objects) {
1626 MacroAssembler masm(isolate, u.buffer, sizeof u.buffer);
1627 // Generate the code/adaptor.
1628 typedef void (*Generator)(MacroAssembler*, int, BuiltinExtraArguments);
1629 Generator g = FUNCTION_CAST<Generator>(functions[i].generator);
1630 // We pass all arguments to the generator, but it may not use all of
1631 // them. This works because the first arguments are on top of the
1632 // stack.
1633 ASSERT(!masm.has_frame());
1634 g(&masm, functions[i].name, functions[i].extra_args);
1635 // Move the code into the object heap.
1636 CodeDesc desc;
1637 masm.GetCode(&desc);
1638 Code::Flags flags = functions[i].flags;
1639 Handle<Code> code =
1640 isolate->factory()->NewCode(desc, flags, masm.CodeObject());
1641 // Log the event and add the code to the builtins array.
1642 PROFILE(isolate,
1643 CodeCreateEvent(Logger::BUILTIN_TAG, *code, functions[i].s_name));
1644 GDBJIT(AddCode(GDBJITInterface::BUILTIN, functions[i].s_name, *code));
1645 builtins_[i] = *code;
1646 #ifdef ENABLE_DISASSEMBLER
1647 if (FLAG_print_builtin_code) {
1648 CodeTracer::Scope trace_scope(isolate->GetCodeTracer());
1649 PrintF(trace_scope.file(), "Builtin: %s\n", functions[i].s_name);
1650 code->Disassemble(functions[i].s_name, trace_scope.file());
1651 PrintF(trace_scope.file(), "\n");
1652 }
1653 #endif
1654 } else {
1655 // Deserializing. The values will be filled in during IterateBuiltins.
1656 builtins_[i] = NULL;
1657 }
1658 names_[i] = functions[i].s_name;
1659 }
1660
1661 // Mark as initialized.
1662 initialized_ = true;
1663 }
1664
1665
TearDown()1666 void Builtins::TearDown() {
1667 initialized_ = false;
1668 }
1669
1670
IterateBuiltins(ObjectVisitor * v)1671 void Builtins::IterateBuiltins(ObjectVisitor* v) {
1672 v->VisitPointers(&builtins_[0], &builtins_[0] + builtin_count);
1673 }
1674
1675
Lookup(byte * pc)1676 const char* Builtins::Lookup(byte* pc) {
1677 // may be called during initialization (disassembler!)
1678 if (initialized_) {
1679 for (int i = 0; i < builtin_count; i++) {
1680 Code* entry = Code::cast(builtins_[i]);
1681 if (entry->contains(pc)) {
1682 return names_[i];
1683 }
1684 }
1685 }
1686 return NULL;
1687 }
1688
1689
Generate_InterruptCheck(MacroAssembler * masm)1690 void Builtins::Generate_InterruptCheck(MacroAssembler* masm) {
1691 masm->TailCallRuntime(Runtime::kHiddenInterrupt, 0, 1);
1692 }
1693
1694
Generate_StackCheck(MacroAssembler * masm)1695 void Builtins::Generate_StackCheck(MacroAssembler* masm) {
1696 masm->TailCallRuntime(Runtime::kHiddenStackGuard, 0, 1);
1697 }
1698
1699
1700 #define DEFINE_BUILTIN_ACCESSOR_C(name, ignore) \
1701 Handle<Code> Builtins::name() { \
1702 Code** code_address = \
1703 reinterpret_cast<Code**>(builtin_address(k##name)); \
1704 return Handle<Code>(code_address); \
1705 }
1706 #define DEFINE_BUILTIN_ACCESSOR_A(name, kind, state, extra) \
1707 Handle<Code> Builtins::name() { \
1708 Code** code_address = \
1709 reinterpret_cast<Code**>(builtin_address(k##name)); \
1710 return Handle<Code>(code_address); \
1711 }
1712 #define DEFINE_BUILTIN_ACCESSOR_H(name, kind) \
1713 Handle<Code> Builtins::name() { \
1714 Code** code_address = \
1715 reinterpret_cast<Code**>(builtin_address(k##name)); \
1716 return Handle<Code>(code_address); \
1717 }
1718 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C)
1719 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A)
1720 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H)
1721 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A)
1722 #undef DEFINE_BUILTIN_ACCESSOR_C
1723 #undef DEFINE_BUILTIN_ACCESSOR_A
1724
1725
1726 } } // namespace v8::internal
1727