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 |
421 static void GenerateFastApiCallBody(MacroAssembler* masm, | 454 static void GenerateFastApiCallBody(MacroAssembler* masm, |
422 const CallOptimization& optimization, | 455 const CallOptimization& optimization, |
423 int argc, | 456 int argc, |
424 Register holder, | |
425 Register scratch1, | |
426 Register scratch2, | |
427 Register scratch3, | |
428 bool restore_context); | 457 bool restore_context); |
429 | 458 |
| 459 |
430 // Generates call to API function. | 460 // Generates call to API function. |
431 static void GenerateFastApiCall(MacroAssembler* masm, | 461 static void GenerateFastApiCall(MacroAssembler* masm, |
432 const CallOptimization& optimization, | 462 const CallOptimization& optimization, |
433 int argc, | 463 int argc) { |
434 Handle<Map> map_to_holder, | 464 typedef FunctionCallbackArguments FCA; |
435 CallOptimization::HolderLookup holder_lookup) { | 465 // Save calling context. |
436 Counters* counters = masm->isolate()->counters(); | 466 __ mov(Operand(esp, (1 + FCA::kContextSaveIndex) * kPointerSize), esi); |
437 __ IncrementCounter(counters->call_const_fast_api(), 1); | |
438 | 467 |
439 // Move holder to a register | 468 // Get the function and setup the context. |
440 Register holder_reg = eax; | 469 Handle<JSFunction> function = optimization.constant_function(); |
441 switch (holder_lookup) { | 470 __ LoadHeapObject(edi, function); |
442 case CallOptimization::kHolderIsReceiver: | 471 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); |
443 { | 472 |
444 ASSERT(map_to_holder.is_null()); | 473 // Construct the FunctionCallbackInfo. |
445 __ mov(holder_reg, Operand(esp, (argc + 1)* kPointerSize)); | 474 __ mov(Operand(esp, (1 + FCA::kCalleeIndex) * kPointerSize), edi); |
446 } | 475 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); |
447 break; | 476 Handle<Object> call_data(api_call_info->data(), masm->isolate()); |
448 case CallOptimization::kHolderIsPrototypeOfMap: | 477 if (masm->isolate()->heap()->InNewSpace(*call_data)) { |
449 { | 478 __ mov(ecx, api_call_info); |
450 Handle<JSObject> holder(JSObject::cast(map_to_holder->prototype())); | 479 __ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kDataOffset)); |
451 if (!masm->isolate()->heap()->InNewSpace(*holder)) { | 480 __ mov(Operand(esp, (1 + FCA::kDataIndex) * kPointerSize), ebx); |
452 __ mov(holder_reg, holder); | 481 } else { |
453 } else { | 482 __ mov(Operand(esp, (1 + FCA::kDataIndex) * kPointerSize), |
454 __ mov(holder_reg, map_to_holder); | 483 Immediate(call_data)); |
455 __ mov(holder_reg, FieldOperand(holder_reg, Map::kPrototypeOffset)); | |
456 } | |
457 } | |
458 break; | |
459 case CallOptimization::kHolderNotFound: | |
460 UNREACHABLE(); | |
461 } | 484 } |
462 GenerateFastApiCallBody(masm, | 485 __ mov(Operand(esp, (1 + FCA::kIsolateIndex) * kPointerSize), |
463 optimization, | 486 Immediate(reinterpret_cast<int>(masm->isolate()))); |
464 argc, | 487 __ mov(Operand(esp, (1 + FCA::kReturnValueOffset) * kPointerSize), |
465 holder_reg, | 488 masm->isolate()->factory()->undefined_value()); |
466 ebx, | 489 __ mov(Operand(esp, (1 + FCA::kReturnValueDefaultValueIndex) * kPointerSize), |
467 ecx, | 490 masm->isolate()->factory()->undefined_value()); |
468 edx, | 491 |
469 false); | 492 // Prepare arguments. |
| 493 STATIC_ASSERT(kFastApiCallArguments == 7); |
| 494 __ lea(eax, Operand(esp, 1 * kPointerSize)); |
| 495 |
| 496 GenerateFastApiCallBody(masm, optimization, argc, false); |
470 } | 497 } |
471 | 498 |
472 | 499 |
473 // Generate call to api function. | 500 // Generate call to api function. |
474 // This function uses push() to generate smaller, faster code than | 501 // This function uses push() to generate smaller, faster code than |
475 // the version above. It is an optimization that should will be removed | 502 // the version above. It is an optimization that should will be removed |
476 // when api call ICs are generated in hydrogen. | 503 // when api call ICs are generated in hydrogen. |
477 static void GenerateFastApiCall(MacroAssembler* masm, | 504 static void GenerateFastApiCall(MacroAssembler* masm, |
478 const CallOptimization& optimization, | 505 const CallOptimization& optimization, |
479 Register receiver, | 506 Register receiver, |
480 Register scratch1, | 507 Register scratch1, |
481 Register scratch2, | 508 Register scratch2, |
482 Register scratch3, | 509 Register scratch3, |
483 int argc, | 510 int argc, |
484 Register* values) { | 511 Register* values) { |
| 512 ASSERT(optimization.is_simple_api_call()); |
| 513 |
485 // Copy return value. | 514 // Copy return value. |
486 __ pop(scratch1); | 515 __ pop(scratch1); |
| 516 |
487 // receiver | 517 // receiver |
488 __ push(receiver); | 518 __ push(receiver); |
| 519 |
489 // Write the arguments to stack frame. | 520 // Write the arguments to stack frame. |
490 for (int i = 0; i < argc; i++) { | 521 for (int i = 0; i < argc; i++) { |
491 Register arg = values[argc-1-i]; | 522 Register arg = values[argc-1-i]; |
492 ASSERT(!receiver.is(arg)); | 523 ASSERT(!receiver.is(arg)); |
493 ASSERT(!scratch1.is(arg)); | 524 ASSERT(!scratch1.is(arg)); |
494 ASSERT(!scratch2.is(arg)); | 525 ASSERT(!scratch2.is(arg)); |
495 ASSERT(!scratch3.is(arg)); | 526 ASSERT(!scratch3.is(arg)); |
496 __ push(arg); | 527 __ push(arg); |
497 } | 528 } |
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()); | |
526 | 529 |
527 typedef FunctionCallbackArguments FCA; | 530 typedef FunctionCallbackArguments FCA; |
528 | 531 |
529 STATIC_ASSERT(FCA::kHolderIndex == 0); | 532 STATIC_ASSERT(FCA::kHolderIndex == 0); |
530 STATIC_ASSERT(FCA::kIsolateIndex == 1); | 533 STATIC_ASSERT(FCA::kIsolateIndex == 1); |
531 STATIC_ASSERT(FCA::kReturnValueDefaultValueIndex == 2); | 534 STATIC_ASSERT(FCA::kReturnValueDefaultValueIndex == 2); |
532 STATIC_ASSERT(FCA::kReturnValueOffset == 3); | 535 STATIC_ASSERT(FCA::kReturnValueOffset == 3); |
533 STATIC_ASSERT(FCA::kDataIndex == 4); | 536 STATIC_ASSERT(FCA::kDataIndex == 4); |
534 STATIC_ASSERT(FCA::kCalleeIndex == 5); | 537 STATIC_ASSERT(FCA::kCalleeIndex == 5); |
535 STATIC_ASSERT(FCA::kContextSaveIndex == 6); | 538 STATIC_ASSERT(FCA::kContextSaveIndex == 6); |
536 STATIC_ASSERT(FCA::kArgsLength == 7); | 539 STATIC_ASSERT(FCA::kArgsLength == 7); |
537 | 540 |
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(holder); | 569 __ push(receiver); |
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 |
578 // API function gets reference to the v8::Arguments. If CPU profiler | 600 // API function gets reference to the v8::Arguments. If CPU profiler |
579 // is enabled wrapper function will be called and we need to pass | 601 // is enabled wrapper function will be called and we need to pass |
580 // address of the callback as additional parameter, always allocate | 602 // address of the callback as additional parameter, always allocate |
581 // space for it. | 603 // space for it. |
582 const int kApiArgc = 1 + 1; | 604 const int kApiArgc = 1 + 1; |
583 | 605 |
584 // Allocate the v8::Arguments structure in the arguments' space since | 606 // Allocate the v8::Arguments structure in the arguments' space since |
585 // it's not controlled by GC. | 607 // it's not controlled by GC. |
586 const int kApiStackSpace = 4; | 608 const int kApiStackSpace = 4; |
587 | 609 |
| 610 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); |
| 611 |
588 // Function address is a foreign pointer outside V8's heap. | 612 // Function address is a foreign pointer outside V8's heap. |
589 Address function_address = v8::ToCData<Address>(api_call_info->callback()); | 613 Address function_address = v8::ToCData<Address>(api_call_info->callback()); |
590 __ PrepareCallApiFunction(kApiArgc + kApiStackSpace); | 614 __ PrepareCallApiFunction(kApiArgc + kApiStackSpace); |
591 | 615 |
592 // FunctionCallbackInfo::implicit_args_. | 616 // FunctionCallbackInfo::implicit_args_. |
593 __ mov(ApiParameterOperand(2), eax); | 617 __ mov(ApiParameterOperand(2), eax); |
594 __ add(eax, Immediate((argc + kFastApiCallArguments - 1) * kPointerSize)); | 618 __ add(eax, Immediate((argc + kFastApiCallArguments - 1) * kPointerSize)); |
595 // FunctionCallbackInfo::values_. | 619 // FunctionCallbackInfo::values_. |
596 __ mov(ApiParameterOperand(3), eax); | 620 __ mov(ApiParameterOperand(3), eax); |
597 // FunctionCallbackInfo::length_. | 621 // FunctionCallbackInfo::length_. |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
662 Register scratch2, | 686 Register scratch2, |
663 Register scratch3, | 687 Register scratch3, |
664 Handle<JSObject> interceptor_holder, | 688 Handle<JSObject> interceptor_holder, |
665 LookupResult* lookup, | 689 LookupResult* lookup, |
666 Handle<Name> name, | 690 Handle<Name> name, |
667 const CallOptimization& optimization, | 691 const CallOptimization& optimization, |
668 Label* miss_label) { | 692 Label* miss_label) { |
669 ASSERT(optimization.is_constant_call()); | 693 ASSERT(optimization.is_constant_call()); |
670 ASSERT(!lookup->holder()->IsGlobalObject()); | 694 ASSERT(!lookup->holder()->IsGlobalObject()); |
671 | 695 |
| 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 |
672 Counters* counters = masm->isolate()->counters(); | 711 Counters* counters = masm->isolate()->counters(); |
673 __ IncrementCounter(counters->call_const_interceptor(), 1); | 712 __ IncrementCounter(counters->call_const_interceptor(), 1); |
674 | 713 |
| 714 if (can_do_fast_api_call) { |
| 715 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1); |
| 716 ReserveSpaceForFastApiCall(masm, scratch1); |
| 717 } |
| 718 |
675 // Check that the maps from receiver to interceptor's holder | 719 // Check that the maps from receiver to interceptor's holder |
676 // haven't changed and thus we can invoke interceptor. | 720 // 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; |
677 Register holder = | 723 Register holder = |
678 stub_compiler_->CheckPrototypes( | 724 stub_compiler_->CheckPrototypes( |
679 IC::CurrentTypeOf(object, masm->isolate()), receiver, | 725 IC::CurrentTypeOf(object, masm->isolate()), receiver, |
680 interceptor_holder, scratch1, scratch2, scratch3, | 726 interceptor_holder, scratch1, scratch2, scratch3, |
681 name, miss_label); | 727 name, depth1, miss); |
682 | 728 |
683 // Invoke an interceptor and if it provides a value, | 729 // Invoke an interceptor and if it provides a value, |
684 // branch to |regular_invoke|. | 730 // branch to |regular_invoke|. |
685 Label regular_invoke; | 731 Label regular_invoke; |
686 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, | 732 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, |
687 ®ular_invoke); | 733 ®ular_invoke); |
688 | 734 |
689 // Interceptor returned nothing for this property. Try to use cached | 735 // Interceptor returned nothing for this property. Try to use cached |
690 // constant function. | 736 // constant function. |
691 | 737 |
692 // Check that the maps from interceptor's holder to constant function's | 738 // Check that the maps from interceptor's holder to constant function's |
693 // holder haven't changed and thus we can use cached constant function. | 739 // holder haven't changed and thus we can use cached constant function. |
694 if (*interceptor_holder != lookup->holder()) { | 740 if (*interceptor_holder != lookup->holder()) { |
695 stub_compiler_->CheckPrototypes( | 741 stub_compiler_->CheckPrototypes( |
696 IC::CurrentTypeOf(interceptor_holder, masm->isolate()), holder, | 742 IC::CurrentTypeOf(interceptor_holder, masm->isolate()), holder, |
697 handle(lookup->holder()), scratch1, scratch2, scratch3, | 743 handle(lookup->holder()), scratch1, scratch2, scratch3, |
698 name, miss_label); | 744 name, depth2, miss); |
699 } | 745 } else { |
700 | 746 // CheckPrototypes has a side effect of fetching a 'holder' |
701 Handle<Map> lookup_map; | 747 // for API (object which is instanceof for the signature). It's |
702 CallOptimization::HolderLookup holder_lookup = | 748 // safe to omit it here, as if present, it should be fetched |
703 CallOptimization::kHolderNotFound; | 749 // by the previous CheckPrototypes. |
704 if (optimization.is_simple_api_call() && | 750 ASSERT(depth2 == kInvalidProtoDepth); |
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 } | |
716 } | 751 } |
717 | 752 |
718 // Invoke function. | 753 // Invoke function. |
719 if (holder_lookup != CallOptimization::kHolderNotFound) { | 754 if (can_do_fast_api_call) { |
720 int argc = arguments_.immediate(); | 755 GenerateFastApiCall(masm, optimization, arguments_.immediate()); |
721 GenerateFastApiCall(masm, | |
722 optimization, | |
723 argc, | |
724 lookup_map, | |
725 holder_lookup); | |
726 } else { | 756 } else { |
727 Handle<JSFunction> fun = optimization.constant_function(); | 757 Handle<JSFunction> fun = optimization.constant_function(); |
728 stub_compiler_->GenerateJumpFunction(object, fun); | 758 stub_compiler_->GenerateJumpFunction(object, fun); |
729 } | 759 } |
730 | 760 |
| 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 |
731 // Invoke a regular function. | 768 // Invoke a regular function. |
732 __ bind(®ular_invoke); | 769 __ bind(®ular_invoke); |
| 770 if (can_do_fast_api_call) { |
| 771 FreeSpaceForFastApiCall(masm, scratch1); |
| 772 } |
733 } | 773 } |
734 | 774 |
735 void CompileRegular(MacroAssembler* masm, | 775 void CompileRegular(MacroAssembler* masm, |
736 Handle<JSObject> object, | 776 Handle<JSObject> object, |
737 Register receiver, | 777 Register receiver, |
738 Register scratch1, | 778 Register scratch1, |
739 Register scratch2, | 779 Register scratch2, |
740 Register scratch3, | 780 Register scratch3, |
741 Handle<Name> name, | 781 Handle<Name> name, |
742 Handle<JSObject> interceptor_holder, | 782 Handle<JSObject> interceptor_holder, |
(...skipping 400 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1143 #define __ ACCESS_MASM(masm()) | 1183 #define __ ACCESS_MASM(masm()) |
1144 | 1184 |
1145 | 1185 |
1146 Register StubCompiler::CheckPrototypes(Handle<HeapType> type, | 1186 Register StubCompiler::CheckPrototypes(Handle<HeapType> type, |
1147 Register object_reg, | 1187 Register object_reg, |
1148 Handle<JSObject> holder, | 1188 Handle<JSObject> holder, |
1149 Register holder_reg, | 1189 Register holder_reg, |
1150 Register scratch1, | 1190 Register scratch1, |
1151 Register scratch2, | 1191 Register scratch2, |
1152 Handle<Name> name, | 1192 Handle<Name> name, |
| 1193 int save_at_depth, |
1153 Label* miss, | 1194 Label* miss, |
1154 PrototypeCheckType check) { | 1195 PrototypeCheckType check) { |
1155 Handle<Map> receiver_map(IC::TypeToMap(*type, isolate())); | 1196 Handle<Map> receiver_map(IC::TypeToMap(*type, isolate())); |
1156 // Make sure that the type feedback oracle harvests the receiver map. | 1197 // Make sure that the type feedback oracle harvests the receiver map. |
1157 // TODO(svenpanne) Remove this hack when all ICs are reworked. | 1198 // TODO(svenpanne) Remove this hack when all ICs are reworked. |
1158 __ mov(scratch1, receiver_map); | 1199 __ mov(scratch1, receiver_map); |
1159 | 1200 |
1160 // Make sure there's no overlap between holder and object registers. | 1201 // Make sure there's no overlap between holder and object registers. |
1161 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); | 1202 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); |
1162 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg) | 1203 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg) |
1163 && !scratch2.is(scratch1)); | 1204 && !scratch2.is(scratch1)); |
1164 | 1205 |
1165 // Keep track of the current object in register reg. | 1206 // Keep track of the current object in register reg. |
1166 Register reg = object_reg; | 1207 Register reg = object_reg; |
1167 int depth = 0; | 1208 int depth = 0; |
1168 | 1209 |
| 1210 const int kHolderIndex = FunctionCallbackArguments::kHolderIndex + 1; |
| 1211 if (save_at_depth == depth) { |
| 1212 __ mov(Operand(esp, kHolderIndex * kPointerSize), reg); |
| 1213 } |
| 1214 |
1169 Handle<JSObject> current = Handle<JSObject>::null(); | 1215 Handle<JSObject> current = Handle<JSObject>::null(); |
1170 if (type->IsConstant()) current = Handle<JSObject>::cast(type->AsConstant()); | 1216 if (type->IsConstant()) current = Handle<JSObject>::cast(type->AsConstant()); |
1171 Handle<JSObject> prototype = Handle<JSObject>::null(); | 1217 Handle<JSObject> prototype = Handle<JSObject>::null(); |
1172 Handle<Map> current_map = receiver_map; | 1218 Handle<Map> current_map = receiver_map; |
1173 Handle<Map> holder_map(holder->map()); | 1219 Handle<Map> holder_map(holder->map()); |
1174 // Traverse the prototype chain and check the maps in the prototype chain for | 1220 // Traverse the prototype chain and check the maps in the prototype chain for |
1175 // fast and global objects or do negative lookup for normal objects. | 1221 // fast and global objects or do negative lookup for normal objects. |
1176 while (!current_map.is_identical_to(holder_map)) { | 1222 while (!current_map.is_identical_to(holder_map)) { |
1177 ++depth; | 1223 ++depth; |
1178 | 1224 |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1226 if (in_new_space) { | 1272 if (in_new_space) { |
1227 // The prototype is in new space; we cannot store a reference to it | 1273 // The prototype is in new space; we cannot store a reference to it |
1228 // in the code. Load it from the map. | 1274 // in the code. Load it from the map. |
1229 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); | 1275 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); |
1230 } else { | 1276 } else { |
1231 // The prototype is in old space; load it directly. | 1277 // The prototype is in old space; load it directly. |
1232 __ mov(reg, prototype); | 1278 __ mov(reg, prototype); |
1233 } | 1279 } |
1234 } | 1280 } |
1235 | 1281 |
| 1282 if (save_at_depth == depth) { |
| 1283 __ mov(Operand(esp, kHolderIndex * kPointerSize), reg); |
| 1284 } |
| 1285 |
1236 // Go to the next object in the prototype chain. | 1286 // Go to the next object in the prototype chain. |
1237 current = prototype; | 1287 current = prototype; |
1238 current_map = handle(current->map()); | 1288 current_map = handle(current->map()); |
1239 } | 1289 } |
1240 | 1290 |
1241 // Log the check depth. | 1291 // Log the check depth. |
1242 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); | 1292 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); |
1243 | 1293 |
1244 if (depth != 0 || check == CHECK_ALL_MAPS) { | 1294 if (depth != 0 || check == CHECK_ALL_MAPS) { |
1245 // Check the holder map. | 1295 // Check the holder map. |
(...skipping 376 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1622 Handle<JSObject> holder, | 1672 Handle<JSObject> holder, |
1623 Handle<Cell> cell, | 1673 Handle<Cell> cell, |
1624 Handle<JSFunction> function, | 1674 Handle<JSFunction> function, |
1625 Handle<String> name) { | 1675 Handle<String> name) { |
1626 ASSERT(optimization.is_simple_api_call()); | 1676 ASSERT(optimization.is_simple_api_call()); |
1627 // Bail out if object is a global object as we don't want to | 1677 // Bail out if object is a global object as we don't want to |
1628 // repatch it to global receiver. | 1678 // repatch it to global receiver. |
1629 if (object->IsGlobalObject()) return Handle<Code>::null(); | 1679 if (object->IsGlobalObject()) return Handle<Code>::null(); |
1630 if (!cell.is_null()) return Handle<Code>::null(); | 1680 if (!cell.is_null()) return Handle<Code>::null(); |
1631 if (!object->IsJSObject()) return Handle<Code>::null(); | 1681 if (!object->IsJSObject()) return Handle<Code>::null(); |
1632 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1682 int depth = optimization.GetPrototypeDepthOfExpectedType( |
1633 CallOptimization::HolderLookup holder_lookup = | 1683 Handle<JSObject>::cast(object), holder); |
1634 CallOptimization::kHolderNotFound; | 1684 if (depth == kInvalidProtoDepth) return Handle<Code>::null(); |
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 } | |
1640 | 1685 |
1641 Label miss; | 1686 Label miss, miss_before_stack_reserved; |
1642 GenerateNameCheck(name, &miss); | 1687 |
| 1688 GenerateNameCheck(name, &miss_before_stack_reserved); |
1643 | 1689 |
1644 // Get the receiver from the stack. | 1690 // Get the receiver from the stack. |
1645 const int argc = arguments().immediate(); | 1691 const int argc = arguments().immediate(); |
1646 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 1692 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
1647 | 1693 |
1648 // Check that the receiver isn't a smi. | 1694 // Check that the receiver isn't a smi. |
1649 __ JumpIfSmi(edx, &miss); | 1695 __ JumpIfSmi(edx, &miss_before_stack_reserved); |
1650 | 1696 |
1651 Counters* counters = isolate()->counters(); | 1697 Counters* counters = isolate()->counters(); |
1652 __ IncrementCounter(counters->call_const(), 1); | 1698 __ 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)); |
1653 | 1704 |
1654 // Check that the maps haven't changed and find a Holder as a side effect. | 1705 // Check that the maps haven't changed and find a Holder as a side effect. |
1655 CheckPrototypes(IC::CurrentTypeOf(object, isolate()), edx, holder, | 1706 CheckPrototypes(IC::CurrentTypeOf(object, isolate()), edx, holder, |
1656 ebx, eax, edi, name, &miss); | 1707 ebx, eax, edi, name, depth, &miss); |
1657 | 1708 |
1658 GenerateFastApiCall(masm(), optimization, argc, lookup_map, holder_lookup); | 1709 // Move the return address on top of the stack. |
| 1710 __ mov(eax, Operand(esp, kFastApiCallArguments * kPointerSize)); |
| 1711 __ mov(Operand(esp, 0 * kPointerSize), eax); |
1659 | 1712 |
1660 HandlerFrontendFooter(&miss); | 1713 // esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains |
| 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); |
1661 | 1721 |
1662 // Return the generated code. | 1722 // Return the generated code. |
1663 return GetCode(function); | 1723 return GetCode(function); |
1664 } | 1724 } |
1665 | 1725 |
1666 | 1726 |
1667 void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) { | 1727 void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) { |
1668 Label success; | 1728 Label success; |
1669 // Check that the object is a boolean. | 1729 // Check that the object is a boolean. |
1670 __ cmp(object, factory()->true_value()); | 1730 __ cmp(object, factory()->true_value()); |
(...skipping 515 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2186 // ----------------------------------- | 2246 // ----------------------------------- |
2187 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); | 2247 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); |
2188 } | 2248 } |
2189 | 2249 |
2190 | 2250 |
2191 #undef __ | 2251 #undef __ |
2192 | 2252 |
2193 } } // namespace v8::internal | 2253 } } // namespace v8::internal |
2194 | 2254 |
2195 #endif // V8_TARGET_ARCH_IA32 | 2255 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |