builtins.cc 80.3 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5
#include "src/builtins.h"
6

7
#include "src/api.h"
8
#include "src/api-natives.h"
9
#include "src/arguments.h"
10
#include "src/base/once.h"
11
#include "src/bootstrapper.h"
12
#include "src/elements.h"
13
#include "src/frames-inl.h"
14
#include "src/gdb-jit.h"
15
#include "src/ic/handler-compiler.h"
16
#include "src/ic/ic.h"
17
#include "src/isolate-inl.h"
18
#include "src/messages.h"
19
#include "src/profiler/cpu-profiler.h"
20
#include "src/property-descriptor.h"
21
#include "src/prototype.h"
22
#include "src/vm-state-inl.h"
23

24 25
namespace v8 {
namespace internal {
26

27 28 29 30 31 32
namespace {

// Arguments object passed to C++ builtins.
template <BuiltinExtraArguments extra_args>
class BuiltinArguments : public Arguments {
 public:
vitalyr@chromium.org's avatar
vitalyr@chromium.org committed
33 34 35
  BuiltinArguments(int length, Object** arguments)
      : Arguments(length, arguments) { }

36
  Object*& operator[] (int index) {
37
    DCHECK(index < length());
38 39 40 41
    return Arguments::operator[](index);
  }

  template <class S> Handle<S> at(int index) {
42
    DCHECK(index < length());
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
    return Arguments::at<S>(index);
  }

  Handle<Object> receiver() {
    return Arguments::at<Object>(0);
  }

  Handle<JSFunction> called_function() {
    STATIC_ASSERT(extra_args == NEEDS_CALLED_FUNCTION);
    return Arguments::at<JSFunction>(Arguments::length() - 1);
  }

  // Gets the total number of arguments including the receiver (but
  // excluding extra arguments).
  int length() const {
    STATIC_ASSERT(extra_args == NO_EXTRA_ARGUMENTS);
    return Arguments::length();
  }

#ifdef DEBUG
  void Verify() {
    // Check we have at least the receiver.
65
    DCHECK(Arguments::length() >= 1);
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
  }
#endif
};


// Specialize BuiltinArguments for the called function extra argument.

template <>
int BuiltinArguments<NEEDS_CALLED_FUNCTION>::length() const {
  return Arguments::length() - 1;
}

#ifdef DEBUG
template <>
void BuiltinArguments<NEEDS_CALLED_FUNCTION>::Verify() {
  // Check we have at least the receiver and the called function.
82
  DCHECK(Arguments::length() >= 2);
83 84 85 86 87 88 89 90 91 92 93 94
  // Make sure cast to JSFunction succeeds.
  called_function();
}
#endif


#define DEF_ARG_TYPE(name, spec)                      \
  typedef BuiltinArguments<spec> name##ArgumentsType;
BUILTIN_LIST_C(DEF_ARG_TYPE)
#undef DEF_ARG_TYPE


95
// ----------------------------------------------------------------------------
96
// Support macro for defining builtins in C++.
97 98 99 100
// ----------------------------------------------------------------------------
//
// A builtin function is defined by writing:
//
101
//   BUILTIN(name) {
102 103 104
//     ...
//   }
//
105 106
// In the body of the builtin function the arguments can be accessed
// through the BuiltinArguments object args.
107

108
#ifdef DEBUG
109

110
#define BUILTIN(name)                                            \
111
  MUST_USE_RESULT static Object* Builtin_Impl_##name(            \
112
      name##ArgumentsType args, Isolate* isolate);               \
113
  MUST_USE_RESULT static Object* Builtin_##name(                 \
114 115 116 117 118
      int args_length, Object** args_object, Isolate* isolate) { \
    name##ArgumentsType args(args_length, args_object);          \
    args.Verify();                                               \
    return Builtin_Impl_##name(args, isolate);                   \
  }                                                              \
119
  MUST_USE_RESULT static Object* Builtin_Impl_##name(            \
120
      name##ArgumentsType args, Isolate* isolate)
121

122
#else  // For release mode.
123

124
#define BUILTIN(name)                                            \
125
  static Object* Builtin_impl##name(                             \
126
      name##ArgumentsType args, Isolate* isolate);               \
127
  static Object* Builtin_##name(                                 \
128 129 130 131
      int args_length, Object** args_object, Isolate* isolate) { \
    name##ArgumentsType args(args_length, args_object);          \
    return Builtin_impl##name(args, isolate);                    \
  }                                                              \
132
  static Object* Builtin_impl##name(                             \
133
      name##ArgumentsType args, Isolate* isolate)
134
#endif
135 136


137
#ifdef DEBUG
138
inline bool CalledAsConstructor(Isolate* isolate) {
139 140 141
  // Calculate the result using a full stack frame iterator and check
  // that the state of the stack is as we assume it to be in the
  // code below.
142
  StackFrameIterator it(isolate);
143
  DCHECK(it.frame()->is_exit());
144 145
  it.Advance();
  StackFrame* frame = it.frame();
146
  bool reference_result = frame->is_construct();
147
  Address fp = Isolate::c_entry_fp(isolate->thread_local_top());
148 149 150 151 152 153 154 155 156 157 158 159
  // Because we know fp points to an exit frame we can use the relevant
  // part of ExitFrame::ComputeCallerState directly.
  const int kCallerOffset = ExitFrameConstants::kCallerFPOffset;
  Address caller_fp = Memory::Address_at(fp + kCallerOffset);
  // This inlines the part of StackFrame::ComputeType that grabs the
  // type of the current frame.  Note that StackFrame::ComputeType
  // has been specialized for each architecture so if any one of them
  // changes this code has to be changed as well.
  const int kMarkerOffset = StandardFrameConstants::kMarkerOffset;
  const Smi* kConstructMarker = Smi::FromInt(StackFrame::CONSTRUCT);
  Object* marker = Memory::Object_at(caller_fp + kMarkerOffset);
  bool result = (marker == kConstructMarker);
160
  DCHECK_EQ(result, reference_result);
161
  return result;
162
}
163
#endif
164

165

166 167 168
// ----------------------------------------------------------------------------


169
inline bool ClampedToInteger(Object* object, int* out) {
170 171 172 173 174 175
  // This is an extended version of ECMA-262 7.1.11 handling signed values
  // Try to convert object to a number and clamp values to [kMinInt, kMaxInt]
  if (object->IsSmi()) {
    *out = Smi::cast(object)->value();
    return true;
  } else if (object->IsHeapNumber()) {
176 177 178 179 180 181 182 183 184 185
    double value = HeapNumber::cast(object)->value();
    if (std::isnan(value)) {
      *out = 0;
    } else if (value > kMaxInt) {
      *out = kMaxInt;
    } else if (value < kMinInt) {
      *out = kMinInt;
    } else {
      *out = static_cast<int>(value);
    }
186
    return true;
187
  } else if (object->IsUndefined() || object->IsNull()) {
188 189 190 191 192 193 194
    *out = 0;
    return true;
  } else if (object->IsBoolean()) {
    *out = object->IsTrue();
    return true;
  }
  return false;
195 196 197
}


198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
inline bool GetSloppyArgumentsLength(Isolate* isolate, Handle<JSObject> object,
                                     int* out) {
  Map* arguments_map =
      isolate->context()->native_context()->sloppy_arguments_map();
  if (object->map() != arguments_map || !object->HasFastElements()) {
    return false;
  }
  Object* len_obj = object->InObjectPropertyAt(Heap::kArgumentsLengthIndex);
  if (!len_obj->IsSmi()) {
    return false;
  }
  *out = Smi::cast(len_obj)->value();
  return *out <= object->elements()->length();
}


cbruni's avatar
cbruni committed
214
inline bool PrototypeHasNoElements(PrototypeIterator* iter) {
215
  DisallowHeapAllocation no_gc;
216 217
  for (; !iter->IsAtEnd(); iter->Advance()) {
    if (iter->GetCurrent()->IsJSProxy()) return false;
218
    JSObject* current = iter->GetCurrent<JSObject>();
219 220 221
    if (current->IsAccessCheckNeeded()) return false;
    if (current->HasIndexedInterceptor()) return false;
    if (current->elements()->length() != 0) return false;
222 223
  }
  return true;
224 225 226
}


227 228
inline bool IsJSArrayFastElementMovingAllowed(Isolate* isolate,
                                              JSArray* receiver) {
229
  DisallowHeapAllocation no_gc;
230 231 232 233
  // If the array prototype chain is intact (and free of elements), and if the
  // receiver's prototype is the array prototype, then we are done.
  Object* prototype = receiver->map()->prototype();
  if (prototype->IsJSArray() &&
234 235
      isolate->is_initial_array_prototype(JSArray::cast(prototype)) &&
      isolate->IsFastArrayConstructorPrototypeChainIntact()) {
236 237 238 239 240
    return true;
  }

  // Slow case.
  PrototypeIterator iter(isolate, receiver);
241
  return PrototypeHasNoElements(&iter);
242 243 244
}


245
// Returns empty handle if not applicable.
246
MUST_USE_RESULT
247 248
inline MaybeHandle<FixedArrayBase> EnsureJSArrayWithWritableFastElements(
    Isolate* isolate, Handle<Object> receiver, Arguments* args,
249
    int first_added_arg) {
250
  if (!receiver->IsJSArray()) return MaybeHandle<FixedArrayBase>();
251
  Handle<JSArray> array = Handle<JSArray>::cast(receiver);
252
  // If there may be elements accessors in the prototype chain, the fast path
253
  // cannot be used if there arguments to add to the array.
254
  Heap* heap = isolate->heap();
255
  if (args != NULL && !IsJSArrayFastElementMovingAllowed(isolate, *array)) {
256 257
    return MaybeHandle<FixedArrayBase>();
  }
258 259
  if (array->map()->is_observed()) return MaybeHandle<FixedArrayBase>();
  if (!array->map()->is_extensible()) return MaybeHandle<FixedArrayBase>();
260
  Handle<FixedArrayBase> elms(array->elements(), isolate);
261 262
  Map* map = elms->map();
  if (map == heap->fixed_array_map()) {
263
    if (args == NULL || array->HasFastObjectElements()) return elms;
264
  } else if (map == heap->fixed_cow_array_map()) {
265 266
    elms = JSObject::EnsureWritableFastElements(array);
    if (args == NULL || array->HasFastObjectElements()) return elms;
267 268
  } else if (map == heap->fixed_double_array_map()) {
    if (args == NULL) return elms;
269
  } else {
270
    return MaybeHandle<FixedArrayBase>();
271
  }
272

273 274
  // Adding elements to the array prototype would break code that makes sure
  // it has no elements. Handle that elsewhere.
275
  if (isolate->IsAnyInitialArrayPrototype(array)) {
276 277 278
    return MaybeHandle<FixedArrayBase>();
  }

279 280 281
  // Need to ensure that the arguments passed in args can be contained in
  // the array.
  int args_length = args->length();
282
  if (first_added_arg >= args_length) return handle(array->elements(), isolate);
283

284
  ElementsKind origin_kind = array->map()->elements_kind();
285
  DCHECK(!IsFastObjectElementsKind(origin_kind));
286
  ElementsKind target_kind = origin_kind;
287 288
  {
    DisallowHeapAllocation no_gc;
289
    int arg_count = args_length - first_added_arg;
290 291 292 293 294 295 296 297 298 299
    Object** arguments = args->arguments() - first_added_arg - (arg_count - 1);
    for (int i = 0; i < arg_count; i++) {
      Object* arg = arguments[i];
      if (arg->IsHeapObject()) {
        if (arg->IsHeapNumber()) {
          target_kind = FAST_DOUBLE_ELEMENTS;
        } else {
          target_kind = FAST_ELEMENTS;
          break;
        }
300 301 302 303
      }
    }
  }
  if (target_kind != origin_kind) {
304
    JSObject::TransitionElementsKind(array, target_kind);
305
    return handle(array->elements(), isolate);
306 307
  }
  return elms;
308 309 310
}


311 312
MUST_USE_RESULT static Object* CallJsIntrinsic(
    Isolate* isolate, Handle<JSFunction> function,
313
    BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
314
  HandleScope handleScope(isolate);
315 316 317 318
  int argc = args.length() - 1;
  ScopedVector<Handle<Object> > argv(argc);
  for (int i = 0; i < argc; ++i) {
    argv[i] = args.at<Object>(i + 1);
319
  }
320 321 322 323 324 325 326 327
  Handle<Object> result;
  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
      isolate, result,
      Execution::Call(isolate,
                      function,
                      args.receiver(),
                      argc,
                      argv.start()));
328 329 330 331
  return *result;
}


332 333 334 335 336 337 338 339 340 341 342 343
}  // namespace


BUILTIN(Illegal) {
  UNREACHABLE();
  return isolate->heap()->undefined_value();  // Make compiler happy.
}


BUILTIN(EmptyFunction) { return isolate->heap()->undefined_value(); }


344
BUILTIN(ArrayPush) {
345 346
  HandleScope scope(isolate);
  Handle<Object> receiver = args.receiver();
347
  MaybeHandle<FixedArrayBase> maybe_elms_obj =
348
      EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1);
349 350
  Handle<FixedArrayBase> elms_obj;
  if (!maybe_elms_obj.ToHandle(&elms_obj)) {
351
    return CallJsIntrinsic(isolate, isolate->array_push(), args);
352
  }
353 354
  // Fast Elements Path
  int push_size = args.length() - 1;
355
  Handle<JSArray> array = Handle<JSArray>::cast(receiver);
356
  int len = Smi::cast(array->length())->value();
357 358 359 360 361
  if (push_size == 0) {
    return Smi::FromInt(len);
  }
  if (push_size > 0 &&
      JSArray::WouldChangeReadOnlyLength(array, len + push_size)) {
362
    return CallJsIntrinsic(isolate, isolate->array_push(), args);
363
  }
364
  DCHECK(!array->map()->is_observed());
365
  ElementsAccessor* accessor = array->GetElementsAccessor();
366
  int new_length = accessor->Push(array, elms_obj, &args, push_size);
367
  return Smi::FromInt(new_length);
368 369 370
}


371
BUILTIN(ArrayPop) {
372 373
  HandleScope scope(isolate);
  Handle<Object> receiver = args.receiver();
374
  MaybeHandle<FixedArrayBase> maybe_elms_obj =
375
      EnsureJSArrayWithWritableFastElements(isolate, receiver, NULL, 0);
376 377
  Handle<FixedArrayBase> elms_obj;
  if (!maybe_elms_obj.ToHandle(&elms_obj)) {
378
    return CallJsIntrinsic(isolate, isolate->array_pop(), args);
379
  }
380 381

  Handle<JSArray> array = Handle<JSArray>::cast(receiver);
382
  DCHECK(!array->map()->is_observed());
383

384
  uint32_t len = static_cast<uint32_t>(Smi::cast(array->length())->value());
385
  if (len == 0) return isolate->heap()->undefined_value();
386

387
  if (JSArray::HasReadOnlyLength(array)) {
388
    return CallJsIntrinsic(isolate, isolate->array_pop(), args);
389 390
  }

cbruni's avatar
cbruni committed
391 392 393 394 395 396 397 398 399 400 401 402
  Handle<Object> result;
  if (IsJSArrayFastElementMovingAllowed(isolate, JSArray::cast(*receiver))) {
    // Fast Elements Path
    result = array->GetElementsAccessor()->Pop(array, elms_obj);
  } else {
    // Use Slow Lookup otherwise
    uint32_t new_length = len - 1;
    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
        isolate, result, Object::GetElement(isolate, array, new_length));
    JSArray::SetLength(array, new_length);
  }
  return *result;
403 404 405
}


406
BUILTIN(ArrayShift) {
407
  HandleScope scope(isolate);
408
  Heap* heap = isolate->heap();
409
  Handle<Object> receiver = args.receiver();
410
  MaybeHandle<FixedArrayBase> maybe_elms_obj =
411
      EnsureJSArrayWithWritableFastElements(isolate, receiver, NULL, 0);
412 413
  Handle<FixedArrayBase> elms_obj;
  if (!maybe_elms_obj.ToHandle(&elms_obj) ||
414
      !IsJSArrayFastElementMovingAllowed(isolate, JSArray::cast(*receiver))) {
415
    return CallJsIntrinsic(isolate, isolate->array_shift(), args);
416
  }
417
  Handle<JSArray> array = Handle<JSArray>::cast(receiver);
418
  DCHECK(!array->map()->is_observed());
419

420
  int len = Smi::cast(array->length())->value();
421
  if (len == 0) return heap->undefined_value();
422

423
  if (JSArray::HasReadOnlyLength(array)) {
424
    return CallJsIntrinsic(isolate, isolate->array_shift(), args);
425 426
  }

427
  Handle<Object> first = array->GetElementsAccessor()->Shift(array, elms_obj);
428
  return *first;
429 430 431
}


432
BUILTIN(ArrayUnshift) {
433 434
  HandleScope scope(isolate);
  Handle<Object> receiver = args.receiver();
435
  MaybeHandle<FixedArrayBase> maybe_elms_obj =
436
      EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1);
437
  Handle<FixedArrayBase> elms_obj;
438
  if (!maybe_elms_obj.ToHandle(&elms_obj)) {
439
    return CallJsIntrinsic(isolate, isolate->array_unshift(), args);
440
  }
441
  Handle<JSArray> array = Handle<JSArray>::cast(receiver);
442
  DCHECK(!array->map()->is_observed());
443
  int to_add = args.length() - 1;
444 445 446
  if (to_add == 0) {
    return array->length();
  }
447 448
  // Currently fixed arrays cannot grow too big, so
  // we should never hit this case.
449
  DCHECK(to_add <= (Smi::kMaxValue - Smi::cast(array->length())->value()));
450

451
  if (to_add > 0 && JSArray::HasReadOnlyLength(array)) {
452
    return CallJsIntrinsic(isolate, isolate->array_unshift(), args);
453 454
  }

455 456
  ElementsAccessor* accessor = array->GetElementsAccessor();
  int new_length = accessor->Unshift(array, elms_obj, &args, to_add);
457 458 459 460
  return Smi::FromInt(new_length);
}


461
BUILTIN(ArraySlice) {
462 463
  HandleScope scope(isolate);
  Handle<Object> receiver = args.receiver();
464 465
  Handle<JSObject> object;
  Handle<FixedArrayBase> elms_obj;
466
  int len = -1;
467 468
  int relative_start = 0;
  int relative_end = 0;
469
  bool is_sloppy_arguments = false;
470

471 472 473 474 475 476 477
  if (receiver->IsJSArray()) {
    DisallowHeapAllocation no_gc;
    JSArray* array = JSArray::cast(*receiver);
    if (!array->HasFastElements() ||
        !IsJSArrayFastElementMovingAllowed(isolate, array)) {
      AllowHeapAllocation allow_allocation;
      return CallJsIntrinsic(isolate, isolate->array_slice(), args);
478
    }
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513
    len = Smi::cast(array->length())->value();
    object = Handle<JSObject>::cast(receiver);
    elms_obj = handle(array->elements(), isolate);
  } else if (receiver->IsJSObject() &&
             GetSloppyArgumentsLength(isolate, Handle<JSObject>::cast(receiver),
                                      &len)) {
    // Array.prototype.slice(arguments, ...) is quite a common idiom
    // (notably more than 50% of invocations in Web apps).
    // Treat it in C++ as well.
    is_sloppy_arguments = true;
    object = Handle<JSObject>::cast(receiver);
    elms_obj = handle(object->elements(), isolate);
  } else {
    AllowHeapAllocation allow_allocation;
    return CallJsIntrinsic(isolate, isolate->array_slice(), args);
  }
  DCHECK(len >= 0);
  int argument_count = args.length() - 1;
  // Note carefully chosen defaults---if argument is missing,
  // it's undefined which gets converted to 0 for relative_start
  // and to len for relative_end.
  relative_start = 0;
  relative_end = len;
  if (argument_count > 0) {
    DisallowHeapAllocation no_gc;
    if (!ClampedToInteger(args[1], &relative_start)) {
      AllowHeapAllocation allow_allocation;
      return CallJsIntrinsic(isolate, isolate->array_slice(), args);
    }
    if (argument_count > 1) {
      Object* end_arg = args[2];
      // slice handles the end_arg specially
      if (end_arg->IsUndefined()) {
        relative_end = len;
      } else if (!ClampedToInteger(end_arg, &relative_end)) {
514
        AllowHeapAllocation allow_allocation;
515
        return CallJsIntrinsic(isolate, isolate->array_slice(), args);
516 517 518 519 520
      }
    }
  }

  // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6.
521 522
  uint32_t actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
                                               : Min(relative_start, len);
523 524

  // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8.
525 526
  uint32_t actual_end =
      (relative_end < 0) ? Max(len + relative_end, 0) : Min(relative_end, len);
527

528
  if (actual_end <= actual_start) {
529 530
    Handle<JSArray> result_array = isolate->factory()->NewJSArray(
        GetPackedElementsKind(object->GetElementsKind()), 0, 0);
531 532 533
    return *result_array;
  }

534 535 536 537 538 539
  ElementsAccessor* accessor = object->GetElementsAccessor();
  if (is_sloppy_arguments &&
      !accessor->IsPacked(object, elms_obj, actual_start, actual_end)) {
    // Don't deal with arguments with holes in C++
    AllowHeapAllocation allow_allocation;
    return CallJsIntrinsic(isolate, isolate->array_slice(), args);
540
  }
541
  Handle<JSArray> result_array =
542
      accessor->Slice(object, elms_obj, actual_start, actual_end);
543
  return *result_array;
544 545 546
}


547
BUILTIN(ArraySplice) {
548 549
  HandleScope scope(isolate);
  Handle<Object> receiver = args.receiver();
550
  MaybeHandle<FixedArrayBase> maybe_elms_obj =
551
      EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3);
552
  Handle<FixedArrayBase> elms_obj;
553
  if (!maybe_elms_obj.ToHandle(&elms_obj)) {
554
    return CallJsIntrinsic(isolate, isolate->array_splice(), args);
555
  }
556
  Handle<JSArray> array = Handle<JSArray>::cast(receiver);
557
  DCHECK(!array->map()->is_observed());
558

559
  int argument_count = args.length() - 1;
560
  int relative_start = 0;
561
  if (argument_count > 0) {
562
    DisallowHeapAllocation no_gc;
563
    if (!ClampedToInteger(args[1], &relative_start)) {
564
      AllowHeapAllocation allow_allocation;
565
      return CallJsIntrinsic(isolate, isolate->array_splice(), args);
566
    }
567
  }
568 569
  int len = Smi::cast(array->length())->value();
  // clip relative start to [0, len]
570 571
  int actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
                                          : Min(relative_start, len);
572

573
  int actual_delete_count;
574 575 576 577 578
  if (argument_count == 1) {
    // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
    // given as a request to delete all the elements from the start.
    // And it differs from the case of undefined delete count.
    // This does not follow ECMA-262, but we do the same for compatibility.
579
    DCHECK(len - actual_start >= 0);
580 581
    actual_delete_count = len - actual_start;
  } else {
582 583 584 585
    int delete_count = 0;
    DisallowHeapAllocation no_gc;
    if (argument_count > 1) {
      if (!ClampedToInteger(args[2], &delete_count)) {
586
        AllowHeapAllocation allow_allocation;
587
        return CallJsIntrinsic(isolate, isolate->array_splice(), args);
588
      }
589
    }
590
    actual_delete_count = Min(Max(delete_count, 0), len - actual_start);
591 592
  }

593 594
  int add_count = (argument_count > 1) ? (argument_count - 2) : 0;
  int new_length = len - actual_delete_count + add_count;
595

596 597
  if (new_length != len && JSArray::HasReadOnlyLength(array)) {
    AllowHeapAllocation allow_allocation;
598
    return CallJsIntrinsic(isolate, isolate->array_splice(), args);
599
  }
600
  ElementsAccessor* accessor = array->GetElementsAccessor();
601
  Handle<JSArray> result_array = accessor->Splice(
602
      array, elms_obj, actual_start, actual_delete_count, &args, add_count);
603
  return *result_array;
604 605 606
}


607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955
// Array Concat -------------------------------------------------------------

namespace {

/**
 * A simple visitor visits every element of Array's.
 * The backend storage can be a fixed array for fast elements case,
 * or a dictionary for sparse array. Since Dictionary is a subtype
 * of FixedArray, the class can be used by both fast and slow cases.
 * The second parameter of the constructor, fast_elements, specifies
 * whether the storage is a FixedArray or Dictionary.
 *
 * An index limit is used to deal with the situation that a result array
 * length overflows 32-bit non-negative integer.
 */
class ArrayConcatVisitor {
 public:
  ArrayConcatVisitor(Isolate* isolate, Handle<FixedArray> storage,
                     bool fast_elements)
      : isolate_(isolate),
        storage_(Handle<FixedArray>::cast(
            isolate->global_handles()->Create(*storage))),
        index_offset_(0u),
        bit_field_(FastElementsField::encode(fast_elements) |
                   ExceedsLimitField::encode(false)) {}

  ~ArrayConcatVisitor() { clear_storage(); }

  void visit(uint32_t i, Handle<Object> elm) {
    if (i >= JSObject::kMaxElementCount - index_offset_) {
      set_exceeds_array_limit(true);
      return;
    }
    uint32_t index = index_offset_ + i;

    if (fast_elements()) {
      if (index < static_cast<uint32_t>(storage_->length())) {
        storage_->set(index, *elm);
        return;
      }
      // Our initial estimate of length was foiled, possibly by
      // getters on the arrays increasing the length of later arrays
      // during iteration.
      // This shouldn't happen in anything but pathological cases.
      SetDictionaryMode();
      // Fall-through to dictionary mode.
    }
    DCHECK(!fast_elements());
    Handle<SeededNumberDictionary> dict(
        SeededNumberDictionary::cast(*storage_));
    // The object holding this backing store has just been allocated, so
    // it cannot yet be used as a prototype.
    Handle<SeededNumberDictionary> result =
        SeededNumberDictionary::AtNumberPut(dict, index, elm, false);
    if (!result.is_identical_to(dict)) {
      // Dictionary needed to grow.
      clear_storage();
      set_storage(*result);
    }
  }

  void increase_index_offset(uint32_t delta) {
    if (JSObject::kMaxElementCount - index_offset_ < delta) {
      index_offset_ = JSObject::kMaxElementCount;
    } else {
      index_offset_ += delta;
    }
    // If the initial length estimate was off (see special case in visit()),
    // but the array blowing the limit didn't contain elements beyond the
    // provided-for index range, go to dictionary mode now.
    if (fast_elements() &&
        index_offset_ >
            static_cast<uint32_t>(FixedArrayBase::cast(*storage_)->length())) {
      SetDictionaryMode();
    }
  }

  bool exceeds_array_limit() const {
    return ExceedsLimitField::decode(bit_field_);
  }

  Handle<JSArray> ToArray() {
    Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
    Handle<Object> length =
        isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
    Handle<Map> map = JSObject::GetElementsTransitionMap(
        array, fast_elements() ? FAST_HOLEY_ELEMENTS : DICTIONARY_ELEMENTS);
    array->set_map(*map);
    array->set_length(*length);
    array->set_elements(*storage_);
    return array;
  }

 private:
  // Convert storage to dictionary mode.
  void SetDictionaryMode() {
    DCHECK(fast_elements());
    Handle<FixedArray> current_storage(*storage_);
    Handle<SeededNumberDictionary> slow_storage(
        SeededNumberDictionary::New(isolate_, current_storage->length()));
    uint32_t current_length = static_cast<uint32_t>(current_storage->length());
    for (uint32_t i = 0; i < current_length; i++) {
      HandleScope loop_scope(isolate_);
      Handle<Object> element(current_storage->get(i), isolate_);
      if (!element->IsTheHole()) {
        // The object holding this backing store has just been allocated, so
        // it cannot yet be used as a prototype.
        Handle<SeededNumberDictionary> new_storage =
            SeededNumberDictionary::AtNumberPut(slow_storage, i, element,
                                                false);
        if (!new_storage.is_identical_to(slow_storage)) {
          slow_storage = loop_scope.CloseAndEscape(new_storage);
        }
      }
    }
    clear_storage();
    set_storage(*slow_storage);
    set_fast_elements(false);
  }

  inline void clear_storage() {
    GlobalHandles::Destroy(Handle<Object>::cast(storage_).location());
  }

  inline void set_storage(FixedArray* storage) {
    storage_ =
        Handle<FixedArray>::cast(isolate_->global_handles()->Create(storage));
  }

  class FastElementsField : public BitField<bool, 0, 1> {};
  class ExceedsLimitField : public BitField<bool, 1, 1> {};

  bool fast_elements() const { return FastElementsField::decode(bit_field_); }
  void set_fast_elements(bool fast) {
    bit_field_ = FastElementsField::update(bit_field_, fast);
  }
  void set_exceeds_array_limit(bool exceeds) {
    bit_field_ = ExceedsLimitField::update(bit_field_, exceeds);
  }

  Isolate* isolate_;
  Handle<FixedArray> storage_;  // Always a global handle.
  // Index after last seen index. Always less than or equal to
  // JSObject::kMaxElementCount.
  uint32_t index_offset_;
  uint32_t bit_field_;
};


uint32_t EstimateElementCount(Handle<JSArray> array) {
  uint32_t length = static_cast<uint32_t>(array->length()->Number());
  int element_count = 0;
  switch (array->GetElementsKind()) {
    case FAST_SMI_ELEMENTS:
    case FAST_HOLEY_SMI_ELEMENTS:
    case FAST_ELEMENTS:
    case FAST_HOLEY_ELEMENTS: {
      // Fast elements can't have lengths that are not representable by
      // a 32-bit signed integer.
      DCHECK(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
      int fast_length = static_cast<int>(length);
      Handle<FixedArray> elements(FixedArray::cast(array->elements()));
      for (int i = 0; i < fast_length; i++) {
        if (!elements->get(i)->IsTheHole()) element_count++;
      }
      break;
    }
    case FAST_DOUBLE_ELEMENTS:
    case FAST_HOLEY_DOUBLE_ELEMENTS: {
      // Fast elements can't have lengths that are not representable by
      // a 32-bit signed integer.
      DCHECK(static_cast<int32_t>(FixedDoubleArray::kMaxLength) >= 0);
      int fast_length = static_cast<int>(length);
      if (array->elements()->IsFixedArray()) {
        DCHECK(FixedArray::cast(array->elements())->length() == 0);
        break;
      }
      Handle<FixedDoubleArray> elements(
          FixedDoubleArray::cast(array->elements()));
      for (int i = 0; i < fast_length; i++) {
        if (!elements->is_the_hole(i)) element_count++;
      }
      break;
    }
    case DICTIONARY_ELEMENTS: {
      Handle<SeededNumberDictionary> dictionary(
          SeededNumberDictionary::cast(array->elements()));
      int capacity = dictionary->Capacity();
      for (int i = 0; i < capacity; i++) {
        Handle<Object> key(dictionary->KeyAt(i), array->GetIsolate());
        if (dictionary->IsKey(*key)) {
          element_count++;
        }
      }
      break;
    }
    case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
    case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS:

      TYPED_ARRAYS(TYPED_ARRAY_CASE)
#undef TYPED_ARRAY_CASE
      // External arrays are always dense.
      return length;
  }
  // As an estimate, we assume that the prototype doesn't contain any
  // inherited elements.
  return element_count;
}


template <class ExternalArrayClass, class ElementType>
void IterateTypedArrayElements(Isolate* isolate, Handle<JSObject> receiver,
                               bool elements_are_ints,
                               bool elements_are_guaranteed_smis,
                               ArrayConcatVisitor* visitor) {
  Handle<ExternalArrayClass> array(
      ExternalArrayClass::cast(receiver->elements()));
  uint32_t len = static_cast<uint32_t>(array->length());

  DCHECK(visitor != NULL);
  if (elements_are_ints) {
    if (elements_are_guaranteed_smis) {
      for (uint32_t j = 0; j < len; j++) {
        HandleScope loop_scope(isolate);
        Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))),
                      isolate);
        visitor->visit(j, e);
      }
    } else {
      for (uint32_t j = 0; j < len; j++) {
        HandleScope loop_scope(isolate);
        int64_t val = static_cast<int64_t>(array->get_scalar(j));
        if (Smi::IsValid(static_cast<intptr_t>(val))) {
          Handle<Smi> e(Smi::FromInt(static_cast<int>(val)), isolate);
          visitor->visit(j, e);
        } else {
          Handle<Object> e =
              isolate->factory()->NewNumber(static_cast<ElementType>(val));
          visitor->visit(j, e);
        }
      }
    }
  } else {
    for (uint32_t j = 0; j < len; j++) {
      HandleScope loop_scope(isolate);
      Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
      visitor->visit(j, e);
    }
  }
}


// Used for sorting indices in a List<uint32_t>.
int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
  uint32_t a = *ap;
  uint32_t b = *bp;
  return (a == b) ? 0 : (a < b) ? -1 : 1;
}


void CollectElementIndices(Handle<JSObject> object, uint32_t range,
                           List<uint32_t>* indices) {
  Isolate* isolate = object->GetIsolate();
  ElementsKind kind = object->GetElementsKind();
  switch (kind) {
    case FAST_SMI_ELEMENTS:
    case FAST_ELEMENTS:
    case FAST_HOLEY_SMI_ELEMENTS:
    case FAST_HOLEY_ELEMENTS: {
      Handle<FixedArray> elements(FixedArray::cast(object->elements()));
      uint32_t length = static_cast<uint32_t>(elements->length());
      if (range < length) length = range;
      for (uint32_t i = 0; i < length; i++) {
        if (!elements->get(i)->IsTheHole()) {
          indices->Add(i);
        }
      }
      break;
    }
    case FAST_HOLEY_DOUBLE_ELEMENTS:
    case FAST_DOUBLE_ELEMENTS: {
      if (object->elements()->IsFixedArray()) {
        DCHECK(object->elements()->length() == 0);
        break;
      }
      Handle<FixedDoubleArray> elements(
          FixedDoubleArray::cast(object->elements()));
      uint32_t length = static_cast<uint32_t>(elements->length());
      if (range < length) length = range;
      for (uint32_t i = 0; i < length; i++) {
        if (!elements->is_the_hole(i)) {
          indices->Add(i);
        }
      }
      break;
    }
    case DICTIONARY_ELEMENTS: {
      Handle<SeededNumberDictionary> dict(
          SeededNumberDictionary::cast(object->elements()));
      uint32_t capacity = dict->Capacity();
      for (uint32_t j = 0; j < capacity; j++) {
        HandleScope loop_scope(isolate);
        Handle<Object> k(dict->KeyAt(j), isolate);
        if (dict->IsKey(*k)) {
          DCHECK(k->IsNumber());
          uint32_t index = static_cast<uint32_t>(k->Number());
          if (index < range) {
            indices->Add(index);
          }
        }
      }
      break;
    }
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS:

      TYPED_ARRAYS(TYPED_ARRAY_CASE)
#undef TYPED_ARRAY_CASE
      {
        uint32_t length = static_cast<uint32_t>(
            FixedArrayBase::cast(object->elements())->length());
        if (range <= length) {
          length = range;
          // We will add all indices, so we might as well clear it first
          // and avoid duplicates.
          indices->Clear();
        }
        for (uint32_t i = 0; i < length; i++) {
          indices->Add(i);
        }
        if (length == range) return;  // All indices accounted for already.
        break;
      }
    case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
    case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
      ElementsAccessor* accessor = object->GetElementsAccessor();
      for (uint32_t i = 0; i < range; i++) {
        if (accessor->HasElement(object, i)) {
          indices->Add(i);
        }
      }
      break;
    }
  }

  PrototypeIterator iter(isolate, object);
  if (!iter.IsAtEnd()) {
    // The prototype will usually have no inherited element indices,
    // but we have to check.
956 957
    CollectElementIndices(PrototypeIterator::GetCurrent<JSObject>(iter), range,
                          indices);
958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993
  }
}


bool IterateElementsSlow(Isolate* isolate, Handle<JSObject> receiver,
                         uint32_t length, ArrayConcatVisitor* visitor) {
  for (uint32_t i = 0; i < length; ++i) {
    HandleScope loop_scope(isolate);
    Maybe<bool> maybe = JSReceiver::HasElement(receiver, i);
    if (!maybe.IsJust()) return false;
    if (maybe.FromJust()) {
      Handle<Object> element_value;
      ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_value,
                                       Object::GetElement(isolate, receiver, i),
                                       false);
      visitor->visit(i, element_value);
    }
  }
  visitor->increase_index_offset(length);
  return true;
}


/**
 * A helper function that visits elements of a JSObject in numerical
 * order.
 *
 * The visitor argument called for each existing element in the array
 * with the element index and the element's value.
 * Afterwards it increments the base-index of the visitor by the array
 * length.
 * Returns false if any access threw an exception, otherwise true.
 */
bool IterateElements(Isolate* isolate, Handle<JSObject> receiver,
                     ArrayConcatVisitor* visitor) {
  uint32_t length = 0;
994

995 996 997 998 999 1000 1001 1002 1003
  if (receiver->IsJSArray()) {
    Handle<JSArray> array(Handle<JSArray>::cast(receiver));
    length = static_cast<uint32_t>(array->length()->Number());
  } else {
    Handle<Object> val;
    Handle<Object> key(isolate->heap()->length_string(), isolate);
    ASSIGN_RETURN_ON_EXCEPTION_VALUE(
        isolate, val, Runtime::GetObjectProperty(isolate, receiver, key),
        false);
1004 1005
    ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, val,
                                     Object::ToLength(isolate, val), false);
1006 1007
    // TODO(caitp): Support larger element indexes (up to 2^53-1).
    if (!val->ToUint32(&length)) {
1008
      length = 0;
1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085
    }
  }

  if (!(receiver->IsJSArray() || receiver->IsJSTypedArray())) {
    // For classes which are not known to be safe to access via elements alone,
    // use the slow case.
    return IterateElementsSlow(isolate, receiver, length, visitor);
  }

  switch (receiver->GetElementsKind()) {
    case FAST_SMI_ELEMENTS:
    case FAST_ELEMENTS:
    case FAST_HOLEY_SMI_ELEMENTS:
    case FAST_HOLEY_ELEMENTS: {
      // Run through the elements FixedArray and use HasElement and GetElement
      // to check the prototype for missing elements.
      Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
      int fast_length = static_cast<int>(length);
      DCHECK(fast_length <= elements->length());
      for (int j = 0; j < fast_length; j++) {
        HandleScope loop_scope(isolate);
        Handle<Object> element_value(elements->get(j), isolate);
        if (!element_value->IsTheHole()) {
          visitor->visit(j, element_value);
        } else {
          Maybe<bool> maybe = JSReceiver::HasElement(receiver, j);
          if (!maybe.IsJust()) return false;
          if (maybe.FromJust()) {
            // Call GetElement on receiver, not its prototype, or getters won't
            // have the correct receiver.
            ASSIGN_RETURN_ON_EXCEPTION_VALUE(
                isolate, element_value,
                Object::GetElement(isolate, receiver, j), false);
            visitor->visit(j, element_value);
          }
        }
      }
      break;
    }
    case FAST_HOLEY_DOUBLE_ELEMENTS:
    case FAST_DOUBLE_ELEMENTS: {
      // Empty array is FixedArray but not FixedDoubleArray.
      if (length == 0) break;
      // Run through the elements FixedArray and use HasElement and GetElement
      // to check the prototype for missing elements.
      if (receiver->elements()->IsFixedArray()) {
        DCHECK(receiver->elements()->length() == 0);
        break;
      }
      Handle<FixedDoubleArray> elements(
          FixedDoubleArray::cast(receiver->elements()));
      int fast_length = static_cast<int>(length);
      DCHECK(fast_length <= elements->length());
      for (int j = 0; j < fast_length; j++) {
        HandleScope loop_scope(isolate);
        if (!elements->is_the_hole(j)) {
          double double_value = elements->get_scalar(j);
          Handle<Object> element_value =
              isolate->factory()->NewNumber(double_value);
          visitor->visit(j, element_value);
        } else {
          Maybe<bool> maybe = JSReceiver::HasElement(receiver, j);
          if (!maybe.IsJust()) return false;
          if (maybe.FromJust()) {
            // Call GetElement on receiver, not its prototype, or getters won't
            // have the correct receiver.
            Handle<Object> element_value;
            ASSIGN_RETURN_ON_EXCEPTION_VALUE(
                isolate, element_value,
                Object::GetElement(isolate, receiver, j), false);
            visitor->visit(j, element_value);
          }
        }
      }
      break;
    }
    case DICTIONARY_ELEMENTS: {
1086 1087 1088 1089 1090 1091 1092 1093
      // CollectElementIndices() can't be called when there's a JSProxy
      // on the prototype chain.
      for (PrototypeIterator iter(isolate, receiver); !iter.IsAtEnd();
           iter.Advance()) {
        if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
          return IterateElementsSlow(isolate, receiver, length, visitor);
        }
      }
1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238
      Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
      List<uint32_t> indices(dict->Capacity() / 2);
      // Collect all indices in the object and the prototypes less
      // than length. This might introduce duplicates in the indices list.
      CollectElementIndices(receiver, length, &indices);
      indices.Sort(&compareUInt32);
      int j = 0;
      int n = indices.length();
      while (j < n) {
        HandleScope loop_scope(isolate);
        uint32_t index = indices[j];
        Handle<Object> element;
        ASSIGN_RETURN_ON_EXCEPTION_VALUE(
            isolate, element, Object::GetElement(isolate, receiver, index),
            false);
        visitor->visit(index, element);
        // Skip to next different index (i.e., omit duplicates).
        do {
          j++;
        } while (j < n && indices[j] == index);
      }
      break;
    }
    case UINT8_CLAMPED_ELEMENTS: {
      Handle<FixedUint8ClampedArray> pixels(
          FixedUint8ClampedArray::cast(receiver->elements()));
      for (uint32_t j = 0; j < length; j++) {
        Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)), isolate);
        visitor->visit(j, e);
      }
      break;
    }
    case INT8_ELEMENTS: {
      IterateTypedArrayElements<FixedInt8Array, int8_t>(isolate, receiver, true,
                                                        true, visitor);
      break;
    }
    case UINT8_ELEMENTS: {
      IterateTypedArrayElements<FixedUint8Array, uint8_t>(isolate, receiver,
                                                          true, true, visitor);
      break;
    }
    case INT16_ELEMENTS: {
      IterateTypedArrayElements<FixedInt16Array, int16_t>(isolate, receiver,
                                                          true, true, visitor);
      break;
    }
    case UINT16_ELEMENTS: {
      IterateTypedArrayElements<FixedUint16Array, uint16_t>(
          isolate, receiver, true, true, visitor);
      break;
    }
    case INT32_ELEMENTS: {
      IterateTypedArrayElements<FixedInt32Array, int32_t>(isolate, receiver,
                                                          true, false, visitor);
      break;
    }
    case UINT32_ELEMENTS: {
      IterateTypedArrayElements<FixedUint32Array, uint32_t>(
          isolate, receiver, true, false, visitor);
      break;
    }
    case FLOAT32_ELEMENTS: {
      IterateTypedArrayElements<FixedFloat32Array, float>(
          isolate, receiver, false, false, visitor);
      break;
    }
    case FLOAT64_ELEMENTS: {
      IterateTypedArrayElements<FixedFloat64Array, double>(
          isolate, receiver, false, false, visitor);
      break;
    }
    case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
    case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
      for (uint32_t index = 0; index < length; index++) {
        HandleScope loop_scope(isolate);
        Handle<Object> element;
        ASSIGN_RETURN_ON_EXCEPTION_VALUE(
            isolate, element, Object::GetElement(isolate, receiver, index),
            false);
        visitor->visit(index, element);
      }
      break;
    }
  }
  visitor->increase_index_offset(length);
  return true;
}


bool HasConcatSpreadableModifier(Isolate* isolate, Handle<JSArray> obj) {
  if (!FLAG_harmony_concat_spreadable) return false;
  Handle<Symbol> key(isolate->factory()->is_concat_spreadable_symbol());
  Maybe<bool> maybe =
      JSReceiver::HasProperty(Handle<JSReceiver>::cast(obj), key);
  if (!maybe.IsJust()) return false;
  return maybe.FromJust();
}


bool IsConcatSpreadable(Isolate* isolate, Handle<Object> obj) {
  HandleScope handle_scope(isolate);
  if (!obj->IsSpecObject()) return false;
  if (FLAG_harmony_concat_spreadable) {
    Handle<Symbol> key(isolate->factory()->is_concat_spreadable_symbol());
    Handle<Object> value;
    MaybeHandle<Object> maybeValue =
        i::Runtime::GetObjectProperty(isolate, obj, key);
    if (maybeValue.ToHandle(&value) && !value->IsUndefined()) {
      return value->BooleanValue();
    }
  }
  return obj->IsJSArray();
}


/**
 * Array::concat implementation.
 * See ECMAScript 262, 15.4.4.4.
 * TODO(581): Fix non-compliance for very large concatenations and update to
 * following the ECMAScript 5 specification.
 */
Object* Slow_ArrayConcat(Arguments* args, Isolate* isolate) {
  int argument_count = args->length();

  // Pass 1: estimate the length and number of elements of the result.
  // The actual length can be larger if any of the arguments have getters
  // that mutate other arguments (but will otherwise be precise).
  // The number of elements is precise if there are no inherited elements.

  ElementsKind kind = FAST_SMI_ELEMENTS;

  uint32_t estimate_result_length = 0;
  uint32_t estimate_nof_elements = 0;
  for (int i = 0; i < argument_count; i++) {
    HandleScope loop_scope(isolate);
    Handle<Object> obj((*args)[i], isolate);
    uint32_t length_estimate;
    uint32_t element_estimate;
    if (obj->IsJSArray()) {
      Handle<JSArray> array(Handle<JSArray>::cast(obj));
      length_estimate = static_cast<uint32_t>(array->length()->Number());
      if (length_estimate != 0) {
        ElementsKind array_kind =
            GetPackedElementsKind(array->map()->elements_kind());
1239
        kind = GetMoreGeneralElementsKind(kind, array_kind);
1240 1241 1242 1243 1244
      }
      element_estimate = EstimateElementCount(array);
    } else {
      if (obj->IsHeapObject()) {
        if (obj->IsNumber()) {
1245 1246 1247
          kind = GetMoreGeneralElementsKind(kind, FAST_DOUBLE_ELEMENTS);
        } else {
          kind = GetMoreGeneralElementsKind(kind, FAST_ELEMENTS);
1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396
        }
      }
      length_estimate = 1;
      element_estimate = 1;
    }
    // Avoid overflows by capping at kMaxElementCount.
    if (JSObject::kMaxElementCount - estimate_result_length < length_estimate) {
      estimate_result_length = JSObject::kMaxElementCount;
    } else {
      estimate_result_length += length_estimate;
    }
    if (JSObject::kMaxElementCount - estimate_nof_elements < element_estimate) {
      estimate_nof_elements = JSObject::kMaxElementCount;
    } else {
      estimate_nof_elements += element_estimate;
    }
  }

  // If estimated number of elements is more than half of length, a
  // fixed array (fast case) is more time and space-efficient than a
  // dictionary.
  bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;

  if (fast_case && kind == FAST_DOUBLE_ELEMENTS) {
    Handle<FixedArrayBase> storage =
        isolate->factory()->NewFixedDoubleArray(estimate_result_length);
    int j = 0;
    bool failure = false;
    if (estimate_result_length > 0) {
      Handle<FixedDoubleArray> double_storage =
          Handle<FixedDoubleArray>::cast(storage);
      for (int i = 0; i < argument_count; i++) {
        Handle<Object> obj((*args)[i], isolate);
        if (obj->IsSmi()) {
          double_storage->set(j, Smi::cast(*obj)->value());
          j++;
        } else if (obj->IsNumber()) {
          double_storage->set(j, obj->Number());
          j++;
        } else {
          JSArray* array = JSArray::cast(*obj);
          uint32_t length = static_cast<uint32_t>(array->length()->Number());
          switch (array->map()->elements_kind()) {
            case FAST_HOLEY_DOUBLE_ELEMENTS:
            case FAST_DOUBLE_ELEMENTS: {
              // Empty array is FixedArray but not FixedDoubleArray.
              if (length == 0) break;
              FixedDoubleArray* elements =
                  FixedDoubleArray::cast(array->elements());
              for (uint32_t i = 0; i < length; i++) {
                if (elements->is_the_hole(i)) {
                  // TODO(jkummerow/verwaest): We could be a bit more clever
                  // here: Check if there are no elements/getters on the
                  // prototype chain, and if so, allow creation of a holey
                  // result array.
                  // Same thing below (holey smi case).
                  failure = true;
                  break;
                }
                double double_value = elements->get_scalar(i);
                double_storage->set(j, double_value);
                j++;
              }
              break;
            }
            case FAST_HOLEY_SMI_ELEMENTS:
            case FAST_SMI_ELEMENTS: {
              FixedArray* elements(FixedArray::cast(array->elements()));
              for (uint32_t i = 0; i < length; i++) {
                Object* element = elements->get(i);
                if (element->IsTheHole()) {
                  failure = true;
                  break;
                }
                int32_t int_value = Smi::cast(element)->value();
                double_storage->set(j, int_value);
                j++;
              }
              break;
            }
            case FAST_HOLEY_ELEMENTS:
            case FAST_ELEMENTS:
            case DICTIONARY_ELEMENTS:
              DCHECK_EQ(0u, length);
              break;
            default:
              UNREACHABLE();
          }
        }
        if (failure) break;
      }
    }
    if (!failure) {
      Handle<JSArray> array = isolate->factory()->NewJSArray(0);
      Smi* length = Smi::FromInt(j);
      Handle<Map> map;
      map = JSObject::GetElementsTransitionMap(array, kind);
      array->set_map(*map);
      array->set_length(length);
      array->set_elements(*storage);
      return *array;
    }
    // In case of failure, fall through.
  }

  Handle<FixedArray> storage;
  if (fast_case) {
    // The backing storage array must have non-existing elements to preserve
    // holes across concat operations.
    storage =
        isolate->factory()->NewFixedArrayWithHoles(estimate_result_length);
  } else {
    // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
    uint32_t at_least_space_for =
        estimate_nof_elements + (estimate_nof_elements >> 2);
    storage = Handle<FixedArray>::cast(
        SeededNumberDictionary::New(isolate, at_least_space_for));
  }

  ArrayConcatVisitor visitor(isolate, storage, fast_case);

  for (int i = 0; i < argument_count; i++) {
    Handle<Object> obj((*args)[i], isolate);
    bool spreadable = IsConcatSpreadable(isolate, obj);
    if (isolate->has_pending_exception()) return isolate->heap()->exception();
    if (spreadable) {
      Handle<JSObject> object = Handle<JSObject>::cast(obj);
      if (!IterateElements(isolate, object, &visitor)) {
        return isolate->heap()->exception();
      }
    } else {
      visitor.visit(0, obj);
      visitor.increase_index_offset(1);
    }
  }

  if (visitor.exceeds_array_limit()) {
    THROW_NEW_ERROR_RETURN_FAILURE(
        isolate, NewRangeError(MessageTemplate::kInvalidArrayLength));
  }
  return *visitor.ToArray();
}


MaybeHandle<JSArray> Fast_ArrayConcat(Isolate* isolate, Arguments* args) {
  if (!isolate->IsFastArrayConstructorPrototypeChainIntact()) {
    return MaybeHandle<JSArray>();
  }
  int n_arguments = args->length();
1397
  int result_len = 0;
1398
  {
1399
    DisallowHeapAllocation no_gc;
1400
    Object* array_proto = isolate->array_function()->prototype();
1401 1402 1403
    // Iterate through all the arguments performing checks
    // and calculating total length.
    for (int i = 0; i < n_arguments; i++) {
1404 1405 1406 1407
      Object* arg = (*args)[i];
      if (!arg->IsJSArray()) return MaybeHandle<JSArray>();
      Handle<JSArray> array(JSArray::cast(arg), isolate);
      if (!array->HasFastElements()) return MaybeHandle<JSArray>();
1408
      PrototypeIterator iter(isolate, arg);
1409 1410 1411
      if (iter.GetCurrent() != array_proto) return MaybeHandle<JSArray>();
      if (HasConcatSpreadableModifier(isolate, array)) {
        return MaybeHandle<JSArray>();
1412
      }
1413
      int len = Smi::cast(array->length())->value();
1414

1415 1416 1417 1418 1419
      // We shouldn't overflow when adding another len.
      const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
      STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt);
      USE(kHalfOfMaxInt);
      result_len += len;
1420
      DCHECK(result_len >= 0);
1421 1422 1423 1424 1425
      // Throw an Error if we overflow the FixedArray limits
      if (FixedArray::kMaxLength < result_len) {
        THROW_NEW_ERROR(isolate,
                        NewRangeError(MessageTemplate::kInvalidArrayLength),
                        JSArray);
1426
      }
1427
    }
1428
  }
1429 1430
  return ElementsAccessor::Concat(isolate, args, n_arguments);
}
1431

1432
}  // namespace
1433

1434 1435
BUILTIN(ArrayConcat) {
  HandleScope scope(isolate);
1436

1437 1438 1439 1440 1441 1442 1443 1444 1445
  Handle<Object> receiver;
  if (!Object::ToObject(isolate, handle(args[0], isolate))
           .ToHandle(&receiver)) {
    THROW_NEW_ERROR_RETURN_FAILURE(
        isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
                              isolate->factory()->NewStringFromAsciiChecked(
                                  "Array.prototype.concat")));
  }
  args[0] = *receiver;
1446

1447 1448 1449 1450 1451 1452
  Handle<JSArray> result_array;
  if (Fast_ArrayConcat(isolate, &args).ToHandle(&result_array)) {
    return *result_array;
  }
  if (isolate->has_pending_exception()) return isolate->heap()->exception();
  return Slow_ArrayConcat(&args, isolate);
1453 1454 1455
}


1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488
// ES6 section 26.1.3 Reflect.defineProperty
BUILTIN(ReflectDefineProperty) {
  HandleScope scope(isolate);
  DCHECK_EQ(4, args.length());
  Handle<Object> target = args.at<Object>(1);
  Handle<Object> key = args.at<Object>(2);
  Handle<Object> attributes = args.at<Object>(3);

  if (!target->IsJSReceiver()) {
    THROW_NEW_ERROR_RETURN_FAILURE(
        isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
                              isolate->factory()->NewStringFromAsciiChecked(
                                  "Reflect.defineProperty")));
  }

  Handle<Name> name;
  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
                                     Object::ToName(isolate, key));

  PropertyDescriptor desc;
  if (!PropertyDescriptor::ToPropertyDescriptor(isolate, attributes, &desc)) {
    return isolate->heap()->exception();
  }

  bool result =
      JSReceiver::DefineOwnProperty(isolate, Handle<JSReceiver>::cast(target),
                                    name, &desc, Object::DONT_THROW);
  if (isolate->has_pending_exception()) return isolate->heap()->exception();
  // TODO(neis): Make DefineOwnProperty return Maybe<bool>.
  return *isolate->factory()->ToBoolean(result);
}


1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518
// ES6 section 26.1.4 Reflect.deleteProperty
BUILTIN(ReflectDeleteProperty) {
  HandleScope scope(isolate);
  DCHECK_EQ(3, args.length());
  Handle<Object> target = args.at<Object>(1);
  Handle<Object> key = args.at<Object>(2);

  if (!target->IsJSReceiver()) {
    THROW_NEW_ERROR_RETURN_FAILURE(
        isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
                              isolate->factory()->NewStringFromAsciiChecked(
                                  "Reflect.deleteProperty")));
  }

  Handle<Name> name;
  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
                                     Object::ToName(isolate, key));

  Handle<Object> result;
  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
      isolate, result, JSReceiver::DeletePropertyOrElement(
                           Handle<JSReceiver>::cast(target), name));

  return *result;
}


// ES6 section 26.1.6 Reflect.get
BUILTIN(ReflectGet) {
  HandleScope scope(isolate);
1519 1520 1521 1522
  Handle<Object> undef = isolate->factory()->undefined_value();
  Handle<Object> target = args.length() > 1 ? args.at<Object>(1) : undef;
  Handle<Object> key = args.length() > 2 ? args.at<Object>(2) : undef;
  Handle<Object> receiver = args.length() > 3 ? args.at<Object>(3) : target;
1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536

  if (!target->IsJSReceiver()) {
    THROW_NEW_ERROR_RETURN_FAILURE(
        isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
                              isolate->factory()->NewStringFromAsciiChecked(
                                  "Reflect.get")));
  }

  Handle<Name> name;
  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
                                     Object::ToName(isolate, key));

  Handle<Object> result;
  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1537 1538
      isolate, result, Object::GetPropertyOrElement(
          Handle<JSReceiver>::cast(target), name, receiver));
1539 1540 1541 1542 1543

  return *result;
}


1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570
// ES6 section 26.1.7 Reflect.getOwnPropertyDescriptor
BUILTIN(ReflectGetOwnPropertyDescriptor) {
  HandleScope scope(isolate);
  DCHECK_EQ(3, args.length());
  Handle<Object> target = args.at<Object>(1);
  Handle<Object> key = args.at<Object>(2);

  if (!target->IsJSReceiver()) {
    THROW_NEW_ERROR_RETURN_FAILURE(
        isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
                              isolate->factory()->NewStringFromAsciiChecked(
                                  "Reflect.getOwnPropertyDescriptor")));
  }

  Handle<Name> name;
  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
                                     Object::ToName(isolate, key));

  PropertyDescriptor desc;
  bool found = JSReceiver::GetOwnPropertyDescriptor(
      isolate, Handle<JSReceiver>::cast(target), name, &desc);
  if (isolate->has_pending_exception()) return isolate->heap()->exception();
  if (!found) return isolate->heap()->undefined_value();
  return *desc.ToObject(isolate);
}


1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587
// ES6 section 26.1.8 Reflect.getPrototypeOf
BUILTIN(ReflectGetPrototypeOf) {
  HandleScope scope(isolate);
  DCHECK_EQ(2, args.length());
  Handle<Object> target = args.at<Object>(1);

  if (!target->IsJSReceiver()) {
    THROW_NEW_ERROR_RETURN_FAILURE(
        isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
                              isolate->factory()->NewStringFromAsciiChecked(
                                  "Reflect.getPrototypeOf")));
  }

  return *Object::GetPrototype(isolate, target);
}


1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605
// ES6 section 26.1.9 Reflect.has
BUILTIN(ReflectHas) {
  HandleScope scope(isolate);
  DCHECK_EQ(3, args.length());
  Handle<Object> target = args.at<Object>(1);
  Handle<Object> key = args.at<Object>(2);

  if (!target->IsJSReceiver()) {
    THROW_NEW_ERROR_RETURN_FAILURE(
        isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
                              isolate->factory()->NewStringFromAsciiChecked(
                                  "Reflect.has")));
  }

  Handle<Name> name;
  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
                                     Object::ToName(isolate, key));

1606
  Maybe<bool> result =
1607
      JSReceiver::HasProperty(Handle<JSReceiver>::cast(target), name);
1608 1609
  return result.IsJust() ? *isolate->factory()->ToBoolean(result.FromJust())
                         : isolate->heap()->exception();
1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642
}


// ES6 section 26.1.10 Reflect.isExtensible
BUILTIN(ReflectIsExtensible) {
  HandleScope scope(isolate);
  DCHECK_EQ(2, args.length());
  Handle<Object> target = args.at<Object>(1);

  if (!target->IsJSReceiver()) {
    THROW_NEW_ERROR_RETURN_FAILURE(
        isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
                              isolate->factory()->NewStringFromAsciiChecked(
                                  "Reflect.isExtensible")));
  }

  // TODO(neis): For now, we ignore proxies.  Once proxies are fully
  // implemented, do something like the following:
  /*
  Maybe<bool> maybe = JSReceiver::IsExtensible(
      Handle<JSReceiver>::cast(target));
  if (!maybe.IsJust()) return isolate->heap()->exception();
  return *isolate->factory()->ToBoolean(maybe.FromJust());
  */

  if (target->IsJSObject()) {
    return *isolate->factory()->ToBoolean(
        JSObject::IsExtensible(Handle<JSObject>::cast(target)));
  }
  return *isolate->factory()->false_value();
}


1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656
// ES6 section 26.1.12 Reflect.preventExtensions
BUILTIN(ReflectPreventExtensions) {
  HandleScope scope(isolate);
  DCHECK_EQ(2, args.length());
  Handle<Object> target = args.at<Object>(1);

  if (!target->IsJSReceiver()) {
    THROW_NEW_ERROR_RETURN_FAILURE(
        isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
                              isolate->factory()->NewStringFromAsciiChecked(
                                  "Reflect.preventExtensions")));
  }

  Maybe<bool> result = JSReceiver::PreventExtensions(
1657
      Handle<JSReceiver>::cast(target), Object::DONT_THROW);
1658 1659 1660 1661 1662
  return result.IsJust() ? *isolate->factory()->ToBoolean(result.FromJust())
                         : isolate->heap()->exception();
}


1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691
// ES6 section 26.1.13 Reflect.set
BUILTIN(ReflectSet) {
  HandleScope scope(isolate);
  Handle<Object> undef = isolate->factory()->undefined_value();
  Handle<Object> target = args.length() > 1 ? args.at<Object>(1) : undef;
  Handle<Object> key = args.length() > 2 ? args.at<Object>(2) : undef;
  Handle<Object> value = args.length() > 3 ? args.at<Object>(3) : undef;
  Handle<Object> receiver = args.length() > 4 ? args.at<Object>(4) : target;

  if (!target->IsJSReceiver()) {
    THROW_NEW_ERROR_RETURN_FAILURE(
        isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
                              isolate->factory()->NewStringFromAsciiChecked(
                                  "Reflect.set")));
  }

  Handle<Name> name;
  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
                                     Object::ToName(isolate, key));

  LookupIterator it = LookupIterator::PropertyOrElement(
      isolate, receiver, name, Handle<JSReceiver>::cast(target));
  Maybe<bool> result = Object::SetSuperProperty(
      &it, value, SLOPPY, Object::MAY_BE_STORE_FROM_KEYED);
  MAYBE_RETURN(result, isolate->heap()->exception());
  return *isolate->factory()->ToBoolean(result.FromJust());
}


1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711
// ES6 section 26.1.14 Reflect.setPrototypeOf
BUILTIN(ReflectSetPrototypeOf) {
  HandleScope scope(isolate);
  DCHECK_EQ(3, args.length());
  Handle<Object> target = args.at<Object>(1);
  Handle<Object> proto = args.at<Object>(2);

  if (!target->IsJSReceiver()) {
    THROW_NEW_ERROR_RETURN_FAILURE(
        isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
                              isolate->factory()->NewStringFromAsciiChecked(
                                  "Reflect.setPrototypeOf")));
  }

  if (!proto->IsJSReceiver() && !proto->IsNull()) {
    THROW_NEW_ERROR_RETURN_FAILURE(
        isolate, NewTypeError(MessageTemplate::kProtoObjectOrNull, proto));
  }

  Maybe<bool> result = JSReceiver::SetPrototype(
1712
      Handle<JSReceiver>::cast(target), proto, true, Object::DONT_THROW);
1713 1714 1715 1716 1717
  MAYBE_RETURN(result, isolate->heap()->exception());
  return *isolate->factory()->ToBoolean(result.FromJust());
}


1718
// ES6 section 20.3.4.45 Date.prototype [ @@toPrimitive ] ( hint )
1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737
BUILTIN(DateToPrimitive) {
  HandleScope scope(isolate);
  DCHECK_EQ(2, args.length());
  if (!args.receiver()->IsJSReceiver()) {
    THROW_NEW_ERROR_RETURN_FAILURE(
        isolate, NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
                              isolate->factory()->NewStringFromAsciiChecked(
                                  "Date.prototype [ @@toPrimitive ]"),
                              args.receiver()));
  }
  Handle<JSReceiver> receiver = args.at<JSReceiver>(0);
  Handle<Object> hint = args.at<Object>(1);
  Handle<Object> result;
  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
                                     JSDate::ToPrimitive(receiver, hint));
  return *result;
}


1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761
// ES6 section 19.4.1.1 Symbol ( [ description ] ) for the [[Call]] case.
BUILTIN(SymbolConstructor) {
  HandleScope scope(isolate);
  DCHECK_EQ(2, args.length());
  Handle<Symbol> result = isolate->factory()->NewSymbol();
  Handle<Object> description = args.at<Object>(1);
  if (!description->IsUndefined()) {
    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, description,
                                       Object::ToString(isolate, description));
    result->set_name(*description);
  }
  return *result;
}


// ES6 section 19.4.1.1 Symbol ( [ description ] ) for the [[Construct]] case.
BUILTIN(SymbolConstructor_ConstructStub) {
  HandleScope scope(isolate);
  THROW_NEW_ERROR_RETURN_FAILURE(
      isolate, NewTypeError(MessageTemplate::kNotConstructor,
                            isolate->factory()->Symbol_string()));
}


1762
// -----------------------------------------------------------------------------
1763 1764
// Throwers for restricted function properties and strict arguments object
// properties
1765 1766


1767
BUILTIN(RestrictedFunctionPropertiesThrower) {
1768
  HandleScope scope(isolate);
1769 1770
  THROW_NEW_ERROR_RETURN_FAILURE(
      isolate, NewTypeError(MessageTemplate::kRestrictedFunctionProperties));
1771 1772
}

1773

1774
BUILTIN(RestrictedStrictArgumentsPropertiesThrower) {
1775
  HandleScope scope(isolate);
1776
  THROW_NEW_ERROR_RETURN_FAILURE(
1777
      isolate, NewTypeError(MessageTemplate::kStrictPoisonPill));
1778 1779 1780
}


1781 1782 1783 1784
// -----------------------------------------------------------------------------
//


1785
template <bool is_construct>
1786 1787
MUST_USE_RESULT static MaybeHandle<Object> HandleApiCallHelper(
    Isolate* isolate, BuiltinArguments<NEEDS_CALLED_FUNCTION>& args) {
1788
  HandleScope scope(isolate);
1789
  Handle<JSFunction> function = args.called_function();
1790 1791
  // TODO(ishell): turn this back to a DCHECK.
  CHECK(function->shared()->IsApiFunction());
1792

1793 1794
  Handle<FunctionTemplateInfo> fun_data(
      function->shared()->get_api_func_data(), isolate);
1795
  if (is_construct) {
1796
    ASSIGN_RETURN_ON_EXCEPTION(
1797
        isolate, fun_data,
1798 1799
        ApiNatives::ConfigureInstance(isolate, fun_data,
                                      Handle<JSObject>::cast(args.receiver())),
1800
        Object);
1801 1802
  }

dcarney's avatar
dcarney committed
1803 1804
  DCHECK(!args[0]->IsNull());
  if (args[0]->IsUndefined()) args[0] = function->global_proxy();
1805

1806 1807 1808 1809
  if (!is_construct && !fun_data->accept_any_receiver()) {
    Handle<Object> receiver(&args[0]);
    if (receiver->IsJSObject() && receiver->IsAccessCheckNeeded()) {
      Handle<JSObject> js_receiver = Handle<JSObject>::cast(receiver);
1810
      if (!isolate->MayAccess(handle(isolate->context()), js_receiver)) {
1811 1812 1813 1814 1815 1816
        isolate->ReportFailedAccessCheck(js_receiver);
        RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
      }
    }
  }

1817
  Object* raw_holder = fun_data->GetCompatibleReceiver(isolate, args[0]);
1818 1819 1820

  if (raw_holder->IsNull()) {
    // This function cannot be called with the given receiver.  Abort!
1821 1822
    THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIllegalInvocation),
                    Object);
1823 1824 1825 1826
  }

  Object* raw_call_data = fun_data->call_code();
  if (!raw_call_data->IsUndefined()) {
1827 1828
    // TODO(ishell): remove this debugging code.
    CHECK(raw_call_data->IsCallHandlerInfo());
1829 1830
    CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
    Object* callback_obj = call_data->callback();
1831 1832
    v8::FunctionCallback callback =
        v8::ToCData<v8::FunctionCallback>(callback_obj);
1833 1834
    Object* data_obj = call_data->data();

1835
    LOG(isolate, ApiObjectAccess("call", JSObject::cast(*args.receiver())));
1836
    DCHECK(raw_holder->IsJSObject());
1837

1838 1839 1840 1841 1842 1843
    FunctionCallbackArguments custom(isolate,
                                     data_obj,
                                     *function,
                                     raw_holder,
                                     &args[0] - 1,
                                     args.length() - 1,
1844
                                     is_construct);
1845

1846
    v8::Local<v8::Value> value = custom.Call(callback);
1847
    Handle<Object> result;
1848
    if (value.IsEmpty()) {
1849
      result = isolate->factory()->undefined_value();
1850
    } else {
1851
      result = v8::Utils::OpenHandle(*value);
1852
      result->VerifyApiCallResultType();
1853 1854
    }

1855 1856 1857 1858
    RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
    if (!is_construct || result->IsJSObject()) {
      return scope.CloseAndEscape(result);
    }
1859 1860
  }

1861
  return scope.CloseAndEscape(args.receiver());
1862 1863 1864 1865
}


BUILTIN(HandleApiCall) {
1866 1867 1868 1869 1870 1871
  HandleScope scope(isolate);
  DCHECK(!CalledAsConstructor(isolate));
  Handle<Object> result;
  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
                                     HandleApiCallHelper<false>(isolate, args));
  return *result;
1872 1873 1874 1875
}


BUILTIN(HandleApiCallConstruct) {
1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933
  HandleScope scope(isolate);
  DCHECK(CalledAsConstructor(isolate));
  Handle<Object> result;
  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
                                     HandleApiCallHelper<true>(isolate, args));
  return *result;
}


namespace {

class RelocatableArguments : public BuiltinArguments<NEEDS_CALLED_FUNCTION>,
                             public Relocatable {
 public:
  RelocatableArguments(Isolate* isolate, int length, Object** arguments)
      : BuiltinArguments<NEEDS_CALLED_FUNCTION>(length, arguments),
        Relocatable(isolate) {}

  virtual inline void IterateInstance(ObjectVisitor* v) {
    if (length() == 0) return;
    v->VisitPointers(lowest_address(), highest_address() + 1);
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(RelocatableArguments);
};

}  // namespace


MaybeHandle<Object> Builtins::InvokeApiFunction(Handle<JSFunction> function,
                                                Handle<Object> receiver,
                                                int argc,
                                                Handle<Object> args[]) {
  // Construct BuiltinArguments object: function, arguments reversed, receiver.
  const int kBufferSize = 32;
  Object* small_argv[kBufferSize];
  Object** argv;
  if (argc + 2 <= kBufferSize) {
    argv = small_argv;
  } else {
    argv = new Object* [argc + 2];
  }
  argv[argc + 1] = *receiver;
  for (int i = 0; i < argc; ++i) {
    argv[argc - i] = *args[i];
  }
  argv[0] = *function;
  MaybeHandle<Object> result;
  {
    auto isolate = function->GetIsolate();
    RelocatableArguments arguments(isolate, argc + 2, &argv[argc + 1]);
    result = HandleApiCallHelper<false>(isolate, arguments);
  }
  if (argv != small_argv) {
    delete[] argv;
  }
  return result;
1934 1935 1936
}


1937 1938 1939
// Helper function to handle calls to non-function objects created through the
// API. The object can be called as either a constructor (using new) or just as
// a function (without new).
1940
MUST_USE_RESULT static Object* HandleApiCallAsFunctionOrConstructor(
1941
    Isolate* isolate,
1942 1943
    bool is_construct_call,
    BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
1944 1945
  // Non-functions are never called as constructors. Even if this is an object
  // called as a constructor the delegate call is not a construct call.
1946
  DCHECK(!CalledAsConstructor(isolate));
1947
  Heap* heap = isolate->heap();
1948

1949
  Handle<Object> receiver = args.receiver();
1950

1951
  // Get the object called.
1952
  JSObject* obj = JSObject::cast(*receiver);
1953 1954 1955

  // Get the invocation callback from the function descriptor that was
  // used to create the called object.
1956
  DCHECK(obj->map()->is_callable());
1957
  JSFunction* constructor = JSFunction::cast(obj->map()->GetConstructor());
1958 1959
  // TODO(ishell): turn this back to a DCHECK.
  CHECK(constructor->shared()->IsApiFunction());
1960
  Object* handler =
1961
      constructor->shared()->get_api_func_data()->instance_call_handler();
1962
  DCHECK(!handler->IsUndefined());
1963 1964
  // TODO(ishell): remove this debugging code.
  CHECK(handler->IsCallHandlerInfo());
1965 1966
  CallHandlerInfo* call_data = CallHandlerInfo::cast(handler);
  Object* callback_obj = call_data->callback();
1967 1968
  v8::FunctionCallback callback =
      v8::ToCData<v8::FunctionCallback>(callback_obj);
1969 1970 1971

  // Get the data for the call and perform the callback.
  Object* result;
1972
  {
1973 1974
    HandleScope scope(isolate);
    LOG(isolate, ApiObjectAccess("call non-function", obj));
1975

1976 1977 1978 1979 1980 1981 1982
    FunctionCallbackArguments custom(isolate,
                                     call_data->data(),
                                     constructor,
                                     obj,
                                     &args[0] - 1,
                                     args.length() - 1,
                                     is_construct_call);
1983
    v8::Local<v8::Value> value = custom.Call(callback);
1984
    if (value.IsEmpty()) {
1985
      result = heap->undefined_value();
1986 1987
    } else {
      result = *reinterpret_cast<Object**>(*value);
1988
      result->VerifyApiCallResultType();
1989 1990 1991
    }
  }
  // Check for exceptions and return result.
1992
  RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
1993 1994
  return result;
}
1995 1996 1997 1998 1999


// Handle calls to non-function objects created through the API. This delegate
// function is used when the call is a normal function call.
BUILTIN(HandleApiCallAsFunction) {
2000
  return HandleApiCallAsFunctionOrConstructor(isolate, false, args);
2001 2002 2003 2004 2005 2006
}


// Handle calls to non-function objects created through the API. This delegate
// function is used when the call is a construct call.
BUILTIN(HandleApiCallAsConstructor) {
2007
  return HandleApiCallAsFunctionOrConstructor(isolate, true, args);
2008
}
2009 2010 2011


static void Generate_LoadIC_Miss(MacroAssembler* masm) {
2012
  LoadIC::GenerateMiss(masm);
2013 2014 2015 2016
}


static void Generate_LoadIC_Normal(MacroAssembler* masm) {
2017 2018 2019 2020 2021 2022
  LoadIC::GenerateNormal(masm, SLOPPY);
}


static void Generate_LoadIC_Normal_Strong(MacroAssembler* masm) {
  LoadIC::GenerateNormal(masm, STRONG);
2023 2024 2025
}


2026
static void Generate_LoadIC_Getter_ForDeopt(MacroAssembler* masm) {
2027
  NamedLoadHandlerCompiler::GenerateLoadViaGetterForDeopt(masm);
2028 2029 2030
}


2031
static void Generate_LoadIC_Slow(MacroAssembler* masm) {
2032
  LoadIC::GenerateRuntimeGetProperty(masm, SLOPPY);
2033 2034 2035
}


2036 2037
static void Generate_LoadIC_Slow_Strong(MacroAssembler* masm) {
  LoadIC::GenerateRuntimeGetProperty(masm, STRONG);
2038 2039 2040
}


danno@chromium.org's avatar
danno@chromium.org committed
2041
static void Generate_KeyedLoadIC_Slow(MacroAssembler* masm) {
2042 2043 2044 2045 2046 2047
  KeyedLoadIC::GenerateRuntimeGetProperty(masm, SLOPPY);
}


static void Generate_KeyedLoadIC_Slow_Strong(MacroAssembler* masm) {
  KeyedLoadIC::GenerateRuntimeGetProperty(masm, STRONG);
danno@chromium.org's avatar
danno@chromium.org committed
2048 2049 2050
}


2051
static void Generate_KeyedLoadIC_Miss(MacroAssembler* masm) {
2052
  KeyedLoadIC::GenerateMiss(masm);
2053 2054 2055
}


2056
static void Generate_KeyedLoadIC_Megamorphic(MacroAssembler* masm) {
2057 2058 2059 2060 2061 2062
  KeyedLoadIC::GenerateMegamorphic(masm, SLOPPY);
}


static void Generate_KeyedLoadIC_Megamorphic_Strong(MacroAssembler* masm) {
  KeyedLoadIC::GenerateMegamorphic(masm, STRONG);
2063 2064 2065 2066 2067 2068 2069 2070
}


static void Generate_StoreIC_Miss(MacroAssembler* masm) {
  StoreIC::GenerateMiss(masm);
}


2071 2072 2073 2074 2075
static void Generate_StoreIC_Normal(MacroAssembler* masm) {
  StoreIC::GenerateNormal(masm);
}


2076 2077 2078 2079 2080 2081 2082 2083 2084 2085
static void Generate_StoreIC_Slow(MacroAssembler* masm) {
  NamedStoreHandlerCompiler::GenerateSlow(masm);
}


static void Generate_KeyedStoreIC_Slow(MacroAssembler* masm) {
  ElementHandlerCompiler::GenerateStoreSlow(masm);
}


2086
static void Generate_StoreIC_Setter_ForDeopt(MacroAssembler* masm) {
2087
  NamedStoreHandlerCompiler::GenerateStoreViaSetterForDeopt(masm);
2088 2089 2090
}


2091
static void Generate_KeyedStoreIC_Megamorphic(MacroAssembler* masm) {
2092
  KeyedStoreIC::GenerateMegamorphic(masm, SLOPPY);
2093 2094 2095 2096
}


static void Generate_KeyedStoreIC_Megamorphic_Strict(MacroAssembler* masm) {
2097
  KeyedStoreIC::GenerateMegamorphic(masm, STRICT);
2098 2099 2100
}


2101
static void Generate_KeyedStoreIC_Miss(MacroAssembler* masm) {
2102
  KeyedStoreIC::GenerateMiss(masm);
danno@chromium.org's avatar
danno@chromium.org committed
2103 2104 2105
}


2106 2107 2108 2109 2110
static void Generate_KeyedStoreIC_Initialize(MacroAssembler* masm) {
  KeyedStoreIC::GenerateInitialize(masm);
}


2111 2112 2113 2114
static void Generate_KeyedStoreIC_Initialize_Strict(MacroAssembler* masm) {
  KeyedStoreIC::GenerateInitialize(masm);
}

2115

2116 2117 2118 2119 2120 2121 2122 2123 2124 2125
static void Generate_KeyedStoreIC_PreMonomorphic(MacroAssembler* masm) {
  KeyedStoreIC::GeneratePreMonomorphic(masm);
}


static void Generate_KeyedStoreIC_PreMonomorphic_Strict(MacroAssembler* masm) {
  KeyedStoreIC::GeneratePreMonomorphic(masm);
}


2126
static void Generate_Return_DebugBreak(MacroAssembler* masm) {
2127 2128
  DebugCodegen::GenerateDebugBreakStub(masm,
                                       DebugCodegen::SAVE_RESULT_REGISTER);
2129 2130 2131
}


2132
static void Generate_Slot_DebugBreak(MacroAssembler* masm) {
2133 2134
  DebugCodegen::GenerateDebugBreakStub(masm,
                                       DebugCodegen::IGNORE_RESULT_REGISTER);
2135 2136 2137
}


2138
static void Generate_PlainReturn_LiveEdit(MacroAssembler* masm) {
2139
  DebugCodegen::GeneratePlainReturnLiveEdit(masm);
2140 2141
}

2142

2143
static void Generate_FrameDropper_LiveEdit(MacroAssembler* masm) {
2144
  DebugCodegen::GenerateFrameDropperLiveEdit(masm);
2145
}
2146

2147 2148 2149 2150 2151 2152 2153 2154 2155 2156

Builtins::Builtins() : initialized_(false) {
  memset(builtins_, 0, sizeof(builtins_[0]) * builtin_count);
  memset(names_, 0, sizeof(names_[0]) * builtin_count);
}


Builtins::~Builtins() {
}

2157

2158
#define DEF_ENUM_C(name, ignore) FUNCTION_ADDR(Builtin_##name),
2159 2160 2161
Address const Builtins::c_functions_[cfunction_count] = {
  BUILTIN_LIST_C(DEF_ENUM_C)
};
2162 2163 2164
#undef DEF_ENUM_C


2165 2166 2167 2168 2169 2170 2171 2172
struct BuiltinDesc {
  byte* generator;
  byte* c_code;
  const char* s_name;  // name is only used for generating log information.
  int name;
  Code::Flags flags;
  BuiltinExtraArguments extra_args;
};
2173

2174 2175
#define BUILTIN_FUNCTION_TABLE_INIT { V8_ONCE_INIT, {} }

2176 2177
class BuiltinFunctionTable {
 public:
2178
  BuiltinDesc* functions() {
2179
    base::CallOnce(&once_, &Builtins::InitBuiltinFunctionTable);
2180
    return functions_;
2181 2182
  }

2183
  base::OnceType once_;
2184
  BuiltinDesc functions_[Builtins::builtin_count + 1];
2185 2186 2187

  friend class Builtins;
};
2188

2189 2190
static BuiltinFunctionTable builtin_function_table =
    BUILTIN_FUNCTION_TABLE_INIT;
2191 2192 2193 2194 2195 2196

// Define array of pointers to generators and C builtin functions.
// We do this in a sort of roundabout way so that we can do the initialization
// within the lexical scope of Builtins:: and within a context where
// Code::Flags names a non-abstract type.
void Builtins::InitBuiltinFunctionTable() {
2197
  BuiltinDesc* functions = builtin_function_table.functions_;
2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217
  functions[builtin_count].generator = NULL;
  functions[builtin_count].c_code = NULL;
  functions[builtin_count].s_name = NULL;
  functions[builtin_count].name = builtin_count;
  functions[builtin_count].flags = static_cast<Code::Flags>(0);
  functions[builtin_count].extra_args = NO_EXTRA_ARGUMENTS;

#define DEF_FUNCTION_PTR_C(aname, aextra_args)                         \
    functions->generator = FUNCTION_ADDR(Generate_Adaptor);            \
    functions->c_code = FUNCTION_ADDR(Builtin_##aname);                \
    functions->s_name = #aname;                                        \
    functions->name = c_##aname;                                       \
    functions->flags = Code::ComputeFlags(Code::BUILTIN);              \
    functions->extra_args = aextra_args;                               \
    ++functions;

#define DEF_FUNCTION_PTR_A(aname, kind, state, extra)                       \
    functions->generator = FUNCTION_ADDR(Generate_##aname);                 \
    functions->c_code = NULL;                                               \
    functions->s_name = #aname;                                             \
2218
    functions->name = k##aname;                                             \
2219 2220 2221 2222 2223 2224
    functions->flags = Code::ComputeFlags(Code::kind,                       \
                                          state,                            \
                                          extra);                           \
    functions->extra_args = NO_EXTRA_ARGUMENTS;                             \
    ++functions;

2225
#define DEF_FUNCTION_PTR_H(aname, kind)                                     \
2226 2227 2228 2229
    functions->generator = FUNCTION_ADDR(Generate_##aname);                 \
    functions->c_code = NULL;                                               \
    functions->s_name = #aname;                                             \
    functions->name = k##aname;                                             \
2230
    functions->flags = Code::ComputeHandlerFlags(Code::kind);               \
2231 2232 2233
    functions->extra_args = NO_EXTRA_ARGUMENTS;                             \
    ++functions;

2234 2235
  BUILTIN_LIST_C(DEF_FUNCTION_PTR_C)
  BUILTIN_LIST_A(DEF_FUNCTION_PTR_A)
2236
  BUILTIN_LIST_H(DEF_FUNCTION_PTR_H)
2237
  BUILTIN_LIST_DEBUG_A(DEF_FUNCTION_PTR_A)
2238 2239 2240

#undef DEF_FUNCTION_PTR_C
#undef DEF_FUNCTION_PTR_A
2241 2242
}

2243

2244
void Builtins::SetUp(Isolate* isolate, bool create_heap_objects) {
2245
  DCHECK(!initialized_);
2246 2247

  // Create a scope for the handles in the builtins.
2248
  HandleScope scope(isolate);
2249

2250
  const BuiltinDesc* functions = builtin_function_table.functions();
2251 2252

  // For now we generate builtin adaptor code into a stack-allocated
2253 2254
  // buffer, before copying it into individual code objects. Be careful
  // with alignment, some platforms don't like unaligned code.
2255 2256 2257
#ifdef DEBUG
  // We can generate a lot of debug code on Arm64.
  const size_t buffer_size = 32*KB;
2258 2259 2260
#elif V8_TARGET_ARCH_PPC64
  // 8 KB is insufficient on PPC64 when FLAG_debug_code is on.
  const size_t buffer_size = 10 * KB;
2261 2262 2263 2264
#else
  const size_t buffer_size = 8*KB;
#endif
  union { int force_alignment; byte buffer[buffer_size]; } u;
2265 2266 2267 2268 2269

  // Traverse the list of builtins and generate an adaptor in a
  // separate code object for each one.
  for (int i = 0; i < builtin_count; i++) {
    if (create_heap_objects) {
2270
      MacroAssembler masm(isolate, u.buffer, sizeof u.buffer);
2271
      // Generate the code/adaptor.
2272
      typedef void (*Generator)(MacroAssembler*, int, BuiltinExtraArguments);
2273 2274 2275 2276
      Generator g = FUNCTION_CAST<Generator>(functions[i].generator);
      // We pass all arguments to the generator, but it may not use all of
      // them.  This works because the first arguments are on top of the
      // stack.
2277
      DCHECK(!masm.has_frame());
2278
      g(&masm, functions[i].name, functions[i].extra_args);
2279 2280 2281
      // Move the code into the object heap.
      CodeDesc desc;
      masm.GetCode(&desc);
2282
      Code::Flags flags = functions[i].flags;
2283 2284
      Handle<Code> code =
          isolate->factory()->NewCode(desc, flags, masm.CodeObject());
2285
      // Log the event and add the code to the builtins array.
2286
      PROFILE(isolate,
2287 2288
              CodeCreateEvent(Logger::BUILTIN_TAG, *code, functions[i].s_name));
      builtins_[i] = *code;
2289
      code->set_builtin_index(i);
2290
#ifdef ENABLE_DISASSEMBLER
2291
      if (FLAG_print_builtin_code) {
2292
        CodeTracer::Scope trace_scope(isolate->GetCodeTracer());
2293 2294 2295 2296
        OFStream os(trace_scope.file());
        os << "Builtin: " << functions[i].s_name << "\n";
        code->Disassemble(functions[i].s_name, os);
        os << "\n";
2297 2298
      }
#endif
2299 2300 2301 2302 2303 2304 2305 2306
    } else {
      // Deserializing. The values will be filled in during IterateBuiltins.
      builtins_[i] = NULL;
    }
    names_[i] = functions[i].s_name;
  }

  // Mark as initialized.
2307
  initialized_ = true;
2308 2309 2310 2311
}


void Builtins::TearDown() {
2312
  initialized_ = false;
2313 2314 2315 2316 2317 2318 2319 2320 2321
}


void Builtins::IterateBuiltins(ObjectVisitor* v) {
  v->VisitPointers(&builtins_[0], &builtins_[0] + builtin_count);
}


const char* Builtins::Lookup(byte* pc) {
2322 2323
  // may be called during initialization (disassembler!)
  if (initialized_) {
2324 2325 2326 2327 2328 2329 2330 2331 2332 2333
    for (int i = 0; i < builtin_count; i++) {
      Code* entry = Code::cast(builtins_[i]);
      if (entry->contains(pc)) {
        return names_[i];
      }
    }
  }
  return NULL;
}

2334

2335
void Builtins::Generate_InterruptCheck(MacroAssembler* masm) {
2336
  masm->TailCallRuntime(Runtime::kInterrupt, 0, 1);
2337 2338 2339 2340
}


void Builtins::Generate_StackCheck(MacroAssembler* masm) {
2341
  masm->TailCallRuntime(Runtime::kStackGuard, 0, 1);
2342 2343 2344
}


2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356
#define DEFINE_BUILTIN_ACCESSOR_C(name, ignore)               \
Handle<Code> Builtins::name() {                               \
  Code** code_address =                                       \
      reinterpret_cast<Code**>(builtin_address(k##name));     \
  return Handle<Code>(code_address);                          \
}
#define DEFINE_BUILTIN_ACCESSOR_A(name, kind, state, extra) \
Handle<Code> Builtins::name() {                             \
  Code** code_address =                                     \
      reinterpret_cast<Code**>(builtin_address(k##name));   \
  return Handle<Code>(code_address);                        \
}
2357
#define DEFINE_BUILTIN_ACCESSOR_H(name, kind)               \
2358 2359 2360 2361 2362
Handle<Code> Builtins::name() {                             \
  Code** code_address =                                     \
      reinterpret_cast<Code**>(builtin_address(k##name));   \
  return Handle<Code>(code_address);                        \
}
2363 2364
BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C)
BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A)
2365
BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H)
2366 2367 2368 2369 2370
BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A)
#undef DEFINE_BUILTIN_ACCESSOR_C
#undef DEFINE_BUILTIN_ACCESSOR_A


2371 2372
}  // namespace internal
}  // namespace v8