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