| 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 400 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1183 #define __ ACCESS_MASM(masm()) | 1143 #define __ ACCESS_MASM(masm()) |
| 1184 | 1144 |
| 1185 | 1145 |
| 1186 Register StubCompiler::CheckPrototypes(Handle<HeapType> 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 376 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1672 Handle<JSObject> holder, | 1622 Handle<JSObject> holder, |
| 1673 Handle<Cell> cell, | 1623 Handle<Cell> cell, |
| 1674 Handle<JSFunction> function, | 1624 Handle<JSFunction> function, |
| 1675 Handle<String> name) { | 1625 Handle<String> name) { |
| 1676 ASSERT(optimization.is_simple_api_call()); | 1626 ASSERT(optimization.is_simple_api_call()); |
| 1677 // 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 |
| 1678 // repatch it to global receiver. | 1628 // repatch it to global receiver. |
| 1679 if (object->IsGlobalObject()) return Handle<Code>::null(); | 1629 if (object->IsGlobalObject()) return Handle<Code>::null(); |
| 1680 if (!cell.is_null()) return Handle<Code>::null(); | 1630 if (!cell.is_null()) return Handle<Code>::null(); |
| 1681 if (!object->IsJSObject()) return Handle<Code>::null(); | 1631 if (!object->IsJSObject()) return Handle<Code>::null(); |
| 1682 int depth = optimization.GetPrototypeDepthOfExpectedType( | 1632 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1683 Handle<JSObject>::cast(object), holder); | 1633 CallOptimization::HolderLookup holder_lookup = |
| 1684 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 } |
| 1685 | 1640 |
| 1686 Label miss, miss_before_stack_reserved; | 1641 Label miss; |
| 1687 | 1642 GenerateNameCheck(name, &miss); |
| 1688 GenerateNameCheck(name, &miss_before_stack_reserved); | |
| 1689 | 1643 |
| 1690 // Get the receiver from the stack. | 1644 // Get the receiver from the stack. |
| 1691 const int argc = arguments().immediate(); | 1645 const int argc = arguments().immediate(); |
| 1692 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 1646 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 1693 | 1647 |
| 1694 // Check that the receiver isn't a smi. | 1648 // Check that the receiver isn't a smi. |
| 1695 __ JumpIfSmi(edx, &miss_before_stack_reserved); | 1649 __ JumpIfSmi(edx, &miss); |
| 1696 | 1650 |
| 1697 Counters* counters = isolate()->counters(); | 1651 Counters* counters = isolate()->counters(); |
| 1698 __ IncrementCounter(counters->call_const(), 1); | 1652 __ IncrementCounter(counters->call_const(), 1); |
| 1699 __ IncrementCounter(counters->call_const_fast_api(), 1); | |
| 1700 | |
| 1701 // Allocate space for v8::Arguments implicit values. Must be initialized | |
| 1702 // before calling any runtime function. | |
| 1703 __ sub(esp, Immediate(kFastApiCallArguments * kPointerSize)); | |
| 1704 | 1653 |
| 1705 // 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. |
| 1706 CheckPrototypes(IC::CurrentTypeOf(object, isolate()), edx, holder, | 1655 CheckPrototypes(IC::CurrentTypeOf(object, isolate()), edx, holder, |
| 1707 ebx, eax, edi, name, depth, &miss); | 1656 ebx, eax, edi, name, &miss); |
| 1708 | 1657 |
| 1709 // Move the return address on top of the stack. | 1658 GenerateFastApiCall(masm(), optimization, argc, lookup_map, holder_lookup); |
| 1710 __ mov(eax, Operand(esp, kFastApiCallArguments * kPointerSize)); | |
| 1711 __ mov(Operand(esp, 0 * kPointerSize), eax); | |
| 1712 | 1659 |
| 1713 // esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains | 1660 HandlerFrontendFooter(&miss); |
| 1714 // duplicate of return address and will be overwritten. | |
| 1715 GenerateFastApiCall(masm(), optimization, argc); | |
| 1716 | |
| 1717 __ bind(&miss); | |
| 1718 __ add(esp, Immediate(kFastApiCallArguments * kPointerSize)); | |
| 1719 | |
| 1720 HandlerFrontendFooter(&miss_before_stack_reserved); | |
| 1721 | 1661 |
| 1722 // Return the generated code. | 1662 // Return the generated code. |
| 1723 return GetCode(function); | 1663 return GetCode(function); |
| 1724 } | 1664 } |
| 1725 | 1665 |
| 1726 | 1666 |
| 1727 void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) { | 1667 void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) { |
| 1728 Label success; | 1668 Label success; |
| 1729 // Check that the object is a boolean. | 1669 // Check that the object is a boolean. |
| 1730 __ cmp(object, factory()->true_value()); | 1670 __ cmp(object, factory()->true_value()); |
| (...skipping 515 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2246 // ----------------------------------- | 2186 // ----------------------------------- |
| 2247 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); | 2187 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); |
| 2248 } | 2188 } |
| 2249 | 2189 |
| 2250 | 2190 |
| 2251 #undef __ | 2191 #undef __ |
| 2252 | 2192 |
| 2253 } } // namespace v8::internal | 2193 } } // namespace v8::internal |
| 2254 | 2194 |
| 2255 #endif // V8_TARGET_ARCH_IA32 | 2195 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |