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