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 |