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