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