1 // Copyright 2006-2008 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 "ic-inl.h" 35 36 namespace v8 { 37 namespace internal { 38 39 namespace { 40 41 // Arguments object passed to C++ builtins. 42 template <BuiltinExtraArguments extra_args> 43 class BuiltinArguments : public Arguments { 44 public: 45 BuiltinArguments(int length, Object** arguments) 46 : Arguments(length, arguments) { } 47 48 Object*& operator[] (int index) { 49 ASSERT(index < length()); 50 return Arguments::operator[](index); 51 } 52 53 template <class S> Handle<S> at(int index) { 54 ASSERT(index < length()); 55 return Arguments::at<S>(index); 56 } 57 58 Handle<Object> receiver() { 59 return Arguments::at<Object>(0); 60 } 61 62 Handle<JSFunction> called_function() { 63 STATIC_ASSERT(extra_args == NEEDS_CALLED_FUNCTION); 64 return Arguments::at<JSFunction>(Arguments::length() - 1); 65 } 66 67 // Gets the total number of arguments including the receiver (but 68 // excluding extra arguments). 69 int length() const { 70 STATIC_ASSERT(extra_args == NO_EXTRA_ARGUMENTS); 71 return Arguments::length(); 72 } 73 74 #ifdef DEBUG 75 void Verify() { 76 // Check we have at least the receiver. 77 ASSERT(Arguments::length() >= 1); 78 } 79 #endif 80 }; 81 82 83 // Specialize BuiltinArguments for the called function extra argument. 84 85 template <> 86 int BuiltinArguments<NEEDS_CALLED_FUNCTION>::length() const { 87 return Arguments::length() - 1; 88 } 89 90 #ifdef DEBUG 91 template <> 92 void BuiltinArguments<NEEDS_CALLED_FUNCTION>::Verify() { 93 // Check we have at least the receiver and the called function. 94 ASSERT(Arguments::length() >= 2); 95 // Make sure cast to JSFunction succeeds. 96 called_function(); 97 } 98 #endif 99 100 101 #define DEF_ARG_TYPE(name, spec) \ 102 typedef BuiltinArguments<spec> name##ArgumentsType; 103 BUILTIN_LIST_C(DEF_ARG_TYPE) 104 #undef DEF_ARG_TYPE 105 106 } // namespace 107 108 109 // ---------------------------------------------------------------------------- 110 // Support macro for defining builtins in C++. 111 // ---------------------------------------------------------------------------- 112 // 113 // A builtin function is defined by writing: 114 // 115 // BUILTIN(name) { 116 // ... 117 // } 118 // 119 // In the body of the builtin function the arguments can be accessed 120 // through the BuiltinArguments object args. 121 122 #ifdef DEBUG 123 124 #define BUILTIN(name) \ 125 static Object* Builtin_Impl_##name(name##ArgumentsType args); \ 126 static Object* Builtin_##name(name##ArgumentsType args) { \ 127 args.Verify(); \ 128 return Builtin_Impl_##name(args); \ 129 } \ 130 static Object* Builtin_Impl_##name(name##ArgumentsType args) 131 132 #else // For release mode. 133 134 #define BUILTIN(name) \ 135 static Object* Builtin_##name(name##ArgumentsType args) 136 137 #endif 138 139 140 static inline bool CalledAsConstructor() { 141 #ifdef DEBUG 142 // Calculate the result using a full stack frame iterator and check 143 // that the state of the stack is as we assume it to be in the 144 // code below. 145 StackFrameIterator it; 146 ASSERT(it.frame()->is_exit()); 147 it.Advance(); 148 StackFrame* frame = it.frame(); 149 bool reference_result = frame->is_construct(); 150 #endif 151 Address fp = Top::c_entry_fp(Top::GetCurrentThread()); 152 // Because we know fp points to an exit frame we can use the relevant 153 // part of ExitFrame::ComputeCallerState directly. 154 const int kCallerOffset = ExitFrameConstants::kCallerFPOffset; 155 Address caller_fp = Memory::Address_at(fp + kCallerOffset); 156 // This inlines the part of StackFrame::ComputeType that grabs the 157 // type of the current frame. Note that StackFrame::ComputeType 158 // has been specialized for each architecture so if any one of them 159 // changes this code has to be changed as well. 160 const int kMarkerOffset = StandardFrameConstants::kMarkerOffset; 161 const Smi* kConstructMarker = Smi::FromInt(StackFrame::CONSTRUCT); 162 Object* marker = Memory::Object_at(caller_fp + kMarkerOffset); 163 bool result = (marker == kConstructMarker); 164 ASSERT_EQ(result, reference_result); 165 return result; 166 } 167 168 // ---------------------------------------------------------------------------- 169 170 171 BUILTIN(Illegal) { 172 UNREACHABLE(); 173 return Heap::undefined_value(); // Make compiler happy. 174 } 175 176 177 BUILTIN(EmptyFunction) { 178 return Heap::undefined_value(); 179 } 180 181 182 BUILTIN(ArrayCodeGeneric) { 183 Counters::array_function_runtime.Increment(); 184 185 JSArray* array; 186 if (CalledAsConstructor()) { 187 array = JSArray::cast(*args.receiver()); 188 } else { 189 // Allocate the JS Array 190 JSFunction* constructor = 191 Top::context()->global_context()->array_function(); 192 Object* obj = Heap::AllocateJSObject(constructor); 193 if (obj->IsFailure()) return obj; 194 array = JSArray::cast(obj); 195 } 196 197 // 'array' now contains the JSArray we should initialize. 198 199 // Optimize the case where there is one argument and the argument is a 200 // small smi. 201 if (args.length() == 2) { 202 Object* obj = args[1]; 203 if (obj->IsSmi()) { 204 int len = Smi::cast(obj)->value(); 205 if (len >= 0 && len < JSObject::kInitialMaxFastElementArray) { 206 Object* obj = Heap::AllocateFixedArrayWithHoles(len); 207 if (obj->IsFailure()) return obj; 208 array->SetContent(FixedArray::cast(obj)); 209 return array; 210 } 211 } 212 // Take the argument as the length. 213 obj = array->Initialize(0); 214 if (obj->IsFailure()) return obj; 215 return array->SetElementsLength(args[1]); 216 } 217 218 // Optimize the case where there are no parameters passed. 219 if (args.length() == 1) { 220 return array->Initialize(JSArray::kPreallocatedArrayElements); 221 } 222 223 // Take the arguments as elements. 224 int number_of_elements = args.length() - 1; 225 Smi* len = Smi::FromInt(number_of_elements); 226 Object* obj = Heap::AllocateFixedArrayWithHoles(len->value()); 227 if (obj->IsFailure()) return obj; 228 229 AssertNoAllocation no_gc; 230 FixedArray* elms = FixedArray::cast(obj); 231 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); 232 // Fill in the content 233 for (int index = 0; index < number_of_elements; index++) { 234 elms->set(index, args[index+1], mode); 235 } 236 237 // Set length and elements on the array. 238 array->set_elements(FixedArray::cast(obj)); 239 array->set_length(len); 240 241 return array; 242 } 243 244 245 BUILTIN(ArrayPush) { 246 JSArray* array = JSArray::cast(*args.receiver()); 247 ASSERT(array->HasFastElements()); 248 249 int len = Smi::cast(array->length())->value(); 250 int to_add = args.length() - 1; 251 if (to_add == 0) { 252 return Smi::FromInt(len); 253 } 254 // Currently fixed arrays cannot grow too big, so 255 // we should never hit this case. 256 ASSERT(to_add <= (Smi::kMaxValue - len)); 257 258 int new_length = len + to_add; 259 FixedArray* elms = FixedArray::cast(array->elements()); 260 261 if (new_length > elms->length()) { 262 // New backing storage is needed. 263 int capacity = new_length + (new_length >> 1) + 16; 264 Object* obj = Heap::AllocateFixedArrayWithHoles(capacity); 265 if (obj->IsFailure()) return obj; 266 267 AssertNoAllocation no_gc; 268 FixedArray* new_elms = FixedArray::cast(obj); 269 WriteBarrierMode mode = new_elms->GetWriteBarrierMode(no_gc); 270 // Fill out the new array with old elements. 271 for (int i = 0; i < len; i++) new_elms->set(i, elms->get(i), mode); 272 elms = new_elms; 273 array->set_elements(elms); 274 } 275 276 AssertNoAllocation no_gc; 277 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); 278 279 // Add the provided values. 280 for (int index = 0; index < to_add; index++) { 281 elms->set(index + len, args[index + 1], mode); 282 } 283 284 // Set the length. 285 array->set_length(Smi::FromInt(new_length)); 286 return Smi::FromInt(new_length); 287 } 288 289 290 BUILTIN(ArrayPop) { 291 JSArray* array = JSArray::cast(*args.receiver()); 292 ASSERT(array->HasFastElements()); 293 Object* undefined = Heap::undefined_value(); 294 295 int len = Smi::cast(array->length())->value(); 296 if (len == 0) return undefined; 297 298 // Get top element 299 FixedArray* elms = FixedArray::cast(array->elements()); 300 Object* top = elms->get(len - 1); 301 302 // Set the length. 303 array->set_length(Smi::FromInt(len - 1)); 304 305 if (!top->IsTheHole()) { 306 // Delete the top element. 307 elms->set_the_hole(len - 1); 308 return top; 309 } 310 311 // Remember to check the prototype chain. 312 JSFunction* array_function = 313 Top::context()->global_context()->array_function(); 314 JSObject* prototype = JSObject::cast(array_function->prototype()); 315 top = prototype->GetElement(len - 1); 316 317 return top; 318 } 319 320 321 static Object* GetElementToMove(uint32_t index, 322 FixedArray* elms, 323 JSObject* prototype) { 324 Object* e = elms->get(index); 325 if (e->IsTheHole() && prototype->HasElement(index)) { 326 e = prototype->GetElement(index); 327 } 328 return e; 329 } 330 331 332 BUILTIN(ArrayShift) { 333 JSArray* array = JSArray::cast(*args.receiver()); 334 ASSERT(array->HasFastElements()); 335 336 int len = Smi::cast(array->length())->value(); 337 if (len == 0) return Heap::undefined_value(); 338 339 // Fetch the prototype. 340 JSFunction* array_function = 341 Top::context()->global_context()->array_function(); 342 JSObject* prototype = JSObject::cast(array_function->prototype()); 343 344 FixedArray* elms = FixedArray::cast(array->elements()); 345 346 // Get first element 347 Object* first = elms->get(0); 348 if (first->IsTheHole()) { 349 first = prototype->GetElement(0); 350 } 351 352 // Shift the elements. 353 for (int i = 0; i < len - 1; i++) { 354 elms->set(i, GetElementToMove(i + 1, elms, prototype)); 355 } 356 elms->set(len - 1, Heap::the_hole_value()); 357 358 // Set the length. 359 array->set_length(Smi::FromInt(len - 1)); 360 361 return first; 362 } 363 364 365 BUILTIN(ArrayUnshift) { 366 JSArray* array = JSArray::cast(*args.receiver()); 367 ASSERT(array->HasFastElements()); 368 369 int len = Smi::cast(array->length())->value(); 370 int to_add = args.length() - 1; 371 // Note that we cannot quit early if to_add == 0 as 372 // values should be lifted from prototype into 373 // the array. 374 375 int new_length = len + to_add; 376 // Currently fixed arrays cannot grow too big, so 377 // we should never hit this case. 378 ASSERT(to_add <= (Smi::kMaxValue - len)); 379 380 FixedArray* elms = FixedArray::cast(array->elements()); 381 382 // Fetch the prototype. 383 JSFunction* array_function = 384 Top::context()->global_context()->array_function(); 385 JSObject* prototype = JSObject::cast(array_function->prototype()); 386 387 if (new_length > elms->length()) { 388 // New backing storage is needed. 389 int capacity = new_length + (new_length >> 1) + 16; 390 Object* obj = Heap::AllocateFixedArrayWithHoles(capacity); 391 if (obj->IsFailure()) return obj; 392 393 AssertNoAllocation no_gc; 394 FixedArray* new_elms = FixedArray::cast(obj); 395 WriteBarrierMode mode = new_elms->GetWriteBarrierMode(no_gc); 396 // Fill out the new array with old elements. 397 for (int i = 0; i < len; i++) 398 new_elms->set(to_add + i, 399 GetElementToMove(i, elms, prototype), 400 mode); 401 402 elms = new_elms; 403 array->set_elements(elms); 404 } else { 405 AssertNoAllocation no_gc; 406 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); 407 408 // Move elements to the right 409 for (int i = 0; i < len; i++) { 410 elms->set(new_length - i - 1, 411 GetElementToMove(len - i - 1, elms, prototype), 412 mode); 413 } 414 } 415 416 // Add the provided values. 417 AssertNoAllocation no_gc; 418 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); 419 for (int i = 0; i < to_add; i++) { 420 elms->set(i, args[i + 1], mode); 421 } 422 423 // Set the length. 424 array->set_length(Smi::FromInt(new_length)); 425 return Smi::FromInt(new_length); 426 } 427 428 429 static Object* CallJsBuiltin(const char* name, 430 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) { 431 HandleScope handleScope; 432 433 Handle<Object> js_builtin = 434 GetProperty(Handle<JSObject>(Top::global_context()->builtins()), 435 name); 436 ASSERT(js_builtin->IsJSFunction()); 437 Handle<JSFunction> function(Handle<JSFunction>::cast(js_builtin)); 438 Vector<Object**> argv(Vector<Object**>::New(args.length() - 1)); 439 int n_args = args.length() - 1; 440 for (int i = 0; i < n_args; i++) { 441 argv[i] = &args[i + 1]; 442 } 443 bool pending_exception = false; 444 Handle<Object> result = Execution::Call(function, 445 args.receiver(), 446 n_args, 447 argv.start(), 448 &pending_exception); 449 if (pending_exception) return Failure::Exception(); 450 return *result; 451 } 452 453 454 BUILTIN(ArraySlice) { 455 JSArray* array = JSArray::cast(*args.receiver()); 456 ASSERT(array->HasFastElements()); 457 458 int len = Smi::cast(array->length())->value(); 459 460 int n_arguments = args.length() - 1; 461 462 // Note carefully choosen defaults---if argument is missing, 463 // it's undefined which gets converted to 0 for relativeStart 464 // and to len for relativeEnd. 465 int relativeStart = 0; 466 int relativeEnd = len; 467 if (n_arguments > 0) { 468 Object* arg1 = args[1]; 469 if (arg1->IsSmi()) { 470 relativeStart = Smi::cast(arg1)->value(); 471 } else if (!arg1->IsUndefined()) { 472 return CallJsBuiltin("ArraySlice", args); 473 } 474 if (n_arguments > 1) { 475 Object* arg2 = args[2]; 476 if (arg2->IsSmi()) { 477 relativeEnd = Smi::cast(arg2)->value(); 478 } else if (!arg2->IsUndefined()) { 479 return CallJsBuiltin("ArraySlice", args); 480 } 481 } 482 } 483 484 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6. 485 int k = (relativeStart < 0) ? Max(len + relativeStart, 0) 486 : Min(relativeStart, len); 487 488 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8. 489 int final = (relativeEnd < 0) ? Max(len + relativeEnd, 0) 490 : Min(relativeEnd, len); 491 492 // Calculate the length of result array. 493 int result_len = final - k; 494 if (result_len < 0) { 495 result_len = 0; 496 } 497 498 JSFunction* array_function = 499 Top::context()->global_context()->array_function(); 500 Object* result = Heap::AllocateJSObject(array_function); 501 if (result->IsFailure()) return result; 502 JSArray* result_array = JSArray::cast(result); 503 504 result = Heap::AllocateFixedArrayWithHoles(result_len); 505 if (result->IsFailure()) return result; 506 FixedArray* result_elms = FixedArray::cast(result); 507 508 FixedArray* elms = FixedArray::cast(array->elements()); 509 510 // Fetch the prototype. 511 JSObject* prototype = JSObject::cast(array_function->prototype()); 512 513 AssertNoAllocation no_gc; 514 WriteBarrierMode mode = result_elms->GetWriteBarrierMode(no_gc); 515 516 // Fill newly created array. 517 for (int i = 0; i < result_len; i++) { 518 result_elms->set(i, 519 GetElementToMove(k + i, elms, prototype), 520 mode); 521 } 522 523 // Set elements. 524 result_array->set_elements(result_elms); 525 526 // Set the length. 527 result_array->set_length(Smi::FromInt(result_len)); 528 return result_array; 529 } 530 531 532 BUILTIN(ArraySplice) { 533 JSArray* array = JSArray::cast(*args.receiver()); 534 ASSERT(array->HasFastElements()); 535 536 int len = Smi::cast(array->length())->value(); 537 538 int n_arguments = args.length() - 1; 539 540 // SpiderMonkey and JSC return undefined in the case where no 541 // arguments are given instead of using the implicit undefined 542 // arguments. This does not follow ECMA-262, but we do the same for 543 // compatibility. 544 // TraceMonkey follows ECMA-262 though. 545 if (n_arguments == 0) { 546 return Heap::undefined_value(); 547 } 548 549 int relativeStart = 0; 550 Object* arg1 = args[1]; 551 if (arg1->IsSmi()) { 552 relativeStart = Smi::cast(arg1)->value(); 553 } else if (!arg1->IsUndefined()) { 554 return CallJsBuiltin("ArraySplice", args); 555 } 556 int actualStart = (relativeStart < 0) ? Max(len + relativeStart, 0) 557 : Min(relativeStart, len); 558 559 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is 560 // given differently from when an undefined delete count is given. 561 // This does not follow ECMA-262, but we do the same for 562 // compatibility. 563 int deleteCount = len; 564 if (n_arguments > 1) { 565 Object* arg2 = args[2]; 566 if (arg2->IsSmi()) { 567 deleteCount = Smi::cast(arg2)->value(); 568 } else { 569 return CallJsBuiltin("ArraySplice", args); 570 } 571 } 572 int actualDeleteCount = Min(Max(deleteCount, 0), len - actualStart); 573 574 JSFunction* array_function = 575 Top::context()->global_context()->array_function(); 576 577 // Allocate result array. 578 Object* result = Heap::AllocateJSObject(array_function); 579 if (result->IsFailure()) return result; 580 JSArray* result_array = JSArray::cast(result); 581 582 result = Heap::AllocateFixedArrayWithHoles(actualDeleteCount); 583 if (result->IsFailure()) return result; 584 FixedArray* result_elms = FixedArray::cast(result); 585 586 FixedArray* elms = FixedArray::cast(array->elements()); 587 588 // Fetch the prototype. 589 JSObject* prototype = JSObject::cast(array_function->prototype()); 590 591 AssertNoAllocation no_gc; 592 WriteBarrierMode mode = result_elms->GetWriteBarrierMode(no_gc); 593 594 // Fill newly created array. 595 for (int k = 0; k < actualDeleteCount; k++) { 596 result_elms->set(k, 597 GetElementToMove(actualStart + k, elms, prototype), 598 mode); 599 } 600 601 // Set elements. 602 result_array->set_elements(result_elms); 603 604 // Set the length. 605 result_array->set_length(Smi::FromInt(actualDeleteCount)); 606 607 int itemCount = (n_arguments > 1) ? (n_arguments - 2) : 0; 608 609 int new_length = len - actualDeleteCount + itemCount; 610 611 mode = elms->GetWriteBarrierMode(no_gc); 612 if (itemCount < actualDeleteCount) { 613 // Shrink the array. 614 for (int k = actualStart; k < (len - actualDeleteCount); k++) { 615 elms->set(k + itemCount, 616 GetElementToMove(k + actualDeleteCount, elms, prototype), 617 mode); 618 } 619 620 for (int k = len; k > new_length; k--) { 621 elms->set(k - 1, Heap::the_hole_value()); 622 } 623 } else if (itemCount > actualDeleteCount) { 624 // Currently fixed arrays cannot grow too big, so 625 // we should never hit this case. 626 ASSERT((itemCount - actualDeleteCount) <= (Smi::kMaxValue - len)); 627 628 FixedArray* source_elms = elms; 629 630 // Check if array need to grow. 631 if (new_length > elms->length()) { 632 // New backing storage is needed. 633 int capacity = new_length + (new_length >> 1) + 16; 634 Object* obj = Heap::AllocateFixedArrayWithHoles(capacity); 635 if (obj->IsFailure()) return obj; 636 637 FixedArray* new_elms = FixedArray::cast(obj); 638 mode = new_elms->GetWriteBarrierMode(no_gc); 639 640 // Copy the part before actualStart as is. 641 for (int k = 0; k < actualStart; k++) { 642 new_elms->set(k, elms->get(k), mode); 643 } 644 645 source_elms = elms; 646 elms = new_elms; 647 array->set_elements(elms); 648 } 649 650 for (int k = len - actualDeleteCount; k > actualStart; k--) { 651 elms->set(k + itemCount - 1, 652 GetElementToMove(k + actualDeleteCount - 1, 653 source_elms, 654 prototype), 655 mode); 656 } 657 } 658 659 for (int k = actualStart; k < actualStart + itemCount; k++) { 660 elms->set(k, args[3 + k - actualStart], mode); 661 } 662 663 // Set the length. 664 array->set_length(Smi::FromInt(new_length)); 665 666 return result_array; 667 } 668 669 670 // ----------------------------------------------------------------------------- 671 // 672 673 674 // Returns the holder JSObject if the function can legally be called 675 // with this receiver. Returns Heap::null_value() if the call is 676 // illegal. Any arguments that don't fit the expected type is 677 // overwritten with undefined. Arguments that do fit the expected 678 // type is overwritten with the object in the prototype chain that 679 // actually has that type. 680 static inline Object* TypeCheck(int argc, 681 Object** argv, 682 FunctionTemplateInfo* info) { 683 Object* recv = argv[0]; 684 Object* sig_obj = info->signature(); 685 if (sig_obj->IsUndefined()) return recv; 686 SignatureInfo* sig = SignatureInfo::cast(sig_obj); 687 // If necessary, check the receiver 688 Object* recv_type = sig->receiver(); 689 690 Object* holder = recv; 691 if (!recv_type->IsUndefined()) { 692 for (; holder != Heap::null_value(); holder = holder->GetPrototype()) { 693 if (holder->IsInstanceOf(FunctionTemplateInfo::cast(recv_type))) { 694 break; 695 } 696 } 697 if (holder == Heap::null_value()) return holder; 698 } 699 Object* args_obj = sig->args(); 700 // If there is no argument signature we're done 701 if (args_obj->IsUndefined()) return holder; 702 FixedArray* args = FixedArray::cast(args_obj); 703 int length = args->length(); 704 if (argc <= length) length = argc - 1; 705 for (int i = 0; i < length; i++) { 706 Object* argtype = args->get(i); 707 if (argtype->IsUndefined()) continue; 708 Object** arg = &argv[-1 - i]; 709 Object* current = *arg; 710 for (; current != Heap::null_value(); current = current->GetPrototype()) { 711 if (current->IsInstanceOf(FunctionTemplateInfo::cast(argtype))) { 712 *arg = current; 713 break; 714 } 715 } 716 if (current == Heap::null_value()) *arg = Heap::undefined_value(); 717 } 718 return holder; 719 } 720 721 722 template <bool is_construct> 723 static Object* HandleApiCallHelper( 724 BuiltinArguments<NEEDS_CALLED_FUNCTION> args) { 725 ASSERT(is_construct == CalledAsConstructor()); 726 727 HandleScope scope; 728 Handle<JSFunction> function = args.called_function(); 729 730 if (is_construct) { 731 Handle<FunctionTemplateInfo> desc = 732 Handle<FunctionTemplateInfo>( 733 FunctionTemplateInfo::cast(function->shared()->function_data())); 734 bool pending_exception = false; 735 Factory::ConfigureInstance(desc, Handle<JSObject>::cast(args.receiver()), 736 &pending_exception); 737 ASSERT(Top::has_pending_exception() == pending_exception); 738 if (pending_exception) return Failure::Exception(); 739 } 740 741 FunctionTemplateInfo* fun_data = 742 FunctionTemplateInfo::cast(function->shared()->function_data()); 743 Object* raw_holder = TypeCheck(args.length(), &args[0], fun_data); 744 745 if (raw_holder->IsNull()) { 746 // This function cannot be called with the given receiver. Abort! 747 Handle<Object> obj = 748 Factory::NewTypeError("illegal_invocation", HandleVector(&function, 1)); 749 return Top::Throw(*obj); 750 } 751 752 Object* raw_call_data = fun_data->call_code(); 753 if (!raw_call_data->IsUndefined()) { 754 CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data); 755 Object* callback_obj = call_data->callback(); 756 v8::InvocationCallback callback = 757 v8::ToCData<v8::InvocationCallback>(callback_obj); 758 Object* data_obj = call_data->data(); 759 Object* result; 760 761 Handle<Object> data_handle(data_obj); 762 v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle); 763 ASSERT(raw_holder->IsJSObject()); 764 v8::Local<v8::Function> callee = v8::Utils::ToLocal(function); 765 Handle<JSObject> holder_handle(JSObject::cast(raw_holder)); 766 v8::Local<v8::Object> holder = v8::Utils::ToLocal(holder_handle); 767 LOG(ApiObjectAccess("call", JSObject::cast(*args.receiver()))); 768 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments( 769 data, 770 holder, 771 callee, 772 is_construct, 773 reinterpret_cast<void**>(&args[0] - 1), 774 args.length() - 1); 775 776 v8::Handle<v8::Value> value; 777 { 778 // Leaving JavaScript. 779 VMState state(EXTERNAL); 780 #ifdef ENABLE_LOGGING_AND_PROFILING 781 state.set_external_callback(v8::ToCData<Address>(callback_obj)); 782 #endif 783 value = callback(new_args); 784 } 785 if (value.IsEmpty()) { 786 result = Heap::undefined_value(); 787 } else { 788 result = *reinterpret_cast<Object**>(*value); 789 } 790 791 RETURN_IF_SCHEDULED_EXCEPTION(); 792 if (!is_construct || result->IsJSObject()) return result; 793 } 794 795 return *args.receiver(); 796 } 797 798 799 BUILTIN(HandleApiCall) { 800 return HandleApiCallHelper<false>(args); 801 } 802 803 804 BUILTIN(HandleApiCallConstruct) { 805 return HandleApiCallHelper<true>(args); 806 } 807 808 809 #ifdef DEBUG 810 811 static void VerifyTypeCheck(Handle<JSObject> object, 812 Handle<JSFunction> function) { 813 FunctionTemplateInfo* info = 814 FunctionTemplateInfo::cast(function->shared()->function_data()); 815 if (info->signature()->IsUndefined()) return; 816 SignatureInfo* signature = SignatureInfo::cast(info->signature()); 817 Object* receiver_type = signature->receiver(); 818 if (receiver_type->IsUndefined()) return; 819 FunctionTemplateInfo* type = FunctionTemplateInfo::cast(receiver_type); 820 ASSERT(object->IsInstanceOf(type)); 821 } 822 823 #endif 824 825 826 BUILTIN(FastHandleApiCall) { 827 ASSERT(!CalledAsConstructor()); 828 const bool is_construct = false; 829 830 // We expect four more arguments: function, callback, call data, and holder. 831 const int args_length = args.length() - 4; 832 ASSERT(args_length >= 0); 833 834 Handle<JSFunction> function = args.at<JSFunction>(args_length); 835 Object* callback_obj = args[args_length + 1]; 836 Handle<Object> data_handle = args.at<Object>(args_length + 2); 837 Handle<JSObject> checked_holder = args.at<JSObject>(args_length + 3); 838 839 #ifdef DEBUG 840 VerifyTypeCheck(checked_holder, function); 841 #endif 842 843 v8::Local<v8::Object> holder = v8::Utils::ToLocal(checked_holder); 844 v8::Local<v8::Function> callee = v8::Utils::ToLocal(function); 845 v8::InvocationCallback callback = 846 v8::ToCData<v8::InvocationCallback>(callback_obj); 847 v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle); 848 849 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments( 850 data, 851 holder, 852 callee, 853 is_construct, 854 reinterpret_cast<void**>(&args[0] - 1), 855 args_length - 1); 856 857 HandleScope scope; 858 Object* result; 859 v8::Handle<v8::Value> value; 860 { 861 // Leaving JavaScript. 862 VMState state(EXTERNAL); 863 #ifdef ENABLE_LOGGING_AND_PROFILING 864 state.set_external_callback(v8::ToCData<Address>(callback_obj)); 865 #endif 866 value = callback(new_args); 867 } 868 if (value.IsEmpty()) { 869 result = Heap::undefined_value(); 870 } else { 871 result = *reinterpret_cast<Object**>(*value); 872 } 873 874 RETURN_IF_SCHEDULED_EXCEPTION(); 875 return result; 876 } 877 878 879 // Helper function to handle calls to non-function objects created through the 880 // API. The object can be called as either a constructor (using new) or just as 881 // a function (without new). 882 static Object* HandleApiCallAsFunctionOrConstructor( 883 bool is_construct_call, 884 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) { 885 // Non-functions are never called as constructors. Even if this is an object 886 // called as a constructor the delegate call is not a construct call. 887 ASSERT(!CalledAsConstructor()); 888 889 Handle<Object> receiver = args.at<Object>(0); 890 891 // Get the object called. 892 JSObject* obj = JSObject::cast(*args.receiver()); 893 894 // Get the invocation callback from the function descriptor that was 895 // used to create the called object. 896 ASSERT(obj->map()->has_instance_call_handler()); 897 JSFunction* constructor = JSFunction::cast(obj->map()->constructor()); 898 Object* template_info = constructor->shared()->function_data(); 899 Object* handler = 900 FunctionTemplateInfo::cast(template_info)->instance_call_handler(); 901 ASSERT(!handler->IsUndefined()); 902 CallHandlerInfo* call_data = CallHandlerInfo::cast(handler); 903 Object* callback_obj = call_data->callback(); 904 v8::InvocationCallback callback = 905 v8::ToCData<v8::InvocationCallback>(callback_obj); 906 907 // Get the data for the call and perform the callback. 908 Object* data_obj = call_data->data(); 909 Object* result; 910 { HandleScope scope; 911 v8::Local<v8::Object> self = 912 v8::Utils::ToLocal(Handle<JSObject>::cast(args.receiver())); 913 Handle<Object> data_handle(data_obj); 914 v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle); 915 Handle<JSFunction> callee_handle(constructor); 916 v8::Local<v8::Function> callee = v8::Utils::ToLocal(callee_handle); 917 LOG(ApiObjectAccess("call non-function", JSObject::cast(*args.receiver()))); 918 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments( 919 data, 920 self, 921 callee, 922 is_construct_call, 923 reinterpret_cast<void**>(&args[0] - 1), 924 args.length() - 1); 925 v8::Handle<v8::Value> value; 926 { 927 // Leaving JavaScript. 928 VMState state(EXTERNAL); 929 #ifdef ENABLE_LOGGING_AND_PROFILING 930 state.set_external_callback(v8::ToCData<Address>(callback_obj)); 931 #endif 932 value = callback(new_args); 933 } 934 if (value.IsEmpty()) { 935 result = Heap::undefined_value(); 936 } else { 937 result = *reinterpret_cast<Object**>(*value); 938 } 939 } 940 // Check for exceptions and return result. 941 RETURN_IF_SCHEDULED_EXCEPTION(); 942 return result; 943 } 944 945 946 // Handle calls to non-function objects created through the API. This delegate 947 // function is used when the call is a normal function call. 948 BUILTIN(HandleApiCallAsFunction) { 949 return HandleApiCallAsFunctionOrConstructor(false, args); 950 } 951 952 953 // Handle calls to non-function objects created through the API. This delegate 954 // function is used when the call is a construct call. 955 BUILTIN(HandleApiCallAsConstructor) { 956 return HandleApiCallAsFunctionOrConstructor(true, args); 957 } 958 959 960 static void Generate_LoadIC_ArrayLength(MacroAssembler* masm) { 961 LoadIC::GenerateArrayLength(masm); 962 } 963 964 965 static void Generate_LoadIC_StringLength(MacroAssembler* masm) { 966 LoadIC::GenerateStringLength(masm); 967 } 968 969 970 static void Generate_LoadIC_FunctionPrototype(MacroAssembler* masm) { 971 LoadIC::GenerateFunctionPrototype(masm); 972 } 973 974 975 static void Generate_LoadIC_Initialize(MacroAssembler* masm) { 976 LoadIC::GenerateInitialize(masm); 977 } 978 979 980 static void Generate_LoadIC_PreMonomorphic(MacroAssembler* masm) { 981 LoadIC::GeneratePreMonomorphic(masm); 982 } 983 984 985 static void Generate_LoadIC_Miss(MacroAssembler* masm) { 986 LoadIC::GenerateMiss(masm); 987 } 988 989 990 static void Generate_LoadIC_Megamorphic(MacroAssembler* masm) { 991 LoadIC::GenerateMegamorphic(masm); 992 } 993 994 995 static void Generate_LoadIC_Normal(MacroAssembler* masm) { 996 LoadIC::GenerateNormal(masm); 997 } 998 999 1000 static void Generate_KeyedLoadIC_Initialize(MacroAssembler* masm) { 1001 KeyedLoadIC::GenerateInitialize(masm); 1002 } 1003 1004 1005 static void Generate_KeyedLoadIC_Miss(MacroAssembler* masm) { 1006 KeyedLoadIC::GenerateMiss(masm); 1007 } 1008 1009 1010 static void Generate_KeyedLoadIC_Generic(MacroAssembler* masm) { 1011 KeyedLoadIC::GenerateGeneric(masm); 1012 } 1013 1014 1015 static void Generate_KeyedLoadIC_String(MacroAssembler* masm) { 1016 KeyedLoadIC::GenerateString(masm); 1017 } 1018 1019 1020 static void Generate_KeyedLoadIC_ExternalByteArray(MacroAssembler* masm) { 1021 KeyedLoadIC::GenerateExternalArray(masm, kExternalByteArray); 1022 } 1023 1024 1025 static void Generate_KeyedLoadIC_ExternalUnsignedByteArray( 1026 MacroAssembler* masm) { 1027 KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedByteArray); 1028 } 1029 1030 1031 static void Generate_KeyedLoadIC_ExternalShortArray(MacroAssembler* masm) { 1032 KeyedLoadIC::GenerateExternalArray(masm, kExternalShortArray); 1033 } 1034 1035 1036 static void Generate_KeyedLoadIC_ExternalUnsignedShortArray( 1037 MacroAssembler* masm) { 1038 KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedShortArray); 1039 } 1040 1041 1042 static void Generate_KeyedLoadIC_ExternalIntArray(MacroAssembler* masm) { 1043 KeyedLoadIC::GenerateExternalArray(masm, kExternalIntArray); 1044 } 1045 1046 1047 static void Generate_KeyedLoadIC_ExternalUnsignedIntArray( 1048 MacroAssembler* masm) { 1049 KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedIntArray); 1050 } 1051 1052 1053 static void Generate_KeyedLoadIC_ExternalFloatArray(MacroAssembler* masm) { 1054 KeyedLoadIC::GenerateExternalArray(masm, kExternalFloatArray); 1055 } 1056 1057 1058 static void Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler* masm) { 1059 KeyedLoadIC::GeneratePreMonomorphic(masm); 1060 } 1061 1062 static void Generate_KeyedLoadIC_IndexedInterceptor(MacroAssembler* masm) { 1063 KeyedLoadIC::GenerateIndexedInterceptor(masm); 1064 } 1065 1066 1067 static void Generate_StoreIC_Initialize(MacroAssembler* masm) { 1068 StoreIC::GenerateInitialize(masm); 1069 } 1070 1071 1072 static void Generate_StoreIC_Miss(MacroAssembler* masm) { 1073 StoreIC::GenerateMiss(masm); 1074 } 1075 1076 1077 static void Generate_StoreIC_Megamorphic(MacroAssembler* masm) { 1078 StoreIC::GenerateMegamorphic(masm); 1079 } 1080 1081 1082 static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) { 1083 KeyedStoreIC::GenerateGeneric(masm); 1084 } 1085 1086 1087 static void Generate_KeyedStoreIC_ExternalByteArray(MacroAssembler* masm) { 1088 KeyedStoreIC::GenerateExternalArray(masm, kExternalByteArray); 1089 } 1090 1091 1092 static void Generate_KeyedStoreIC_ExternalUnsignedByteArray( 1093 MacroAssembler* masm) { 1094 KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedByteArray); 1095 } 1096 1097 1098 static void Generate_KeyedStoreIC_ExternalShortArray(MacroAssembler* masm) { 1099 KeyedStoreIC::GenerateExternalArray(masm, kExternalShortArray); 1100 } 1101 1102 1103 static void Generate_KeyedStoreIC_ExternalUnsignedShortArray( 1104 MacroAssembler* masm) { 1105 KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedShortArray); 1106 } 1107 1108 1109 static void Generate_KeyedStoreIC_ExternalIntArray(MacroAssembler* masm) { 1110 KeyedStoreIC::GenerateExternalArray(masm, kExternalIntArray); 1111 } 1112 1113 1114 static void Generate_KeyedStoreIC_ExternalUnsignedIntArray( 1115 MacroAssembler* masm) { 1116 KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedIntArray); 1117 } 1118 1119 1120 static void Generate_KeyedStoreIC_ExternalFloatArray(MacroAssembler* masm) { 1121 KeyedStoreIC::GenerateExternalArray(masm, kExternalFloatArray); 1122 } 1123 1124 1125 static void Generate_KeyedStoreIC_Miss(MacroAssembler* masm) { 1126 KeyedStoreIC::GenerateMiss(masm); 1127 } 1128 1129 1130 static void Generate_KeyedStoreIC_Initialize(MacroAssembler* masm) { 1131 KeyedStoreIC::GenerateInitialize(masm); 1132 } 1133 1134 1135 #ifdef ENABLE_DEBUGGER_SUPPORT 1136 static void Generate_LoadIC_DebugBreak(MacroAssembler* masm) { 1137 Debug::GenerateLoadICDebugBreak(masm); 1138 } 1139 1140 1141 static void Generate_StoreIC_DebugBreak(MacroAssembler* masm) { 1142 Debug::GenerateStoreICDebugBreak(masm); 1143 } 1144 1145 1146 static void Generate_KeyedLoadIC_DebugBreak(MacroAssembler* masm) { 1147 Debug::GenerateKeyedLoadICDebugBreak(masm); 1148 } 1149 1150 1151 static void Generate_KeyedStoreIC_DebugBreak(MacroAssembler* masm) { 1152 Debug::GenerateKeyedStoreICDebugBreak(masm); 1153 } 1154 1155 1156 static void Generate_ConstructCall_DebugBreak(MacroAssembler* masm) { 1157 Debug::GenerateConstructCallDebugBreak(masm); 1158 } 1159 1160 1161 static void Generate_Return_DebugBreak(MacroAssembler* masm) { 1162 Debug::GenerateReturnDebugBreak(masm); 1163 } 1164 1165 1166 static void Generate_StubNoRegisters_DebugBreak(MacroAssembler* masm) { 1167 Debug::GenerateStubNoRegistersDebugBreak(masm); 1168 } 1169 #endif 1170 1171 Object* Builtins::builtins_[builtin_count] = { NULL, }; 1172 const char* Builtins::names_[builtin_count] = { NULL, }; 1173 1174 #define DEF_ENUM_C(name, ignore) FUNCTION_ADDR(Builtin_##name), 1175 Address Builtins::c_functions_[cfunction_count] = { 1176 BUILTIN_LIST_C(DEF_ENUM_C) 1177 }; 1178 #undef DEF_ENUM_C 1179 1180 #define DEF_JS_NAME(name, ignore) #name, 1181 #define DEF_JS_ARGC(ignore, argc) argc, 1182 const char* Builtins::javascript_names_[id_count] = { 1183 BUILTINS_LIST_JS(DEF_JS_NAME) 1184 }; 1185 1186 int Builtins::javascript_argc_[id_count] = { 1187 BUILTINS_LIST_JS(DEF_JS_ARGC) 1188 }; 1189 #undef DEF_JS_NAME 1190 #undef DEF_JS_ARGC 1191 1192 static bool is_initialized = false; 1193 void Builtins::Setup(bool create_heap_objects) { 1194 ASSERT(!is_initialized); 1195 1196 // Create a scope for the handles in the builtins. 1197 HandleScope scope; 1198 1199 struct BuiltinDesc { 1200 byte* generator; 1201 byte* c_code; 1202 const char* s_name; // name is only used for generating log information. 1203 int name; 1204 Code::Flags flags; 1205 BuiltinExtraArguments extra_args; 1206 }; 1207 1208 #define DEF_FUNCTION_PTR_C(name, extra_args) \ 1209 { FUNCTION_ADDR(Generate_Adaptor), \ 1210 FUNCTION_ADDR(Builtin_##name), \ 1211 #name, \ 1212 c_##name, \ 1213 Code::ComputeFlags(Code::BUILTIN), \ 1214 extra_args \ 1215 }, 1216 1217 #define DEF_FUNCTION_PTR_A(name, kind, state) \ 1218 { FUNCTION_ADDR(Generate_##name), \ 1219 NULL, \ 1220 #name, \ 1221 name, \ 1222 Code::ComputeFlags(Code::kind, NOT_IN_LOOP, state), \ 1223 NO_EXTRA_ARGUMENTS \ 1224 }, 1225 1226 // Define array of pointers to generators and C builtin functions. 1227 static BuiltinDesc functions[] = { 1228 BUILTIN_LIST_C(DEF_FUNCTION_PTR_C) 1229 BUILTIN_LIST_A(DEF_FUNCTION_PTR_A) 1230 BUILTIN_LIST_DEBUG_A(DEF_FUNCTION_PTR_A) 1231 // Terminator: 1232 { NULL, NULL, NULL, builtin_count, static_cast<Code::Flags>(0), 1233 NO_EXTRA_ARGUMENTS } 1234 }; 1235 1236 #undef DEF_FUNCTION_PTR_C 1237 #undef DEF_FUNCTION_PTR_A 1238 1239 // For now we generate builtin adaptor code into a stack-allocated 1240 // buffer, before copying it into individual code objects. 1241 byte buffer[4*KB]; 1242 1243 // Traverse the list of builtins and generate an adaptor in a 1244 // separate code object for each one. 1245 for (int i = 0; i < builtin_count; i++) { 1246 if (create_heap_objects) { 1247 MacroAssembler masm(buffer, sizeof buffer); 1248 // Generate the code/adaptor. 1249 typedef void (*Generator)(MacroAssembler*, int, BuiltinExtraArguments); 1250 Generator g = FUNCTION_CAST<Generator>(functions[i].generator); 1251 // We pass all arguments to the generator, but it may not use all of 1252 // them. This works because the first arguments are on top of the 1253 // stack. 1254 g(&masm, functions[i].name, functions[i].extra_args); 1255 // Move the code into the object heap. 1256 CodeDesc desc; 1257 masm.GetCode(&desc); 1258 Code::Flags flags = functions[i].flags; 1259 Object* code; 1260 { 1261 // During startup it's OK to always allocate and defer GC to later. 1262 // This simplifies things because we don't need to retry. 1263 AlwaysAllocateScope __scope__; 1264 code = Heap::CreateCode(desc, NULL, flags, masm.CodeObject()); 1265 if (code->IsFailure()) { 1266 v8::internal::V8::FatalProcessOutOfMemory("CreateCode"); 1267 } 1268 } 1269 // Log the event and add the code to the builtins array. 1270 LOG(CodeCreateEvent(Logger::BUILTIN_TAG, 1271 Code::cast(code), functions[i].s_name)); 1272 builtins_[i] = code; 1273 #ifdef ENABLE_DISASSEMBLER 1274 if (FLAG_print_builtin_code) { 1275 PrintF("Builtin: %s\n", functions[i].s_name); 1276 Code::cast(code)->Disassemble(functions[i].s_name); 1277 PrintF("\n"); 1278 } 1279 #endif 1280 } else { 1281 // Deserializing. The values will be filled in during IterateBuiltins. 1282 builtins_[i] = NULL; 1283 } 1284 names_[i] = functions[i].s_name; 1285 } 1286 1287 // Mark as initialized. 1288 is_initialized = true; 1289 } 1290 1291 1292 void Builtins::TearDown() { 1293 is_initialized = false; 1294 } 1295 1296 1297 void Builtins::IterateBuiltins(ObjectVisitor* v) { 1298 v->VisitPointers(&builtins_[0], &builtins_[0] + builtin_count); 1299 } 1300 1301 1302 const char* Builtins::Lookup(byte* pc) { 1303 if (is_initialized) { // may be called during initialization (disassembler!) 1304 for (int i = 0; i < builtin_count; i++) { 1305 Code* entry = Code::cast(builtins_[i]); 1306 if (entry->contains(pc)) { 1307 return names_[i]; 1308 } 1309 } 1310 } 1311 return NULL; 1312 } 1313 1314 1315 } } // namespace v8::internal 1316