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