| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 400 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 411 __ CallExternalReference( | 411 __ CallExternalReference( |
| 412 ExternalReference(IC_Utility(id), masm->isolate()), | 412 ExternalReference(IC_Utility(id), masm->isolate()), |
| 413 StubCache::kInterceptorArgsLength); | 413 StubCache::kInterceptorArgsLength); |
| 414 } | 414 } |
| 415 | 415 |
| 416 | 416 |
| 417 // Number of pointers to be reserved on stack for fast API call. | 417 // Number of pointers to be reserved on stack for fast API call. |
| 418 static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength; | 418 static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength; |
| 419 | 419 |
| 420 | 420 |
| 421 // Reserves space for the extra arguments to API function in the | |
| 422 // caller's frame. | |
| 423 // | |
| 424 // These arguments are set by CheckPrototypes and GenerateFastApiCall. | |
| 425 static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) { | |
| 426 // ----------- S t a t e ------------- | |
| 427 // -- esp[0] : return address | |
| 428 // -- esp[4] : last argument in the internal frame of the caller | |
| 429 // ----------------------------------- | |
| 430 __ pop(scratch); | |
| 431 for (int i = 0; i < kFastApiCallArguments; i++) { | |
| 432 __ push(Immediate(Smi::FromInt(0))); | |
| 433 } | |
| 434 __ push(scratch); | |
| 435 } | |
| 436 | |
| 437 | |
| 438 // Undoes the effects of ReserveSpaceForFastApiCall. | |
| 439 static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) { | |
| 440 // ----------- S t a t e ------------- | |
| 441 // -- esp[0] : return address. | |
| 442 // -- esp[4] : last fast api call extra argument. | |
| 443 // -- ... | |
| 444 // -- esp[kFastApiCallArguments * 4] : first fast api call extra argument. | |
| 445 // -- esp[kFastApiCallArguments * 4 + 4] : last argument in the internal | |
| 446 // frame. | |
| 447 // ----------------------------------- | |
| 448 __ pop(scratch); | |
| 449 __ add(esp, Immediate(kPointerSize * kFastApiCallArguments)); | |
| 450 __ push(scratch); | |
| 451 } | |
| 452 | |
| 453 | |
| 454 static void GenerateFastApiCallBody(MacroAssembler* masm, | 421 static void GenerateFastApiCallBody(MacroAssembler* masm, |
| 455 const CallOptimization& optimization, | 422 const CallOptimization& optimization, |
| 456 int argc, | 423 int argc, |
| 424 Register holder, |
| 425 Register scratch1, |
| 426 Register scratch2, |
| 427 Register scratch3, |
| 457 bool restore_context); | 428 bool restore_context); |
| 458 | 429 |
| 459 | |
| 460 // Generates call to API function. | 430 // Generates call to API function. |
| 461 static void GenerateFastApiCall(MacroAssembler* masm, | 431 static void GenerateFastApiCall(MacroAssembler* masm, |
| 462 const CallOptimization& optimization, | 432 const CallOptimization& optimization, |
| 463 int argc) { | 433 int argc, |
| 464 typedef FunctionCallbackArguments FCA; | 434 Handle<Map> map_to_holder, |
| 465 // Save calling context. | 435 CallOptimization::HolderLookup holder_lookup) { |
| 466 __ mov(Operand(esp, (1 + FCA::kContextSaveIndex) * kPointerSize), esi); | 436 Counters* counters = masm->isolate()->counters(); |
| 437 __ IncrementCounter(counters->call_const_fast_api(), 1); |
| 467 | 438 |
| 468 // Get the function and setup the context. | 439 // Move holder to a register |
| 469 Handle<JSFunction> function = optimization.constant_function(); | 440 Register holder_reg = eax; |
| 470 __ LoadHeapObject(edi, function); | 441 switch (holder_lookup) { |
| 471 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); | 442 case CallOptimization::kHolderIsReceiver: |
| 472 | 443 { |
| 473 // Construct the FunctionCallbackInfo. | 444 ASSERT(map_to_holder.is_null()); |
| 474 __ mov(Operand(esp, (1 + FCA::kCalleeIndex) * kPointerSize), edi); | 445 __ mov(holder_reg, Operand(esp, (argc + 1)* kPointerSize)); |
| 475 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); | 446 } |
| 476 Handle<Object> call_data(api_call_info->data(), masm->isolate()); | 447 break; |
| 477 if (masm->isolate()->heap()->InNewSpace(*call_data)) { | 448 case CallOptimization::kHolderIsPrototypeOfMap: |
| 478 __ mov(ecx, api_call_info); | 449 { |
| 479 __ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kDataOffset)); | 450 Handle<JSObject> holder(JSObject::cast(map_to_holder->prototype())); |
| 480 __ mov(Operand(esp, (1 + FCA::kDataIndex) * kPointerSize), ebx); | 451 if (!masm->isolate()->heap()->InNewSpace(*holder)) { |
| 481 } else { | 452 __ mov(holder_reg, holder); |
| 482 __ mov(Operand(esp, (1 + FCA::kDataIndex) * kPointerSize), | 453 } else { |
| 483 Immediate(call_data)); | 454 __ mov(holder_reg, map_to_holder); |
| 455 __ mov(holder_reg, FieldOperand(holder_reg, Map::kPrototypeOffset)); |
| 456 } |
| 457 } |
| 458 break; |
| 459 case CallOptimization::kHolderNotFound: |
| 460 UNREACHABLE(); |
| 484 } | 461 } |
| 485 __ mov(Operand(esp, (1 + FCA::kIsolateIndex) * kPointerSize), | 462 GenerateFastApiCallBody(masm, |
| 486 Immediate(reinterpret_cast<int>(masm->isolate()))); | 463 optimization, |
| 487 __ mov(Operand(esp, (1 + FCA::kReturnValueOffset) * kPointerSize), | 464 argc, |
| 488 masm->isolate()->factory()->undefined_value()); | 465 holder_reg, |
| 489 __ mov(Operand(esp, (1 + FCA::kReturnValueDefaultValueIndex) * kPointerSize), | 466 ebx, |
| 490 masm->isolate()->factory()->undefined_value()); | 467 ecx, |
| 491 | 468 edx, |
| 492 // Prepare arguments. | 469 false); |
| 493 STATIC_ASSERT(kFastApiCallArguments == 7); | |
| 494 __ lea(eax, Operand(esp, 1 * kPointerSize)); | |
| 495 | |
| 496 GenerateFastApiCallBody(masm, optimization, argc, false); | |
| 497 } | 470 } |
| 498 | 471 |
| 499 | 472 |
| 500 // Generate call to api function. | 473 // Generate call to api function. |
| 501 // This function uses push() to generate smaller, faster code than | 474 // This function uses push() to generate smaller, faster code than |
| 502 // the version above. It is an optimization that should will be removed | 475 // the version above. It is an optimization that should will be removed |
| 503 // when api call ICs are generated in hydrogen. | 476 // when api call ICs are generated in hydrogen. |
| 504 static void GenerateFastApiCall(MacroAssembler* masm, | 477 static void GenerateFastApiCall(MacroAssembler* masm, |
| 505 const CallOptimization& optimization, | 478 const CallOptimization& optimization, |
| 506 Register receiver, | 479 Register receiver, |
| 507 Register scratch1, | 480 Register scratch1, |
| 508 Register scratch2, | 481 Register scratch2, |
| 509 Register scratch3, | 482 Register scratch3, |
| 510 int argc, | 483 int argc, |
| 511 Register* values) { | 484 Register* values) { |
| 512 ASSERT(optimization.is_simple_api_call()); | |
| 513 | |
| 514 // Copy return value. | 485 // Copy return value. |
| 515 __ pop(scratch1); | 486 __ pop(scratch1); |
| 516 | |
| 517 // receiver | 487 // receiver |
| 518 __ push(receiver); | 488 __ push(receiver); |
| 519 | |
| 520 // Write the arguments to stack frame. | 489 // Write the arguments to stack frame. |
| 521 for (int i = 0; i < argc; i++) { | 490 for (int i = 0; i < argc; i++) { |
| 522 Register arg = values[argc-1-i]; | 491 Register arg = values[argc-1-i]; |
| 523 ASSERT(!receiver.is(arg)); | 492 ASSERT(!receiver.is(arg)); |
| 524 ASSERT(!scratch1.is(arg)); | 493 ASSERT(!scratch1.is(arg)); |
| 525 ASSERT(!scratch2.is(arg)); | 494 ASSERT(!scratch2.is(arg)); |
| 526 ASSERT(!scratch3.is(arg)); | 495 ASSERT(!scratch3.is(arg)); |
| 527 __ push(arg); | 496 __ push(arg); |
| 528 } | 497 } |
| 498 __ push(scratch1); |
| 499 // Stack now matches JSFunction abi. |
| 500 GenerateFastApiCallBody(masm, |
| 501 optimization, |
| 502 argc, |
| 503 receiver, |
| 504 scratch1, |
| 505 scratch2, |
| 506 scratch3, |
| 507 true); |
| 508 } |
| 509 |
| 510 |
| 511 static void GenerateFastApiCallBody(MacroAssembler* masm, |
| 512 const CallOptimization& optimization, |
| 513 int argc, |
| 514 Register holder, |
| 515 Register scratch1, |
| 516 Register scratch2, |
| 517 Register scratch3, |
| 518 bool restore_context) { |
| 519 // ----------- S t a t e ------------- |
| 520 // -- esp[0] : return address |
| 521 // -- esp[4] : last argument |
| 522 // -- ... |
| 523 // -- esp[argc * 4] : first argument |
| 524 // -- esp[(argc + 1) * 4] : receiver |
| 525 ASSERT(optimization.is_simple_api_call()); |
| 529 | 526 |
| 530 typedef FunctionCallbackArguments FCA; | 527 typedef FunctionCallbackArguments FCA; |
| 531 | 528 |
| 532 STATIC_ASSERT(FCA::kHolderIndex == 0); | 529 STATIC_ASSERT(FCA::kHolderIndex == 0); |
| 533 STATIC_ASSERT(FCA::kIsolateIndex == 1); | 530 STATIC_ASSERT(FCA::kIsolateIndex == 1); |
| 534 STATIC_ASSERT(FCA::kReturnValueDefaultValueIndex == 2); | 531 STATIC_ASSERT(FCA::kReturnValueDefaultValueIndex == 2); |
| 535 STATIC_ASSERT(FCA::kReturnValueOffset == 3); | 532 STATIC_ASSERT(FCA::kReturnValueOffset == 3); |
| 536 STATIC_ASSERT(FCA::kDataIndex == 4); | 533 STATIC_ASSERT(FCA::kDataIndex == 4); |
| 537 STATIC_ASSERT(FCA::kCalleeIndex == 5); | 534 STATIC_ASSERT(FCA::kCalleeIndex == 5); |
| 538 STATIC_ASSERT(FCA::kContextSaveIndex == 6); | 535 STATIC_ASSERT(FCA::kContextSaveIndex == 6); |
| 539 STATIC_ASSERT(FCA::kArgsLength == 7); | 536 STATIC_ASSERT(FCA::kArgsLength == 7); |
| 540 | 537 |
| 538 __ pop(scratch1); |
| 539 |
| 540 ASSERT(!holder.is(esi)); |
| 541 // context save | 541 // context save |
| 542 __ push(esi); | 542 __ push(esi); |
| 543 | 543 |
| 544 // Get the function and setup the context. | 544 // Get the function and setup the context. |
| 545 Handle<JSFunction> function = optimization.constant_function(); | 545 Handle<JSFunction> function = optimization.constant_function(); |
| 546 __ LoadHeapObject(scratch2, function); | 546 __ LoadHeapObject(scratch2, function); |
| 547 __ mov(esi, FieldOperand(scratch2, JSFunction::kContextOffset)); | 547 __ mov(esi, FieldOperand(scratch2, JSFunction::kContextOffset)); |
| 548 // callee | 548 // callee |
| 549 __ push(scratch2); | 549 __ push(scratch2); |
| 550 | 550 |
| 551 Isolate* isolate = masm->isolate(); | 551 Isolate* isolate = masm->isolate(); |
| 552 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); | 552 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); |
| 553 Handle<Object> call_data(api_call_info->data(), isolate); | 553 Handle<Object> call_data(api_call_info->data(), isolate); |
| 554 // Push data from ExecutableAccessorInfo. | 554 // Push data from ExecutableAccessorInfo. |
| 555 if (isolate->heap()->InNewSpace(*call_data)) { | 555 if (isolate->heap()->InNewSpace(*call_data)) { |
| 556 __ mov(scratch2, api_call_info); | 556 __ mov(scratch2, api_call_info); |
| 557 __ mov(scratch3, FieldOperand(scratch2, CallHandlerInfo::kDataOffset)); | 557 __ mov(scratch3, FieldOperand(scratch2, CallHandlerInfo::kDataOffset)); |
| 558 __ push(scratch3); | 558 __ push(scratch3); |
| 559 } else { | 559 } else { |
| 560 __ push(Immediate(call_data)); | 560 __ push(Immediate(call_data)); |
| 561 } | 561 } |
| 562 // return value | 562 // return value |
| 563 __ push(Immediate(isolate->factory()->undefined_value())); | 563 __ push(Immediate(isolate->factory()->undefined_value())); |
| 564 // return value default | 564 // return value default |
| 565 __ push(Immediate(isolate->factory()->undefined_value())); | 565 __ push(Immediate(isolate->factory()->undefined_value())); |
| 566 // isolate | 566 // isolate |
| 567 __ push(Immediate(reinterpret_cast<int>(isolate))); | 567 __ push(Immediate(reinterpret_cast<int>(isolate))); |
| 568 // holder | 568 // holder |
| 569 __ push(receiver); | 569 __ push(holder); |
| 570 | 570 |
| 571 // store receiver address for GenerateFastApiCallBody | 571 // store receiver address for GenerateFastApiCallBody |
| 572 ASSERT(!scratch1.is(eax)); | 572 ASSERT(!scratch1.is(eax)); |
| 573 __ mov(eax, esp); | 573 __ mov(eax, esp); |
| 574 | 574 |
| 575 // return address | 575 // return address |
| 576 __ push(scratch1); | 576 __ push(scratch1); |
| 577 | 577 |
| 578 GenerateFastApiCallBody(masm, optimization, argc, true); | |
| 579 } | |
| 580 | |
| 581 | |
| 582 static void GenerateFastApiCallBody(MacroAssembler* masm, | |
| 583 const CallOptimization& optimization, | |
| 584 int argc, | |
| 585 bool restore_context) { | |
| 586 // ----------- S t a t e ------------- | |
| 587 // -- esp[0] : return address | |
| 588 // -- esp[4] - esp[28] : FunctionCallbackInfo, incl. | |
| 589 // : object passing the type check | |
| 590 // (set by CheckPrototypes) | |
| 591 // -- esp[32] : last argument | |
| 592 // -- ... | |
| 593 // -- esp[(argc + 7) * 4] : first argument | |
| 594 // -- esp[(argc + 8) * 4] : receiver | |
| 595 // | |
| 596 // -- eax : receiver address | |
| 597 // ----------------------------------- | |
| 598 typedef FunctionCallbackArguments FCA; | |
| 599 | |
| 600 // API function gets reference to the v8::Arguments. If CPU profiler | 578 // API function gets reference to the v8::Arguments. If CPU profiler |
| 601 // is enabled wrapper function will be called and we need to pass | 579 // is enabled wrapper function will be called and we need to pass |
| 602 // address of the callback as additional parameter, always allocate | 580 // address of the callback as additional parameter, always allocate |
| 603 // space for it. | 581 // space for it. |
| 604 const int kApiArgc = 1 + 1; | 582 const int kApiArgc = 1 + 1; |
| 605 | 583 |
| 606 // Allocate the v8::Arguments structure in the arguments' space since | 584 // Allocate the v8::Arguments structure in the arguments' space since |
| 607 // it's not controlled by GC. | 585 // it's not controlled by GC. |
| 608 const int kApiStackSpace = 4; | 586 const int kApiStackSpace = 4; |
| 609 | 587 |
| 610 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); | |
| 611 | |
| 612 // Function address is a foreign pointer outside V8's heap. | 588 // Function address is a foreign pointer outside V8's heap. |
| 613 Address function_address = v8::ToCData<Address>(api_call_info->callback()); | 589 Address function_address = v8::ToCData<Address>(api_call_info->callback()); |
| 614 __ PrepareCallApiFunction(kApiArgc + kApiStackSpace); | 590 __ PrepareCallApiFunction(kApiArgc + kApiStackSpace); |
| 615 | 591 |
| 616 // FunctionCallbackInfo::implicit_args_. | 592 // FunctionCallbackInfo::implicit_args_. |
| 617 __ mov(ApiParameterOperand(2), eax); | 593 __ mov(ApiParameterOperand(2), eax); |
| 618 __ add(eax, Immediate((argc + kFastApiCallArguments - 1) * kPointerSize)); | 594 __ add(eax, Immediate((argc + kFastApiCallArguments - 1) * kPointerSize)); |
| 619 // FunctionCallbackInfo::values_. | 595 // FunctionCallbackInfo::values_. |
| 620 __ mov(ApiParameterOperand(3), eax); | 596 __ mov(ApiParameterOperand(3), eax); |
| 621 // FunctionCallbackInfo::length_. | 597 // FunctionCallbackInfo::length_. |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 686 Register scratch2, | 662 Register scratch2, |
| 687 Register scratch3, | 663 Register scratch3, |
| 688 Handle<JSObject> interceptor_holder, | 664 Handle<JSObject> interceptor_holder, |
| 689 LookupResult* lookup, | 665 LookupResult* lookup, |
| 690 Handle<Name> name, | 666 Handle<Name> name, |
| 691 const CallOptimization& optimization, | 667 const CallOptimization& optimization, |
| 692 Label* miss_label) { | 668 Label* miss_label) { |
| 693 ASSERT(optimization.is_constant_call()); | 669 ASSERT(optimization.is_constant_call()); |
| 694 ASSERT(!lookup->holder()->IsGlobalObject()); | 670 ASSERT(!lookup->holder()->IsGlobalObject()); |
| 695 | 671 |
| 696 int depth1 = kInvalidProtoDepth; | |
| 697 int depth2 = kInvalidProtoDepth; | |
| 698 bool can_do_fast_api_call = false; | |
| 699 if (optimization.is_simple_api_call() && | |
| 700 !lookup->holder()->IsGlobalObject()) { | |
| 701 depth1 = optimization.GetPrototypeDepthOfExpectedType( | |
| 702 object, interceptor_holder); | |
| 703 if (depth1 == kInvalidProtoDepth) { | |
| 704 depth2 = optimization.GetPrototypeDepthOfExpectedType( | |
| 705 interceptor_holder, Handle<JSObject>(lookup->holder())); | |
| 706 } | |
| 707 can_do_fast_api_call = | |
| 708 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth; | |
| 709 } | |
| 710 | |
| 711 Counters* counters = masm->isolate()->counters(); | 672 Counters* counters = masm->isolate()->counters(); |
| 712 __ IncrementCounter(counters->call_const_interceptor(), 1); | 673 __ IncrementCounter(counters->call_const_interceptor(), 1); |
| 713 | 674 |
| 714 if (can_do_fast_api_call) { | |
| 715 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1); | |
| 716 ReserveSpaceForFastApiCall(masm, scratch1); | |
| 717 } | |
| 718 | |
| 719 // Check that the maps from receiver to interceptor's holder | 675 // Check that the maps from receiver to interceptor's holder |
| 720 // haven't changed and thus we can invoke interceptor. | 676 // haven't changed and thus we can invoke interceptor. |
| 721 Label miss_cleanup; | |
| 722 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label; | |
| 723 Register holder = | 677 Register holder = |
| 724 stub_compiler_->CheckPrototypes( | 678 stub_compiler_->CheckPrototypes( |
| 725 IC::CurrentTypeOf(object, masm->isolate()), receiver, | 679 IC::CurrentTypeOf(object, masm->isolate()), receiver, |
| 726 interceptor_holder, scratch1, scratch2, scratch3, | 680 interceptor_holder, scratch1, scratch2, scratch3, |
| 727 name, depth1, miss); | 681 name, miss_label); |
| 728 | 682 |
| 729 // Invoke an interceptor and if it provides a value, | 683 // Invoke an interceptor and if it provides a value, |
| 730 // branch to |regular_invoke|. | 684 // branch to |regular_invoke|. |
| 731 Label regular_invoke; | 685 Label regular_invoke; |
| 732 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, | 686 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, |
| 733 ®ular_invoke); | 687 ®ular_invoke); |
| 734 | 688 |
| 735 // Interceptor returned nothing for this property. Try to use cached | 689 // Interceptor returned nothing for this property. Try to use cached |
| 736 // constant function. | 690 // constant function. |
| 737 | 691 |
| 738 // Check that the maps from interceptor's holder to constant function's | 692 // Check that the maps from interceptor's holder to constant function's |
| 739 // holder haven't changed and thus we can use cached constant function. | 693 // holder haven't changed and thus we can use cached constant function. |
| 740 if (*interceptor_holder != lookup->holder()) { | 694 if (*interceptor_holder != lookup->holder()) { |
| 741 stub_compiler_->CheckPrototypes( | 695 stub_compiler_->CheckPrototypes( |
| 742 IC::CurrentTypeOf(interceptor_holder, masm->isolate()), holder, | 696 IC::CurrentTypeOf(interceptor_holder, masm->isolate()), holder, |
| 743 handle(lookup->holder()), scratch1, scratch2, scratch3, | 697 handle(lookup->holder()), scratch1, scratch2, scratch3, |
| 744 name, depth2, miss); | 698 name, miss_label); |
| 745 } else { | 699 } |
| 746 // CheckPrototypes has a side effect of fetching a 'holder' | 700 |
| 747 // for API (object which is instanceof for the signature). It's | 701 Handle<Map> lookup_map; |
| 748 // safe to omit it here, as if present, it should be fetched | 702 CallOptimization::HolderLookup holder_lookup = |
| 749 // by the previous CheckPrototypes. | 703 CallOptimization::kHolderNotFound; |
| 750 ASSERT(depth2 == kInvalidProtoDepth); | 704 if (optimization.is_simple_api_call() && |
| 705 !lookup->holder()->IsGlobalObject()) { |
| 706 lookup_map = optimization.LookupHolderOfExpectedType( |
| 707 object, object, interceptor_holder, &holder_lookup); |
| 708 if (holder_lookup == CallOptimization::kHolderNotFound) { |
| 709 lookup_map = |
| 710 optimization.LookupHolderOfExpectedType( |
| 711 object, |
| 712 interceptor_holder, |
| 713 Handle<JSObject>(lookup->holder()), |
| 714 &holder_lookup); |
| 715 } |
| 751 } | 716 } |
| 752 | 717 |
| 753 // Invoke function. | 718 // Invoke function. |
| 754 if (can_do_fast_api_call) { | 719 if (holder_lookup != CallOptimization::kHolderNotFound) { |
| 755 GenerateFastApiCall(masm, optimization, arguments_.immediate()); | 720 int argc = arguments_.immediate(); |
| 721 GenerateFastApiCall(masm, |
| 722 optimization, |
| 723 argc, |
| 724 lookup_map, |
| 725 holder_lookup); |
| 756 } else { | 726 } else { |
| 757 Handle<JSFunction> fun = optimization.constant_function(); | 727 Handle<JSFunction> fun = optimization.constant_function(); |
| 758 stub_compiler_->GenerateJumpFunction(object, fun); | 728 stub_compiler_->GenerateJumpFunction(object, fun); |
| 759 } | 729 } |
| 760 | 730 |
| 761 // Deferred code for fast API call case---clean preallocated space. | |
| 762 if (can_do_fast_api_call) { | |
| 763 __ bind(&miss_cleanup); | |
| 764 FreeSpaceForFastApiCall(masm, scratch1); | |
| 765 __ jmp(miss_label); | |
| 766 } | |
| 767 | |
| 768 // Invoke a regular function. | 731 // Invoke a regular function. |
| 769 __ bind(®ular_invoke); | 732 __ bind(®ular_invoke); |
| 770 if (can_do_fast_api_call) { | |
| 771 FreeSpaceForFastApiCall(masm, scratch1); | |
| 772 } | |
| 773 } | 733 } |
| 774 | 734 |
| 775 void CompileRegular(MacroAssembler* masm, | 735 void CompileRegular(MacroAssembler* masm, |
| 776 Handle<JSObject> object, | 736 Handle<JSObject> object, |
| 777 Register receiver, | 737 Register receiver, |
| 778 Register scratch1, | 738 Register scratch1, |
| 779 Register scratch2, | 739 Register scratch2, |
| 780 Register scratch3, | 740 Register scratch3, |
| 781 Handle<Name> name, | 741 Handle<Name> name, |
| 782 Handle<JSObject> interceptor_holder, | 742 Handle<JSObject> interceptor_holder, |
| (...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1176 | 1136 |
| 1177 void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) { | 1137 void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) { |
| 1178 __ jmp(code, RelocInfo::CODE_TARGET); | 1138 __ jmp(code, RelocInfo::CODE_TARGET); |
| 1179 } | 1139 } |
| 1180 | 1140 |
| 1181 | 1141 |
| 1182 #undef __ | 1142 #undef __ |
| 1183 #define __ ACCESS_MASM(masm()) | 1143 #define __ ACCESS_MASM(masm()) |
| 1184 | 1144 |
| 1185 | 1145 |
| 1186 Register StubCompiler::CheckPrototypes(Handle<Type> type, | 1146 Register StubCompiler::CheckPrototypes(Handle<HeapType> type, |
| 1187 Register object_reg, | 1147 Register object_reg, |
| 1188 Handle<JSObject> holder, | 1148 Handle<JSObject> holder, |
| 1189 Register holder_reg, | 1149 Register holder_reg, |
| 1190 Register scratch1, | 1150 Register scratch1, |
| 1191 Register scratch2, | 1151 Register scratch2, |
| 1192 Handle<Name> name, | 1152 Handle<Name> name, |
| 1193 int save_at_depth, | |
| 1194 Label* miss, | 1153 Label* miss, |
| 1195 PrototypeCheckType check) { | 1154 PrototypeCheckType check) { |
| 1196 Handle<Map> receiver_map(IC::TypeToMap(*type, isolate())); | 1155 Handle<Map> receiver_map(IC::TypeToMap(*type, isolate())); |
| 1197 // Make sure that the type feedback oracle harvests the receiver map. | 1156 // Make sure that the type feedback oracle harvests the receiver map. |
| 1198 // TODO(svenpanne) Remove this hack when all ICs are reworked. | 1157 // TODO(svenpanne) Remove this hack when all ICs are reworked. |
| 1199 __ mov(scratch1, receiver_map); | 1158 __ mov(scratch1, receiver_map); |
| 1200 | 1159 |
| 1201 // Make sure there's no overlap between holder and object registers. | 1160 // Make sure there's no overlap between holder and object registers. |
| 1202 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); | 1161 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); |
| 1203 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg) | 1162 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg) |
| 1204 && !scratch2.is(scratch1)); | 1163 && !scratch2.is(scratch1)); |
| 1205 | 1164 |
| 1206 // Keep track of the current object in register reg. | 1165 // Keep track of the current object in register reg. |
| 1207 Register reg = object_reg; | 1166 Register reg = object_reg; |
| 1208 int depth = 0; | 1167 int depth = 0; |
| 1209 | 1168 |
| 1210 const int kHolderIndex = FunctionCallbackArguments::kHolderIndex + 1; | |
| 1211 if (save_at_depth == depth) { | |
| 1212 __ mov(Operand(esp, kHolderIndex * kPointerSize), reg); | |
| 1213 } | |
| 1214 | |
| 1215 Handle<JSObject> current = Handle<JSObject>::null(); | 1169 Handle<JSObject> current = Handle<JSObject>::null(); |
| 1216 if (type->IsConstant()) current = Handle<JSObject>::cast(type->AsConstant()); | 1170 if (type->IsConstant()) current = Handle<JSObject>::cast(type->AsConstant()); |
| 1217 Handle<JSObject> prototype = Handle<JSObject>::null(); | 1171 Handle<JSObject> prototype = Handle<JSObject>::null(); |
| 1218 Handle<Map> current_map = receiver_map; | 1172 Handle<Map> current_map = receiver_map; |
| 1219 Handle<Map> holder_map(holder->map()); | 1173 Handle<Map> holder_map(holder->map()); |
| 1220 // Traverse the prototype chain and check the maps in the prototype chain for | 1174 // Traverse the prototype chain and check the maps in the prototype chain for |
| 1221 // fast and global objects or do negative lookup for normal objects. | 1175 // fast and global objects or do negative lookup for normal objects. |
| 1222 while (!current_map.is_identical_to(holder_map)) { | 1176 while (!current_map.is_identical_to(holder_map)) { |
| 1223 ++depth; | 1177 ++depth; |
| 1224 | 1178 |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1272 if (in_new_space) { | 1226 if (in_new_space) { |
| 1273 // The prototype is in new space; we cannot store a reference to it | 1227 // The prototype is in new space; we cannot store a reference to it |
| 1274 // in the code. Load it from the map. | 1228 // in the code. Load it from the map. |
| 1275 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); | 1229 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); |
| 1276 } else { | 1230 } else { |
| 1277 // The prototype is in old space; load it directly. | 1231 // The prototype is in old space; load it directly. |
| 1278 __ mov(reg, prototype); | 1232 __ mov(reg, prototype); |
| 1279 } | 1233 } |
| 1280 } | 1234 } |
| 1281 | 1235 |
| 1282 if (save_at_depth == depth) { | |
| 1283 __ mov(Operand(esp, kHolderIndex * kPointerSize), reg); | |
| 1284 } | |
| 1285 | |
| 1286 // Go to the next object in the prototype chain. | 1236 // Go to the next object in the prototype chain. |
| 1287 current = prototype; | 1237 current = prototype; |
| 1288 current_map = handle(current->map()); | 1238 current_map = handle(current->map()); |
| 1289 } | 1239 } |
| 1290 | 1240 |
| 1291 // Log the check depth. | 1241 // Log the check depth. |
| 1292 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); | 1242 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); |
| 1293 | 1243 |
| 1294 if (depth != 0 || check == CHECK_ALL_MAPS) { | 1244 if (depth != 0 || check == CHECK_ALL_MAPS) { |
| 1295 // Check the holder map. | 1245 // Check the holder map. |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1324 Label success; | 1274 Label success; |
| 1325 __ jmp(&success); | 1275 __ jmp(&success); |
| 1326 GenerateRestoreName(masm(), miss, name); | 1276 GenerateRestoreName(masm(), miss, name); |
| 1327 TailCallBuiltin(masm(), MissBuiltin(kind())); | 1277 TailCallBuiltin(masm(), MissBuiltin(kind())); |
| 1328 __ bind(&success); | 1278 __ bind(&success); |
| 1329 } | 1279 } |
| 1330 } | 1280 } |
| 1331 | 1281 |
| 1332 | 1282 |
| 1333 Register LoadStubCompiler::CallbackHandlerFrontend( | 1283 Register LoadStubCompiler::CallbackHandlerFrontend( |
| 1334 Handle<Type> type, | 1284 Handle<HeapType> type, |
| 1335 Register object_reg, | 1285 Register object_reg, |
| 1336 Handle<JSObject> holder, | 1286 Handle<JSObject> holder, |
| 1337 Handle<Name> name, | 1287 Handle<Name> name, |
| 1338 Handle<Object> callback) { | 1288 Handle<Object> callback) { |
| 1339 Label miss; | 1289 Label miss; |
| 1340 | 1290 |
| 1341 Register reg = HandlerFrontendHeader(type, object_reg, holder, name, &miss); | 1291 Register reg = HandlerFrontendHeader(type, object_reg, holder, name, &miss); |
| 1342 | 1292 |
| 1343 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) { | 1293 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) { |
| 1344 ASSERT(!reg.is(scratch2())); | 1294 ASSERT(!reg.is(scratch2())); |
| (...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1659 index.translate(holder), Representation::Tagged()); | 1609 index.translate(holder), Representation::Tagged()); |
| 1660 GenerateJumpFunction(object, edi, &miss); | 1610 GenerateJumpFunction(object, edi, &miss); |
| 1661 | 1611 |
| 1662 HandlerFrontendFooter(&miss); | 1612 HandlerFrontendFooter(&miss); |
| 1663 | 1613 |
| 1664 // Return the generated code. | 1614 // Return the generated code. |
| 1665 return GetCode(Code::FAST, name); | 1615 return GetCode(Code::FAST, name); |
| 1666 } | 1616 } |
| 1667 | 1617 |
| 1668 | 1618 |
| 1669 Handle<Code> CallStubCompiler::CompileArrayCodeCall( | |
| 1670 Handle<Object> object, | |
| 1671 Handle<JSObject> holder, | |
| 1672 Handle<Cell> cell, | |
| 1673 Handle<JSFunction> function, | |
| 1674 Handle<String> name, | |
| 1675 Code::StubType type) { | |
| 1676 Label miss; | |
| 1677 | |
| 1678 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss); | |
| 1679 if (!cell.is_null()) { | |
| 1680 ASSERT(cell->value() == *function); | |
| 1681 GenerateLoadFunctionFromCell(cell, function, &miss); | |
| 1682 } | |
| 1683 | |
| 1684 Handle<AllocationSite> site = isolate()->factory()->NewAllocationSite(); | |
| 1685 site->SetElementsKind(GetInitialFastElementsKind()); | |
| 1686 Handle<Cell> site_feedback_cell = isolate()->factory()->NewCell(site); | |
| 1687 const int argc = arguments().immediate(); | |
| 1688 __ mov(eax, Immediate(argc)); | |
| 1689 __ mov(ebx, site_feedback_cell); | |
| 1690 __ mov(edi, function); | |
| 1691 | |
| 1692 ArrayConstructorStub stub(isolate()); | |
| 1693 __ TailCallStub(&stub); | |
| 1694 | |
| 1695 HandlerFrontendFooter(&miss); | |
| 1696 | |
| 1697 // Return the generated code. | |
| 1698 return GetCode(type, name); | |
| 1699 } | |
| 1700 | |
| 1701 | |
| 1702 Handle<Code> CallStubCompiler::CompileArrayPushCall( | |
| 1703 Handle<Object> object, | |
| 1704 Handle<JSObject> holder, | |
| 1705 Handle<Cell> cell, | |
| 1706 Handle<JSFunction> function, | |
| 1707 Handle<String> name, | |
| 1708 Code::StubType type) { | |
| 1709 // If object is not an array or is observed or sealed, bail out to regular | |
| 1710 // call. | |
| 1711 if (!object->IsJSArray() || | |
| 1712 !cell.is_null() || | |
| 1713 Handle<JSArray>::cast(object)->map()->is_observed() || | |
| 1714 !Handle<JSArray>::cast(object)->map()->is_extensible()) { | |
| 1715 return Handle<Code>::null(); | |
| 1716 } | |
| 1717 | |
| 1718 Label miss; | |
| 1719 | |
| 1720 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss); | |
| 1721 | |
| 1722 const int argc = arguments().immediate(); | |
| 1723 if (argc == 0) { | |
| 1724 // Noop, return the length. | |
| 1725 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset)); | |
| 1726 __ ret((argc + 1) * kPointerSize); | |
| 1727 } else { | |
| 1728 Label call_builtin; | |
| 1729 | |
| 1730 if (argc == 1) { // Otherwise fall through to call builtin. | |
| 1731 Label attempt_to_grow_elements, with_write_barrier, check_double; | |
| 1732 | |
| 1733 // Get the elements array of the object. | |
| 1734 __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset)); | |
| 1735 | |
| 1736 // Check that the elements are in fast mode and writable. | |
| 1737 __ cmp(FieldOperand(edi, HeapObject::kMapOffset), | |
| 1738 Immediate(factory()->fixed_array_map())); | |
| 1739 __ j(not_equal, &check_double); | |
| 1740 | |
| 1741 // Get the array's length into eax and calculate new length. | |
| 1742 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset)); | |
| 1743 STATIC_ASSERT(kSmiTagSize == 1); | |
| 1744 STATIC_ASSERT(kSmiTag == 0); | |
| 1745 __ add(eax, Immediate(Smi::FromInt(argc))); | |
| 1746 | |
| 1747 // Get the elements' length into ecx. | |
| 1748 __ mov(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); | |
| 1749 | |
| 1750 // Check if we could survive without allocation. | |
| 1751 __ cmp(eax, ecx); | |
| 1752 __ j(greater, &attempt_to_grow_elements); | |
| 1753 | |
| 1754 // Check if value is a smi. | |
| 1755 __ mov(ecx, Operand(esp, argc * kPointerSize)); | |
| 1756 __ JumpIfNotSmi(ecx, &with_write_barrier); | |
| 1757 | |
| 1758 // Save new length. | |
| 1759 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax); | |
| 1760 | |
| 1761 // Store the value. | |
| 1762 __ mov(FieldOperand(edi, | |
| 1763 eax, | |
| 1764 times_half_pointer_size, | |
| 1765 FixedArray::kHeaderSize - argc * kPointerSize), | |
| 1766 ecx); | |
| 1767 | |
| 1768 __ ret((argc + 1) * kPointerSize); | |
| 1769 | |
| 1770 __ bind(&check_double); | |
| 1771 | |
| 1772 | |
| 1773 // Check that the elements are in double mode. | |
| 1774 __ cmp(FieldOperand(edi, HeapObject::kMapOffset), | |
| 1775 Immediate(factory()->fixed_double_array_map())); | |
| 1776 __ j(not_equal, &call_builtin); | |
| 1777 | |
| 1778 // Get the array's length into eax and calculate new length. | |
| 1779 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset)); | |
| 1780 STATIC_ASSERT(kSmiTagSize == 1); | |
| 1781 STATIC_ASSERT(kSmiTag == 0); | |
| 1782 __ add(eax, Immediate(Smi::FromInt(argc))); | |
| 1783 | |
| 1784 // Get the elements' length into ecx. | |
| 1785 __ mov(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); | |
| 1786 | |
| 1787 // Check if we could survive without allocation. | |
| 1788 __ cmp(eax, ecx); | |
| 1789 __ j(greater, &call_builtin); | |
| 1790 | |
| 1791 __ mov(ecx, Operand(esp, argc * kPointerSize)); | |
| 1792 __ StoreNumberToDoubleElements( | |
| 1793 ecx, edi, eax, ecx, xmm0, &call_builtin, true, argc * kDoubleSize); | |
| 1794 | |
| 1795 // Save new length. | |
| 1796 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax); | |
| 1797 __ ret((argc + 1) * kPointerSize); | |
| 1798 | |
| 1799 __ bind(&with_write_barrier); | |
| 1800 | |
| 1801 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); | |
| 1802 | |
| 1803 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) { | |
| 1804 Label fast_object, not_fast_object; | |
| 1805 __ CheckFastObjectElements(ebx, ¬_fast_object, Label::kNear); | |
| 1806 __ jmp(&fast_object); | |
| 1807 // In case of fast smi-only, convert to fast object, otherwise bail out. | |
| 1808 __ bind(¬_fast_object); | |
| 1809 __ CheckFastSmiElements(ebx, &call_builtin); | |
| 1810 __ cmp(FieldOperand(ecx, HeapObject::kMapOffset), | |
| 1811 Immediate(factory()->heap_number_map())); | |
| 1812 __ j(equal, &call_builtin); | |
| 1813 // edi: elements array | |
| 1814 // edx: receiver | |
| 1815 // ebx: map | |
| 1816 Label try_holey_map; | |
| 1817 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, | |
| 1818 FAST_ELEMENTS, | |
| 1819 ebx, | |
| 1820 edi, | |
| 1821 &try_holey_map); | |
| 1822 | |
| 1823 ElementsTransitionGenerator:: | |
| 1824 GenerateMapChangeElementsTransition(masm(), | |
| 1825 DONT_TRACK_ALLOCATION_SITE, | |
| 1826 NULL); | |
| 1827 // Restore edi. | |
| 1828 __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset)); | |
| 1829 __ jmp(&fast_object); | |
| 1830 | |
| 1831 __ bind(&try_holey_map); | |
| 1832 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS, | |
| 1833 FAST_HOLEY_ELEMENTS, | |
| 1834 ebx, | |
| 1835 edi, | |
| 1836 &call_builtin); | |
| 1837 ElementsTransitionGenerator:: | |
| 1838 GenerateMapChangeElementsTransition(masm(), | |
| 1839 DONT_TRACK_ALLOCATION_SITE, | |
| 1840 NULL); | |
| 1841 // Restore edi. | |
| 1842 __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset)); | |
| 1843 __ bind(&fast_object); | |
| 1844 } else { | |
| 1845 __ CheckFastObjectElements(ebx, &call_builtin); | |
| 1846 } | |
| 1847 | |
| 1848 // Save new length. | |
| 1849 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax); | |
| 1850 | |
| 1851 // Store the value. | |
| 1852 __ lea(edx, FieldOperand(edi, | |
| 1853 eax, times_half_pointer_size, | |
| 1854 FixedArray::kHeaderSize - argc * kPointerSize)); | |
| 1855 __ mov(Operand(edx, 0), ecx); | |
| 1856 | |
| 1857 __ RecordWrite(edi, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, | |
| 1858 OMIT_SMI_CHECK); | |
| 1859 | |
| 1860 __ ret((argc + 1) * kPointerSize); | |
| 1861 | |
| 1862 __ bind(&attempt_to_grow_elements); | |
| 1863 if (!FLAG_inline_new) { | |
| 1864 __ jmp(&call_builtin); | |
| 1865 } | |
| 1866 | |
| 1867 __ mov(ebx, Operand(esp, argc * kPointerSize)); | |
| 1868 // Growing elements that are SMI-only requires special handling in case | |
| 1869 // the new element is non-Smi. For now, delegate to the builtin. | |
| 1870 Label no_fast_elements_check; | |
| 1871 __ JumpIfSmi(ebx, &no_fast_elements_check); | |
| 1872 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | |
| 1873 __ CheckFastObjectElements(ecx, &call_builtin, Label::kFar); | |
| 1874 __ bind(&no_fast_elements_check); | |
| 1875 | |
| 1876 // We could be lucky and the elements array could be at the top of | |
| 1877 // new-space. In this case we can just grow it in place by moving the | |
| 1878 // allocation pointer up. | |
| 1879 | |
| 1880 ExternalReference new_space_allocation_top = | |
| 1881 ExternalReference::new_space_allocation_top_address(isolate()); | |
| 1882 ExternalReference new_space_allocation_limit = | |
| 1883 ExternalReference::new_space_allocation_limit_address(isolate()); | |
| 1884 | |
| 1885 const int kAllocationDelta = 4; | |
| 1886 // Load top. | |
| 1887 __ mov(ecx, Operand::StaticVariable(new_space_allocation_top)); | |
| 1888 | |
| 1889 // Check if it's the end of elements. | |
| 1890 __ lea(edx, FieldOperand(edi, | |
| 1891 eax, times_half_pointer_size, | |
| 1892 FixedArray::kHeaderSize - argc * kPointerSize)); | |
| 1893 __ cmp(edx, ecx); | |
| 1894 __ j(not_equal, &call_builtin); | |
| 1895 __ add(ecx, Immediate(kAllocationDelta * kPointerSize)); | |
| 1896 __ cmp(ecx, Operand::StaticVariable(new_space_allocation_limit)); | |
| 1897 __ j(above, &call_builtin); | |
| 1898 | |
| 1899 // We fit and could grow elements. | |
| 1900 __ mov(Operand::StaticVariable(new_space_allocation_top), ecx); | |
| 1901 | |
| 1902 // Push the argument... | |
| 1903 __ mov(Operand(edx, 0), ebx); | |
| 1904 // ... and fill the rest with holes. | |
| 1905 for (int i = 1; i < kAllocationDelta; i++) { | |
| 1906 __ mov(Operand(edx, i * kPointerSize), | |
| 1907 Immediate(factory()->the_hole_value())); | |
| 1908 } | |
| 1909 | |
| 1910 // We know the elements array is in new space so we don't need the | |
| 1911 // remembered set, but we just pushed a value onto it so we may have to | |
| 1912 // tell the incremental marker to rescan the object that we just grew. We | |
| 1913 // don't need to worry about the holes because they are in old space and | |
| 1914 // already marked black. | |
| 1915 __ RecordWrite(edi, edx, ebx, kDontSaveFPRegs, OMIT_REMEMBERED_SET); | |
| 1916 | |
| 1917 // Restore receiver to edx as finish sequence assumes it's here. | |
| 1918 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | |
| 1919 | |
| 1920 // Increment element's and array's sizes. | |
| 1921 __ add(FieldOperand(edi, FixedArray::kLengthOffset), | |
| 1922 Immediate(Smi::FromInt(kAllocationDelta))); | |
| 1923 | |
| 1924 // NOTE: This only happen in new-space, where we don't | |
| 1925 // care about the black-byte-count on pages. Otherwise we should | |
| 1926 // update that too if the object is black. | |
| 1927 | |
| 1928 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax); | |
| 1929 | |
| 1930 __ ret((argc + 1) * kPointerSize); | |
| 1931 } | |
| 1932 | |
| 1933 __ bind(&call_builtin); | |
| 1934 __ TailCallExternalReference( | |
| 1935 ExternalReference(Builtins::c_ArrayPush, isolate()), | |
| 1936 argc + 1, | |
| 1937 1); | |
| 1938 } | |
| 1939 | |
| 1940 HandlerFrontendFooter(&miss); | |
| 1941 | |
| 1942 // Return the generated code. | |
| 1943 return GetCode(type, name); | |
| 1944 } | |
| 1945 | |
| 1946 | |
| 1947 Handle<Code> CallStubCompiler::CompileArrayPopCall( | |
| 1948 Handle<Object> object, | |
| 1949 Handle<JSObject> holder, | |
| 1950 Handle<Cell> cell, | |
| 1951 Handle<JSFunction> function, | |
| 1952 Handle<String> name, | |
| 1953 Code::StubType type) { | |
| 1954 // If object is not an array or is observed or sealed, bail out to regular | |
| 1955 // call. | |
| 1956 if (!object->IsJSArray() || | |
| 1957 !cell.is_null() || | |
| 1958 Handle<JSArray>::cast(object)->map()->is_observed() || | |
| 1959 !Handle<JSArray>::cast(object)->map()->is_extensible()) { | |
| 1960 return Handle<Code>::null(); | |
| 1961 } | |
| 1962 | |
| 1963 Label miss, return_undefined, call_builtin; | |
| 1964 | |
| 1965 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss); | |
| 1966 | |
| 1967 // Get the elements array of the object. | |
| 1968 __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset)); | |
| 1969 | |
| 1970 // Check that the elements are in fast mode and writable. | |
| 1971 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), | |
| 1972 Immediate(factory()->fixed_array_map())); | |
| 1973 __ j(not_equal, &call_builtin); | |
| 1974 | |
| 1975 // Get the array's length into ecx and calculate new length. | |
| 1976 __ mov(ecx, FieldOperand(edx, JSArray::kLengthOffset)); | |
| 1977 __ sub(ecx, Immediate(Smi::FromInt(1))); | |
| 1978 __ j(negative, &return_undefined); | |
| 1979 | |
| 1980 // Get the last element. | |
| 1981 STATIC_ASSERT(kSmiTagSize == 1); | |
| 1982 STATIC_ASSERT(kSmiTag == 0); | |
| 1983 __ mov(eax, FieldOperand(ebx, | |
| 1984 ecx, times_half_pointer_size, | |
| 1985 FixedArray::kHeaderSize)); | |
| 1986 __ cmp(eax, Immediate(factory()->the_hole_value())); | |
| 1987 __ j(equal, &call_builtin); | |
| 1988 | |
| 1989 // Set the array's length. | |
| 1990 __ mov(FieldOperand(edx, JSArray::kLengthOffset), ecx); | |
| 1991 | |
| 1992 // Fill with the hole. | |
| 1993 __ mov(FieldOperand(ebx, | |
| 1994 ecx, times_half_pointer_size, | |
| 1995 FixedArray::kHeaderSize), | |
| 1996 Immediate(factory()->the_hole_value())); | |
| 1997 const int argc = arguments().immediate(); | |
| 1998 __ ret((argc + 1) * kPointerSize); | |
| 1999 | |
| 2000 __ bind(&return_undefined); | |
| 2001 __ mov(eax, Immediate(factory()->undefined_value())); | |
| 2002 __ ret((argc + 1) * kPointerSize); | |
| 2003 | |
| 2004 __ bind(&call_builtin); | |
| 2005 __ TailCallExternalReference( | |
| 2006 ExternalReference(Builtins::c_ArrayPop, isolate()), | |
| 2007 argc + 1, | |
| 2008 1); | |
| 2009 | |
| 2010 HandlerFrontendFooter(&miss); | |
| 2011 | |
| 2012 // Return the generated code. | |
| 2013 return GetCode(type, name); | |
| 2014 } | |
| 2015 | |
| 2016 | |
| 2017 Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall( | |
| 2018 Handle<Object> object, | |
| 2019 Handle<JSObject> holder, | |
| 2020 Handle<Cell> cell, | |
| 2021 Handle<JSFunction> function, | |
| 2022 Handle<String> name, | |
| 2023 Code::StubType type) { | |
| 2024 // If object is not a string, bail out to regular call. | |
| 2025 if (!object->IsString() || !cell.is_null()) { | |
| 2026 return Handle<Code>::null(); | |
| 2027 } | |
| 2028 | |
| 2029 const int argc = arguments().immediate(); | |
| 2030 | |
| 2031 Label miss; | |
| 2032 Label name_miss; | |
| 2033 Label index_out_of_range; | |
| 2034 Label* index_out_of_range_label = &index_out_of_range; | |
| 2035 | |
| 2036 if (kind_ == Code::CALL_IC && | |
| 2037 (CallICBase::StringStubState::decode(extra_state()) == | |
| 2038 DEFAULT_STRING_STUB)) { | |
| 2039 index_out_of_range_label = &miss; | |
| 2040 } | |
| 2041 | |
| 2042 HandlerFrontendHeader(object, holder, name, STRING_CHECK, &name_miss); | |
| 2043 | |
| 2044 Register receiver = ebx; | |
| 2045 Register index = edi; | |
| 2046 Register result = eax; | |
| 2047 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize)); | |
| 2048 if (argc > 0) { | |
| 2049 __ mov(index, Operand(esp, (argc - 0) * kPointerSize)); | |
| 2050 } else { | |
| 2051 __ Set(index, Immediate(factory()->undefined_value())); | |
| 2052 } | |
| 2053 | |
| 2054 StringCharCodeAtGenerator generator(receiver, | |
| 2055 index, | |
| 2056 result, | |
| 2057 &miss, // When not a string. | |
| 2058 &miss, // When not a number. | |
| 2059 index_out_of_range_label, | |
| 2060 STRING_INDEX_IS_NUMBER); | |
| 2061 generator.GenerateFast(masm()); | |
| 2062 __ ret((argc + 1) * kPointerSize); | |
| 2063 | |
| 2064 StubRuntimeCallHelper call_helper; | |
| 2065 generator.GenerateSlow(masm(), call_helper); | |
| 2066 | |
| 2067 if (index_out_of_range.is_linked()) { | |
| 2068 __ bind(&index_out_of_range); | |
| 2069 __ Set(eax, Immediate(factory()->nan_value())); | |
| 2070 __ ret((argc + 1) * kPointerSize); | |
| 2071 } | |
| 2072 | |
| 2073 __ bind(&miss); | |
| 2074 // Restore function name in ecx. | |
| 2075 __ Set(ecx, Immediate(name)); | |
| 2076 HandlerFrontendFooter(&name_miss); | |
| 2077 | |
| 2078 // Return the generated code. | |
| 2079 return GetCode(type, name); | |
| 2080 } | |
| 2081 | |
| 2082 | |
| 2083 Handle<Code> CallStubCompiler::CompileStringCharAtCall( | |
| 2084 Handle<Object> object, | |
| 2085 Handle<JSObject> holder, | |
| 2086 Handle<Cell> cell, | |
| 2087 Handle<JSFunction> function, | |
| 2088 Handle<String> name, | |
| 2089 Code::StubType type) { | |
| 2090 // If object is not a string, bail out to regular call. | |
| 2091 if (!object->IsString() || !cell.is_null()) { | |
| 2092 return Handle<Code>::null(); | |
| 2093 } | |
| 2094 | |
| 2095 const int argc = arguments().immediate(); | |
| 2096 | |
| 2097 Label miss; | |
| 2098 Label name_miss; | |
| 2099 Label index_out_of_range; | |
| 2100 Label* index_out_of_range_label = &index_out_of_range; | |
| 2101 | |
| 2102 if (kind_ == Code::CALL_IC && | |
| 2103 (CallICBase::StringStubState::decode(extra_state()) == | |
| 2104 DEFAULT_STRING_STUB)) { | |
| 2105 index_out_of_range_label = &miss; | |
| 2106 } | |
| 2107 | |
| 2108 HandlerFrontendHeader(object, holder, name, STRING_CHECK, &name_miss); | |
| 2109 | |
| 2110 Register receiver = eax; | |
| 2111 Register index = edi; | |
| 2112 Register scratch = edx; | |
| 2113 Register result = eax; | |
| 2114 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize)); | |
| 2115 if (argc > 0) { | |
| 2116 __ mov(index, Operand(esp, (argc - 0) * kPointerSize)); | |
| 2117 } else { | |
| 2118 __ Set(index, Immediate(factory()->undefined_value())); | |
| 2119 } | |
| 2120 | |
| 2121 StringCharAtGenerator generator(receiver, | |
| 2122 index, | |
| 2123 scratch, | |
| 2124 result, | |
| 2125 &miss, // When not a string. | |
| 2126 &miss, // When not a number. | |
| 2127 index_out_of_range_label, | |
| 2128 STRING_INDEX_IS_NUMBER); | |
| 2129 generator.GenerateFast(masm()); | |
| 2130 __ ret((argc + 1) * kPointerSize); | |
| 2131 | |
| 2132 StubRuntimeCallHelper call_helper; | |
| 2133 generator.GenerateSlow(masm(), call_helper); | |
| 2134 | |
| 2135 if (index_out_of_range.is_linked()) { | |
| 2136 __ bind(&index_out_of_range); | |
| 2137 __ Set(eax, Immediate(factory()->empty_string())); | |
| 2138 __ ret((argc + 1) * kPointerSize); | |
| 2139 } | |
| 2140 | |
| 2141 __ bind(&miss); | |
| 2142 // Restore function name in ecx. | |
| 2143 __ Set(ecx, Immediate(name)); | |
| 2144 HandlerFrontendFooter(&name_miss); | |
| 2145 | |
| 2146 // Return the generated code. | |
| 2147 return GetCode(type, name); | |
| 2148 } | |
| 2149 | |
| 2150 | |
| 2151 Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall( | |
| 2152 Handle<Object> object, | |
| 2153 Handle<JSObject> holder, | |
| 2154 Handle<Cell> cell, | |
| 2155 Handle<JSFunction> function, | |
| 2156 Handle<String> name, | |
| 2157 Code::StubType type) { | |
| 2158 const int argc = arguments().immediate(); | |
| 2159 | |
| 2160 // If the object is not a JSObject or we got an unexpected number of | |
| 2161 // arguments, bail out to the regular call. | |
| 2162 if (!object->IsJSObject() || argc != 1) { | |
| 2163 return Handle<Code>::null(); | |
| 2164 } | |
| 2165 | |
| 2166 Label miss; | |
| 2167 | |
| 2168 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss); | |
| 2169 if (!cell.is_null()) { | |
| 2170 ASSERT(cell->value() == *function); | |
| 2171 GenerateLoadFunctionFromCell(cell, function, &miss); | |
| 2172 } | |
| 2173 | |
| 2174 // Load the char code argument. | |
| 2175 Register code = ebx; | |
| 2176 __ mov(code, Operand(esp, 1 * kPointerSize)); | |
| 2177 | |
| 2178 // Check the code is a smi. | |
| 2179 Label slow; | |
| 2180 STATIC_ASSERT(kSmiTag == 0); | |
| 2181 __ JumpIfNotSmi(code, &slow); | |
| 2182 | |
| 2183 // Convert the smi code to uint16. | |
| 2184 __ and_(code, Immediate(Smi::FromInt(0xffff))); | |
| 2185 | |
| 2186 StringCharFromCodeGenerator generator(code, eax); | |
| 2187 generator.GenerateFast(masm()); | |
| 2188 __ ret(2 * kPointerSize); | |
| 2189 | |
| 2190 StubRuntimeCallHelper call_helper; | |
| 2191 generator.GenerateSlow(masm(), call_helper); | |
| 2192 | |
| 2193 __ bind(&slow); | |
| 2194 // We do not have to patch the receiver because the function makes no use of | |
| 2195 // it. | |
| 2196 GenerateJumpFunctionIgnoreReceiver(function); | |
| 2197 | |
| 2198 HandlerFrontendFooter(&miss); | |
| 2199 | |
| 2200 // Return the generated code. | |
| 2201 return GetCode(type, name); | |
| 2202 } | |
| 2203 | |
| 2204 | |
| 2205 Handle<Code> CallStubCompiler::CompileMathFloorCall( | |
| 2206 Handle<Object> object, | |
| 2207 Handle<JSObject> holder, | |
| 2208 Handle<Cell> cell, | |
| 2209 Handle<JSFunction> function, | |
| 2210 Handle<String> name, | |
| 2211 Code::StubType type) { | |
| 2212 if (!CpuFeatures::IsSupported(SSE2)) { | |
| 2213 return Handle<Code>::null(); | |
| 2214 } | |
| 2215 | |
| 2216 CpuFeatureScope use_sse2(masm(), SSE2); | |
| 2217 | |
| 2218 const int argc = arguments().immediate(); | |
| 2219 | |
| 2220 // If the object is not a JSObject or we got an unexpected number of | |
| 2221 // arguments, bail out to the regular call. | |
| 2222 if (!object->IsJSObject() || argc != 1) { | |
| 2223 return Handle<Code>::null(); | |
| 2224 } | |
| 2225 | |
| 2226 Label miss; | |
| 2227 | |
| 2228 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss); | |
| 2229 if (!cell.is_null()) { | |
| 2230 ASSERT(cell->value() == *function); | |
| 2231 GenerateLoadFunctionFromCell(cell, function, &miss); | |
| 2232 } | |
| 2233 | |
| 2234 // Load the (only) argument into eax. | |
| 2235 __ mov(eax, Operand(esp, 1 * kPointerSize)); | |
| 2236 | |
| 2237 // Check if the argument is a smi. | |
| 2238 Label smi; | |
| 2239 STATIC_ASSERT(kSmiTag == 0); | |
| 2240 __ JumpIfSmi(eax, &smi); | |
| 2241 | |
| 2242 // Check if the argument is a heap number and load its value into xmm0. | |
| 2243 Label slow; | |
| 2244 __ CheckMap(eax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK); | |
| 2245 __ movsd(xmm0, FieldOperand(eax, HeapNumber::kValueOffset)); | |
| 2246 | |
| 2247 // Check if the argument is strictly positive. Note this also | |
| 2248 // discards NaN. | |
| 2249 __ xorpd(xmm1, xmm1); | |
| 2250 __ ucomisd(xmm0, xmm1); | |
| 2251 __ j(below_equal, &slow); | |
| 2252 | |
| 2253 // Do a truncating conversion. | |
| 2254 __ cvttsd2si(eax, Operand(xmm0)); | |
| 2255 | |
| 2256 // Check if the result fits into a smi. Note this also checks for | |
| 2257 // 0x80000000 which signals a failed conversion. | |
| 2258 Label wont_fit_into_smi; | |
| 2259 __ test(eax, Immediate(0xc0000000)); | |
| 2260 __ j(not_zero, &wont_fit_into_smi); | |
| 2261 | |
| 2262 // Smi tag and return. | |
| 2263 __ SmiTag(eax); | |
| 2264 __ bind(&smi); | |
| 2265 __ ret(2 * kPointerSize); | |
| 2266 | |
| 2267 // Check if the argument is < 2^kMantissaBits. | |
| 2268 Label already_round; | |
| 2269 __ bind(&wont_fit_into_smi); | |
| 2270 __ LoadPowerOf2(xmm1, ebx, HeapNumber::kMantissaBits); | |
| 2271 __ ucomisd(xmm0, xmm1); | |
| 2272 __ j(above_equal, &already_round); | |
| 2273 | |
| 2274 // Save a copy of the argument. | |
| 2275 __ movaps(xmm2, xmm0); | |
| 2276 | |
| 2277 // Compute (argument + 2^kMantissaBits) - 2^kMantissaBits. | |
| 2278 __ addsd(xmm0, xmm1); | |
| 2279 __ subsd(xmm0, xmm1); | |
| 2280 | |
| 2281 // Compare the argument and the tentative result to get the right mask: | |
| 2282 // if xmm2 < xmm0: | |
| 2283 // xmm2 = 1...1 | |
| 2284 // else: | |
| 2285 // xmm2 = 0...0 | |
| 2286 __ cmpltsd(xmm2, xmm0); | |
| 2287 | |
| 2288 // Subtract 1 if the argument was less than the tentative result. | |
| 2289 __ LoadPowerOf2(xmm1, ebx, 0); | |
| 2290 __ andpd(xmm1, xmm2); | |
| 2291 __ subsd(xmm0, xmm1); | |
| 2292 | |
| 2293 // Return a new heap number. | |
| 2294 __ AllocateHeapNumber(eax, ebx, edx, &slow); | |
| 2295 __ movsd(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); | |
| 2296 __ ret(2 * kPointerSize); | |
| 2297 | |
| 2298 // Return the argument (when it's an already round heap number). | |
| 2299 __ bind(&already_round); | |
| 2300 __ mov(eax, Operand(esp, 1 * kPointerSize)); | |
| 2301 __ ret(2 * kPointerSize); | |
| 2302 | |
| 2303 __ bind(&slow); | |
| 2304 // We do not have to patch the receiver because the function makes no use of | |
| 2305 // it. | |
| 2306 GenerateJumpFunctionIgnoreReceiver(function); | |
| 2307 | |
| 2308 HandlerFrontendFooter(&miss); | |
| 2309 | |
| 2310 // Return the generated code. | |
| 2311 return GetCode(type, name); | |
| 2312 } | |
| 2313 | |
| 2314 | |
| 2315 Handle<Code> CallStubCompiler::CompileMathAbsCall( | |
| 2316 Handle<Object> object, | |
| 2317 Handle<JSObject> holder, | |
| 2318 Handle<Cell> cell, | |
| 2319 Handle<JSFunction> function, | |
| 2320 Handle<String> name, | |
| 2321 Code::StubType type) { | |
| 2322 const int argc = arguments().immediate(); | |
| 2323 | |
| 2324 // If the object is not a JSObject or we got an unexpected number of | |
| 2325 // arguments, bail out to the regular call. | |
| 2326 if (!object->IsJSObject() || argc != 1) { | |
| 2327 return Handle<Code>::null(); | |
| 2328 } | |
| 2329 | |
| 2330 Label miss; | |
| 2331 | |
| 2332 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss); | |
| 2333 if (!cell.is_null()) { | |
| 2334 ASSERT(cell->value() == *function); | |
| 2335 GenerateLoadFunctionFromCell(cell, function, &miss); | |
| 2336 } | |
| 2337 | |
| 2338 // Load the (only) argument into eax. | |
| 2339 __ mov(eax, Operand(esp, 1 * kPointerSize)); | |
| 2340 | |
| 2341 // Check if the argument is a smi. | |
| 2342 Label not_smi; | |
| 2343 STATIC_ASSERT(kSmiTag == 0); | |
| 2344 __ JumpIfNotSmi(eax, ¬_smi); | |
| 2345 | |
| 2346 // Branchless abs implementation, refer to below: | |
| 2347 // http://graphics.stanford.edu/~seander/bithacks.html#IntegerAbs | |
| 2348 // Set ebx to 1...1 (== -1) if the argument is negative, or to 0...0 | |
| 2349 // otherwise. | |
| 2350 __ mov(ebx, eax); | |
| 2351 __ sar(ebx, kBitsPerInt - 1); | |
| 2352 | |
| 2353 // Do bitwise not or do nothing depending on ebx. | |
| 2354 __ xor_(eax, ebx); | |
| 2355 | |
| 2356 // Add 1 or do nothing depending on ebx. | |
| 2357 __ sub(eax, ebx); | |
| 2358 | |
| 2359 // If the result is still negative, go to the slow case. | |
| 2360 // This only happens for the most negative smi. | |
| 2361 Label slow; | |
| 2362 __ j(negative, &slow); | |
| 2363 | |
| 2364 // Smi case done. | |
| 2365 __ ret(2 * kPointerSize); | |
| 2366 | |
| 2367 // Check if the argument is a heap number and load its exponent and | |
| 2368 // sign into ebx. | |
| 2369 __ bind(¬_smi); | |
| 2370 __ CheckMap(eax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK); | |
| 2371 __ mov(ebx, FieldOperand(eax, HeapNumber::kExponentOffset)); | |
| 2372 | |
| 2373 // Check the sign of the argument. If the argument is positive, | |
| 2374 // just return it. | |
| 2375 Label negative_sign; | |
| 2376 __ test(ebx, Immediate(HeapNumber::kSignMask)); | |
| 2377 __ j(not_zero, &negative_sign); | |
| 2378 __ ret(2 * kPointerSize); | |
| 2379 | |
| 2380 // If the argument is negative, clear the sign, and return a new | |
| 2381 // number. | |
| 2382 __ bind(&negative_sign); | |
| 2383 __ and_(ebx, ~HeapNumber::kSignMask); | |
| 2384 __ mov(ecx, FieldOperand(eax, HeapNumber::kMantissaOffset)); | |
| 2385 __ AllocateHeapNumber(eax, edi, edx, &slow); | |
| 2386 __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), ebx); | |
| 2387 __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx); | |
| 2388 __ ret(2 * kPointerSize); | |
| 2389 | |
| 2390 __ bind(&slow); | |
| 2391 // We do not have to patch the receiver because the function makes no use of | |
| 2392 // it. | |
| 2393 GenerateJumpFunctionIgnoreReceiver(function); | |
| 2394 | |
| 2395 HandlerFrontendFooter(&miss); | |
| 2396 | |
| 2397 // Return the generated code. | |
| 2398 return GetCode(type, name); | |
| 2399 } | |
| 2400 | |
| 2401 | |
| 2402 Handle<Code> CallStubCompiler::CompileFastApiCall( | 1619 Handle<Code> CallStubCompiler::CompileFastApiCall( |
| 2403 const CallOptimization& optimization, | 1620 const CallOptimization& optimization, |
| 2404 Handle<Object> object, | 1621 Handle<Object> object, |
| 2405 Handle<JSObject> holder, | 1622 Handle<JSObject> holder, |
| 2406 Handle<Cell> cell, | 1623 Handle<Cell> cell, |
| 2407 Handle<JSFunction> function, | 1624 Handle<JSFunction> function, |
| 2408 Handle<String> name) { | 1625 Handle<String> name) { |
| 2409 ASSERT(optimization.is_simple_api_call()); | 1626 ASSERT(optimization.is_simple_api_call()); |
| 2410 // Bail out if object is a global object as we don't want to | 1627 // Bail out if object is a global object as we don't want to |
| 2411 // repatch it to global receiver. | 1628 // repatch it to global receiver. |
| 2412 if (object->IsGlobalObject()) return Handle<Code>::null(); | 1629 if (object->IsGlobalObject()) return Handle<Code>::null(); |
| 2413 if (!cell.is_null()) return Handle<Code>::null(); | 1630 if (!cell.is_null()) return Handle<Code>::null(); |
| 2414 if (!object->IsJSObject()) return Handle<Code>::null(); | 1631 if (!object->IsJSObject()) return Handle<Code>::null(); |
| 2415 int depth = optimization.GetPrototypeDepthOfExpectedType( | 1632 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 2416 Handle<JSObject>::cast(object), holder); | 1633 CallOptimization::HolderLookup holder_lookup = |
| 2417 if (depth == kInvalidProtoDepth) return Handle<Code>::null(); | 1634 CallOptimization::kHolderNotFound; |
| 1635 Handle<Map> lookup_map = optimization.LookupHolderOfExpectedType( |
| 1636 receiver, receiver, holder, &holder_lookup); |
| 1637 if (holder_lookup == CallOptimization::kHolderNotFound) { |
| 1638 return Handle<Code>::null(); |
| 1639 } |
| 2418 | 1640 |
| 2419 Label miss, miss_before_stack_reserved; | 1641 Label miss; |
| 2420 | 1642 GenerateNameCheck(name, &miss); |
| 2421 GenerateNameCheck(name, &miss_before_stack_reserved); | |
| 2422 | 1643 |
| 2423 // Get the receiver from the stack. | 1644 // Get the receiver from the stack. |
| 2424 const int argc = arguments().immediate(); | 1645 const int argc = arguments().immediate(); |
| 2425 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 1646 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 2426 | 1647 |
| 2427 // Check that the receiver isn't a smi. | 1648 // Check that the receiver isn't a smi. |
| 2428 __ JumpIfSmi(edx, &miss_before_stack_reserved); | 1649 __ JumpIfSmi(edx, &miss); |
| 2429 | 1650 |
| 2430 Counters* counters = isolate()->counters(); | 1651 Counters* counters = isolate()->counters(); |
| 2431 __ IncrementCounter(counters->call_const(), 1); | 1652 __ IncrementCounter(counters->call_const(), 1); |
| 2432 __ IncrementCounter(counters->call_const_fast_api(), 1); | |
| 2433 | |
| 2434 // Allocate space for v8::Arguments implicit values. Must be initialized | |
| 2435 // before calling any runtime function. | |
| 2436 __ sub(esp, Immediate(kFastApiCallArguments * kPointerSize)); | |
| 2437 | 1653 |
| 2438 // Check that the maps haven't changed and find a Holder as a side effect. | 1654 // Check that the maps haven't changed and find a Holder as a side effect. |
| 2439 CheckPrototypes(IC::CurrentTypeOf(object, isolate()), edx, holder, | 1655 CheckPrototypes(IC::CurrentTypeOf(object, isolate()), edx, holder, |
| 2440 ebx, eax, edi, name, depth, &miss); | 1656 ebx, eax, edi, name, &miss); |
| 2441 | 1657 |
| 2442 // Move the return address on top of the stack. | 1658 GenerateFastApiCall(masm(), optimization, argc, lookup_map, holder_lookup); |
| 2443 __ mov(eax, Operand(esp, kFastApiCallArguments * kPointerSize)); | |
| 2444 __ mov(Operand(esp, 0 * kPointerSize), eax); | |
| 2445 | 1659 |
| 2446 // esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains | 1660 HandlerFrontendFooter(&miss); |
| 2447 // duplicate of return address and will be overwritten. | |
| 2448 GenerateFastApiCall(masm(), optimization, argc); | |
| 2449 | |
| 2450 __ bind(&miss); | |
| 2451 __ add(esp, Immediate(kFastApiCallArguments * kPointerSize)); | |
| 2452 | |
| 2453 HandlerFrontendFooter(&miss_before_stack_reserved); | |
| 2454 | 1661 |
| 2455 // Return the generated code. | 1662 // Return the generated code. |
| 2456 return GetCode(function); | 1663 return GetCode(function); |
| 2457 } | 1664 } |
| 2458 | 1665 |
| 2459 | 1666 |
| 2460 void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) { | 1667 void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) { |
| 2461 Label success; | 1668 Label success; |
| 2462 // Check that the object is a boolean. | 1669 // Check that the object is a boolean. |
| 2463 __ cmp(object, factory()->true_value()); | 1670 __ cmp(object, factory()->true_value()); |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2631 // Return the generated code. | 1838 // Return the generated code. |
| 2632 return GetCode(Code::NORMAL, name); | 1839 return GetCode(Code::NORMAL, name); |
| 2633 } | 1840 } |
| 2634 | 1841 |
| 2635 | 1842 |
| 2636 Handle<Code> StoreStubCompiler::CompileStoreCallback( | 1843 Handle<Code> StoreStubCompiler::CompileStoreCallback( |
| 2637 Handle<JSObject> object, | 1844 Handle<JSObject> object, |
| 2638 Handle<JSObject> holder, | 1845 Handle<JSObject> holder, |
| 2639 Handle<Name> name, | 1846 Handle<Name> name, |
| 2640 Handle<ExecutableAccessorInfo> callback) { | 1847 Handle<ExecutableAccessorInfo> callback) { |
| 2641 HandlerFrontend(IC::CurrentTypeOf(object, isolate()), | 1848 Register holder_reg = HandlerFrontend( |
| 2642 receiver(), holder, name); | 1849 IC::CurrentTypeOf(object, isolate()), receiver(), holder, name); |
| 2643 | 1850 |
| 2644 __ pop(scratch1()); // remove the return address | 1851 __ pop(scratch1()); // remove the return address |
| 2645 __ push(receiver()); | 1852 __ push(receiver()); |
| 1853 __ push(holder_reg); |
| 2646 __ Push(callback); | 1854 __ Push(callback); |
| 2647 __ Push(name); | 1855 __ Push(name); |
| 2648 __ push(value()); | 1856 __ push(value()); |
| 2649 __ push(scratch1()); // restore return address | 1857 __ push(scratch1()); // restore return address |
| 2650 | 1858 |
| 2651 // Do tail-call to the runtime system. | 1859 // Do tail-call to the runtime system. |
| 2652 ExternalReference store_callback_property = | 1860 ExternalReference store_callback_property = |
| 2653 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate()); | 1861 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate()); |
| 2654 __ TailCallExternalReference(store_callback_property, 4, 1); | 1862 __ TailCallExternalReference(store_callback_property, 5, 1); |
| 2655 | 1863 |
| 2656 // Return the generated code. | 1864 // Return the generated code. |
| 2657 return GetCode(kind(), Code::FAST, name); | 1865 return GetCode(kind(), Code::FAST, name); |
| 2658 } | 1866 } |
| 2659 | 1867 |
| 2660 | 1868 |
| 2661 Handle<Code> StoreStubCompiler::CompileStoreCallback( | 1869 Handle<Code> StoreStubCompiler::CompileStoreCallback( |
| 2662 Handle<JSObject> object, | 1870 Handle<JSObject> object, |
| 2663 Handle<JSObject> holder, | 1871 Handle<JSObject> holder, |
| 2664 Handle<Name> name, | 1872 Handle<Name> name, |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2763 } | 1971 } |
| 2764 __ bind(&miss); | 1972 __ bind(&miss); |
| 2765 TailCallBuiltin(masm(), MissBuiltin(kind())); | 1973 TailCallBuiltin(masm(), MissBuiltin(kind())); |
| 2766 | 1974 |
| 2767 // Return the generated code. | 1975 // Return the generated code. |
| 2768 return GetICCode( | 1976 return GetICCode( |
| 2769 kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC); | 1977 kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC); |
| 2770 } | 1978 } |
| 2771 | 1979 |
| 2772 | 1980 |
| 2773 Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<Type> type, | 1981 Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<HeapType> type, |
| 2774 Handle<JSObject> last, | 1982 Handle<JSObject> last, |
| 2775 Handle<Name> name) { | 1983 Handle<Name> name) { |
| 2776 NonexistentHandlerFrontend(type, last, name); | 1984 NonexistentHandlerFrontend(type, last, name); |
| 2777 | 1985 |
| 2778 // Return undefined if maps of the full prototype chain are still the | 1986 // Return undefined if maps of the full prototype chain are still the |
| 2779 // same and no global property with this name contains a value. | 1987 // same and no global property with this name contains a value. |
| 2780 __ mov(eax, isolate()->factory()->undefined_value()); | 1988 __ mov(eax, isolate()->factory()->undefined_value()); |
| 2781 __ ret(0); | 1989 __ ret(0); |
| 2782 | 1990 |
| 2783 // Return the generated code. | 1991 // Return the generated code. |
| (...skipping 22 matching lines...) Expand all Loading... |
| 2806 } | 2014 } |
| 2807 | 2015 |
| 2808 | 2016 |
| 2809 Register* KeyedStoreStubCompiler::registers() { | 2017 Register* KeyedStoreStubCompiler::registers() { |
| 2810 // receiver, name, value, scratch1, scratch2, scratch3. | 2018 // receiver, name, value, scratch1, scratch2, scratch3. |
| 2811 static Register registers[] = { edx, ecx, eax, ebx, edi, no_reg }; | 2019 static Register registers[] = { edx, ecx, eax, ebx, edi, no_reg }; |
| 2812 return registers; | 2020 return registers; |
| 2813 } | 2021 } |
| 2814 | 2022 |
| 2815 | 2023 |
| 2816 void KeyedLoadStubCompiler::GenerateNameCheck(Handle<Name> name, | |
| 2817 Register name_reg, | |
| 2818 Label* miss) { | |
| 2819 __ cmp(name_reg, Immediate(name)); | |
| 2820 __ j(not_equal, miss); | |
| 2821 } | |
| 2822 | |
| 2823 | |
| 2824 void KeyedStoreStubCompiler::GenerateNameCheck(Handle<Name> name, | |
| 2825 Register name_reg, | |
| 2826 Label* miss) { | |
| 2827 __ cmp(name_reg, Immediate(name)); | |
| 2828 __ j(not_equal, miss); | |
| 2829 } | |
| 2830 | |
| 2831 | |
| 2832 #undef __ | 2024 #undef __ |
| 2833 #define __ ACCESS_MASM(masm) | 2025 #define __ ACCESS_MASM(masm) |
| 2834 | 2026 |
| 2835 | 2027 |
| 2836 void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm, | 2028 void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm, |
| 2837 Register receiver, | 2029 Register receiver, |
| 2838 Handle<JSFunction> getter) { | 2030 Handle<JSFunction> getter) { |
| 2839 { | 2031 { |
| 2840 FrameScope scope(masm, StackFrame::INTERNAL); | 2032 FrameScope scope(masm, StackFrame::INTERNAL); |
| 2841 | 2033 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 2857 } | 2049 } |
| 2858 __ ret(0); | 2050 __ ret(0); |
| 2859 } | 2051 } |
| 2860 | 2052 |
| 2861 | 2053 |
| 2862 #undef __ | 2054 #undef __ |
| 2863 #define __ ACCESS_MASM(masm()) | 2055 #define __ ACCESS_MASM(masm()) |
| 2864 | 2056 |
| 2865 | 2057 |
| 2866 Handle<Code> LoadStubCompiler::CompileLoadGlobal( | 2058 Handle<Code> LoadStubCompiler::CompileLoadGlobal( |
| 2867 Handle<Type> type, | 2059 Handle<HeapType> type, |
| 2868 Handle<GlobalObject> global, | 2060 Handle<GlobalObject> global, |
| 2869 Handle<PropertyCell> cell, | 2061 Handle<PropertyCell> cell, |
| 2870 Handle<Name> name, | 2062 Handle<Name> name, |
| 2871 bool is_dont_delete) { | 2063 bool is_dont_delete) { |
| 2872 Label miss; | 2064 Label miss; |
| 2873 | 2065 |
| 2874 HandlerFrontendHeader(type, receiver(), global, name, &miss); | 2066 HandlerFrontendHeader(type, receiver(), global, name, &miss); |
| 2875 // Get the value from the cell. | 2067 // Get the value from the cell. |
| 2876 if (Serializer::enabled()) { | 2068 if (Serializer::enabled()) { |
| 2877 __ mov(eax, Immediate(cell)); | 2069 __ mov(eax, Immediate(cell)); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 2902 | 2094 |
| 2903 | 2095 |
| 2904 Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC( | 2096 Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC( |
| 2905 TypeHandleList* types, | 2097 TypeHandleList* types, |
| 2906 CodeHandleList* handlers, | 2098 CodeHandleList* handlers, |
| 2907 Handle<Name> name, | 2099 Handle<Name> name, |
| 2908 Code::StubType type, | 2100 Code::StubType type, |
| 2909 IcCheckType check) { | 2101 IcCheckType check) { |
| 2910 Label miss; | 2102 Label miss; |
| 2911 | 2103 |
| 2912 if (check == PROPERTY) { | 2104 if (check == PROPERTY && |
| 2913 GenerateNameCheck(name, this->name(), &miss); | 2105 (kind() == Code::KEYED_LOAD_IC || kind() == Code::KEYED_STORE_IC)) { |
| 2106 __ cmp(this->name(), Immediate(name)); |
| 2107 __ j(not_equal, &miss); |
| 2914 } | 2108 } |
| 2915 | 2109 |
| 2916 Label number_case; | 2110 Label number_case; |
| 2917 Label* smi_target = IncludesNumberType(types) ? &number_case : &miss; | 2111 Label* smi_target = IncludesNumberType(types) ? &number_case : &miss; |
| 2918 __ JumpIfSmi(receiver(), smi_target); | 2112 __ JumpIfSmi(receiver(), smi_target); |
| 2919 | 2113 |
| 2920 Register map_reg = scratch1(); | 2114 Register map_reg = scratch1(); |
| 2921 __ mov(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset)); | 2115 __ mov(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset)); |
| 2922 int receiver_count = types->length(); | 2116 int receiver_count = types->length(); |
| 2923 int number_of_handled_maps = 0; | 2117 int number_of_handled_maps = 0; |
| 2924 for (int current = 0; current < receiver_count; ++current) { | 2118 for (int current = 0; current < receiver_count; ++current) { |
| 2925 Handle<Type> type = types->at(current); | 2119 Handle<HeapType> type = types->at(current); |
| 2926 Handle<Map> map = IC::TypeToMap(*type, isolate()); | 2120 Handle<Map> map = IC::TypeToMap(*type, isolate()); |
| 2927 if (!map->is_deprecated()) { | 2121 if (!map->is_deprecated()) { |
| 2928 number_of_handled_maps++; | 2122 number_of_handled_maps++; |
| 2929 __ cmp(map_reg, map); | 2123 __ cmp(map_reg, map); |
| 2930 if (type->Is(Type::Number())) { | 2124 if (type->Is(HeapType::Number())) { |
| 2931 ASSERT(!number_case.is_unused()); | 2125 ASSERT(!number_case.is_unused()); |
| 2932 __ bind(&number_case); | 2126 __ bind(&number_case); |
| 2933 } | 2127 } |
| 2934 __ j(equal, handlers->at(current)); | 2128 __ j(equal, handlers->at(current)); |
| 2935 } | 2129 } |
| 2936 } | 2130 } |
| 2937 ASSERT(number_of_handled_maps != 0); | 2131 ASSERT(number_of_handled_maps != 0); |
| 2938 | 2132 |
| 2939 __ bind(&miss); | 2133 __ bind(&miss); |
| 2940 TailCallBuiltin(masm(), MissBuiltin(kind())); | 2134 TailCallBuiltin(masm(), MissBuiltin(kind())); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2992 // ----------------------------------- | 2186 // ----------------------------------- |
| 2993 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); | 2187 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); |
| 2994 } | 2188 } |
| 2995 | 2189 |
| 2996 | 2190 |
| 2997 #undef __ | 2191 #undef __ |
| 2998 | 2192 |
| 2999 } } // namespace v8::internal | 2193 } } // namespace v8::internal |
| 3000 | 2194 |
| 3001 #endif // V8_TARGET_ARCH_IA32 | 2195 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |