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