| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved.7 | 1 // Copyright 2012 the V8 project authors. All rights reserved.7 |
| 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 2039 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2050 __ BranchF(chunk_->GetAssemblyLabel(left_block), NULL, | 2050 __ BranchF(chunk_->GetAssemblyLabel(left_block), NULL, |
| 2051 condition, src1, src2); | 2051 condition, src1, src2); |
| 2052 } else { | 2052 } else { |
| 2053 __ BranchF(chunk_->GetAssemblyLabel(left_block), NULL, | 2053 __ BranchF(chunk_->GetAssemblyLabel(left_block), NULL, |
| 2054 condition, src1, src2); | 2054 condition, src1, src2); |
| 2055 __ Branch(chunk_->GetAssemblyLabel(right_block)); | 2055 __ Branch(chunk_->GetAssemblyLabel(right_block)); |
| 2056 } | 2056 } |
| 2057 } | 2057 } |
| 2058 | 2058 |
| 2059 | 2059 |
| 2060 template<class InstrType> | 2060 template <class InstrType> |
| 2061 void LCodeGen::EmitFalseBranch(InstrType instr, | 2061 void LCodeGen::EmitTrueBranch(InstrType instr, Condition condition, |
| 2062 Condition condition, | 2062 Register src1, const Operand& src2) { |
| 2063 Register src1, | 2063 int true_block = instr->TrueDestination(chunk_); |
| 2064 const Operand& src2) { | 2064 __ Branch(chunk_->GetAssemblyLabel(true_block), condition, src1, src2); |
| 2065 } |
| 2066 |
| 2067 |
| 2068 template <class InstrType> |
| 2069 void LCodeGen::EmitFalseBranch(InstrType instr, Condition condition, |
| 2070 Register src1, const Operand& src2) { |
| 2065 int false_block = instr->FalseDestination(chunk_); | 2071 int false_block = instr->FalseDestination(chunk_); |
| 2066 __ Branch(chunk_->GetAssemblyLabel(false_block), condition, src1, src2); | 2072 __ Branch(chunk_->GetAssemblyLabel(false_block), condition, src1, src2); |
| 2067 } | 2073 } |
| 2068 | 2074 |
| 2069 | 2075 |
| 2070 template<class InstrType> | 2076 template<class InstrType> |
| 2071 void LCodeGen::EmitFalseBranchF(InstrType instr, | 2077 void LCodeGen::EmitFalseBranchF(InstrType instr, |
| 2072 Condition condition, | 2078 Condition condition, |
| 2073 FPURegister src1, | 2079 FPURegister src1, |
| 2074 FPURegister src2) { | 2080 FPURegister src2) { |
| (...skipping 569 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2644 Register reg = ToRegister(instr->value()); | 2650 Register reg = ToRegister(instr->value()); |
| 2645 Register temp = ToRegister(instr->temp()); | 2651 Register temp = ToRegister(instr->temp()); |
| 2646 | 2652 |
| 2647 __ lw(temp, FieldMemOperand(reg, HeapObject::kMapOffset)); | 2653 __ lw(temp, FieldMemOperand(reg, HeapObject::kMapOffset)); |
| 2648 EmitBranch(instr, eq, temp, Operand(instr->map())); | 2654 EmitBranch(instr, eq, temp, Operand(instr->map())); |
| 2649 } | 2655 } |
| 2650 | 2656 |
| 2651 | 2657 |
| 2652 void LCodeGen::DoInstanceOf(LInstanceOf* instr) { | 2658 void LCodeGen::DoInstanceOf(LInstanceOf* instr) { |
| 2653 DCHECK(ToRegister(instr->context()).is(cp)); | 2659 DCHECK(ToRegister(instr->context()).is(cp)); |
| 2654 Label true_label, done; | 2660 DCHECK(ToRegister(instr->left()).is(InstanceOfDescriptor::LeftRegister())); |
| 2655 DCHECK(ToRegister(instr->left()).is(a0)); // Object is in a0. | 2661 DCHECK(ToRegister(instr->right()).is(InstanceOfDescriptor::RightRegister())); |
| 2656 DCHECK(ToRegister(instr->right()).is(a1)); // Function is in a1. | 2662 DCHECK(ToRegister(instr->result()).is(v0)); |
| 2657 Register result = ToRegister(instr->result()); | 2663 InstanceOfStub stub(isolate()); |
| 2658 DCHECK(result.is(v0)); | |
| 2659 | |
| 2660 InstanceofStub stub(isolate(), InstanceofStub::kArgsInRegisters); | |
| 2661 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 2664 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 2662 | |
| 2663 __ Branch(&true_label, eq, result, Operand(zero_reg)); | |
| 2664 __ li(result, Operand(factory()->false_value())); | |
| 2665 __ Branch(&done); | |
| 2666 __ bind(&true_label); | |
| 2667 __ li(result, Operand(factory()->true_value())); | |
| 2668 __ bind(&done); | |
| 2669 } | 2665 } |
| 2670 | 2666 |
| 2671 | 2667 |
| 2672 void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { | 2668 void LCodeGen::DoHasInPrototypeChainAndBranch( |
| 2673 class DeferredInstanceOfKnownGlobal final : public LDeferredCode { | 2669 LHasInPrototypeChainAndBranch* instr) { |
| 2674 public: | 2670 Register const object = ToRegister(instr->object()); |
| 2675 DeferredInstanceOfKnownGlobal(LCodeGen* codegen, | 2671 Register const object_map = scratch0(); |
| 2676 LInstanceOfKnownGlobal* instr) | 2672 Register const object_prototype = object_map; |
| 2677 : LDeferredCode(codegen), instr_(instr) { } | 2673 Register const prototype = ToRegister(instr->prototype()); |
| 2678 void Generate() override { | |
| 2679 codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_); | |
| 2680 } | |
| 2681 LInstruction* instr() override { return instr_; } | |
| 2682 Label* map_check() { return &map_check_; } | |
| 2683 | 2674 |
| 2684 private: | 2675 // The {object} must be a spec object. It's sufficient to know that {object} |
| 2685 LInstanceOfKnownGlobal* instr_; | 2676 // is not a smi, since all other non-spec objects have {null} prototypes and |
| 2686 Label map_check_; | 2677 // will be ruled out below. |
| 2687 }; | 2678 if (instr->hydrogen()->ObjectNeedsSmiCheck()) { |
| 2688 | 2679 __ SmiTst(object, at); |
| 2689 DeferredInstanceOfKnownGlobal* deferred; | 2680 EmitFalseBranch(instr, eq, at, Operand(zero_reg)); |
| 2690 deferred = new(zone()) DeferredInstanceOfKnownGlobal(this, instr); | 2681 } |
| 2691 | 2682 // Loop through the {object}s prototype chain looking for the {prototype}. |
| 2692 Label done, false_result; | 2683 __ lw(object_map, FieldMemOperand(object, HeapObject::kMapOffset)); |
| 2693 Register object = ToRegister(instr->value()); | 2684 Label loop; |
| 2694 Register temp = ToRegister(instr->temp()); | 2685 __ bind(&loop); |
| 2695 Register result = ToRegister(instr->result()); | 2686 __ lw(object_prototype, FieldMemOperand(object_map, Map::kPrototypeOffset)); |
| 2696 | 2687 EmitTrueBranch(instr, eq, object_prototype, Operand(prototype)); |
| 2697 DCHECK(object.is(a0)); | 2688 __ LoadRoot(at, Heap::kNullValueRootIndex); |
| 2698 DCHECK(result.is(v0)); | 2689 EmitFalseBranch(instr, eq, object_prototype, Operand(at)); |
| 2699 | 2690 __ Branch(USE_DELAY_SLOT, &loop); |
| 2700 // A Smi is not instance of anything. | 2691 __ lw(object_map, FieldMemOperand(object_prototype, HeapObject::kMapOffset)); |
| 2701 __ JumpIfSmi(object, &false_result); | |
| 2702 | |
| 2703 // This is the inlined call site instanceof cache. The two occurences of the | |
| 2704 // hole value will be patched to the last map/result pair generated by the | |
| 2705 // instanceof stub. | |
| 2706 Label cache_miss; | |
| 2707 Register map = temp; | |
| 2708 __ lw(map, FieldMemOperand(object, HeapObject::kMapOffset)); | |
| 2709 | |
| 2710 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); | |
| 2711 __ bind(deferred->map_check()); // Label for calculating code patching. | |
| 2712 // We use Factory::the_hole_value() on purpose instead of loading from the | |
| 2713 // root array to force relocation to be able to later patch with | |
| 2714 // the cached map. | |
| 2715 Handle<Cell> cell = factory()->NewCell(factory()->the_hole_value()); | |
| 2716 __ li(at, Operand(cell)); | |
| 2717 __ lw(at, FieldMemOperand(at, Cell::kValueOffset)); | |
| 2718 __ BranchShort(&cache_miss, ne, map, Operand(at)); | |
| 2719 // We use Factory::the_hole_value() on purpose instead of loading from the | |
| 2720 // root array to force relocation to be able to later patch | |
| 2721 // with true or false. The distance from map check has to be constant. | |
| 2722 __ li(result, Operand(factory()->the_hole_value()), CONSTANT_SIZE); | |
| 2723 __ Branch(&done); | |
| 2724 | |
| 2725 // The inlined call site cache did not match. Check null and string before | |
| 2726 // calling the deferred code. | |
| 2727 __ bind(&cache_miss); | |
| 2728 // Null is not instance of anything. | |
| 2729 __ LoadRoot(temp, Heap::kNullValueRootIndex); | |
| 2730 __ Branch(&false_result, eq, object, Operand(temp)); | |
| 2731 | |
| 2732 // String values is not instance of anything. | |
| 2733 Condition cc = __ IsObjectStringType(object, temp, temp); | |
| 2734 __ Branch(&false_result, cc, temp, Operand(zero_reg)); | |
| 2735 | |
| 2736 // Go to the deferred code. | |
| 2737 __ Branch(deferred->entry()); | |
| 2738 | |
| 2739 __ bind(&false_result); | |
| 2740 __ LoadRoot(result, Heap::kFalseValueRootIndex); | |
| 2741 | |
| 2742 // Here result has either true or false. Deferred code also produces true or | |
| 2743 // false object. | |
| 2744 __ bind(deferred->exit()); | |
| 2745 __ bind(&done); | |
| 2746 } | 2692 } |
| 2747 | 2693 |
| 2748 | 2694 |
| 2749 void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, | |
| 2750 Label* map_check) { | |
| 2751 Register result = ToRegister(instr->result()); | |
| 2752 DCHECK(result.is(v0)); | |
| 2753 | |
| 2754 InstanceofStub::Flags flags = InstanceofStub::kNoFlags; | |
| 2755 flags = static_cast<InstanceofStub::Flags>( | |
| 2756 flags | InstanceofStub::kArgsInRegisters); | |
| 2757 flags = static_cast<InstanceofStub::Flags>( | |
| 2758 flags | InstanceofStub::kCallSiteInlineCheck); | |
| 2759 flags = static_cast<InstanceofStub::Flags>( | |
| 2760 flags | InstanceofStub::kReturnTrueFalseObject); | |
| 2761 InstanceofStub stub(isolate(), flags); | |
| 2762 | |
| 2763 PushSafepointRegistersScope scope(this); | |
| 2764 LoadContextFromDeferred(instr->context()); | |
| 2765 | |
| 2766 // Get the temp register reserved by the instruction. This needs to be t0 as | |
| 2767 // its slot of the pushing of safepoint registers is used to communicate the | |
| 2768 // offset to the location of the map check. | |
| 2769 Register temp = ToRegister(instr->temp()); | |
| 2770 DCHECK(temp.is(t0)); | |
| 2771 __ li(InstanceofStub::right(), instr->function()); | |
| 2772 static const int kAdditionalDelta = 7; | |
| 2773 int delta = masm_->InstructionsGeneratedSince(map_check) + kAdditionalDelta; | |
| 2774 Label before_push_delta; | |
| 2775 __ bind(&before_push_delta); | |
| 2776 { | |
| 2777 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); | |
| 2778 __ li(temp, Operand(delta * kPointerSize), CONSTANT_SIZE); | |
| 2779 __ StoreToSafepointRegisterSlot(temp, temp); | |
| 2780 } | |
| 2781 CallCodeGeneric(stub.GetCode(), | |
| 2782 RelocInfo::CODE_TARGET, | |
| 2783 instr, | |
| 2784 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); | |
| 2785 LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment(); | |
| 2786 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); | |
| 2787 // Put the result value into the result register slot and | |
| 2788 // restore all registers. | |
| 2789 __ StoreToSafepointRegisterSlot(result, result); | |
| 2790 } | |
| 2791 | |
| 2792 | |
| 2793 void LCodeGen::DoCmpT(LCmpT* instr) { | 2695 void LCodeGen::DoCmpT(LCmpT* instr) { |
| 2794 DCHECK(ToRegister(instr->context()).is(cp)); | 2696 DCHECK(ToRegister(instr->context()).is(cp)); |
| 2795 Token::Value op = instr->op(); | 2697 Token::Value op = instr->op(); |
| 2796 | 2698 |
| 2797 Handle<Code> ic = | 2699 Handle<Code> ic = |
| 2798 CodeFactory::CompareIC(isolate(), op, instr->strength()).code(); | 2700 CodeFactory::CompareIC(isolate(), op, instr->strength()).code(); |
| 2799 CallCode(ic, RelocInfo::CODE_TARGET, instr); | 2701 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 2800 // On MIPS there is no need for a "no inlined smi code" marker (nop). | 2702 // On MIPS there is no need for a "no inlined smi code" marker (nop). |
| 2801 | 2703 |
| 2802 Condition condition = ComputeCompareCondition(op); | 2704 Condition condition = ComputeCompareCondition(op); |
| (...skipping 3262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6065 __ Push(at, ToRegister(instr->function())); | 5967 __ Push(at, ToRegister(instr->function())); |
| 6066 CallRuntime(Runtime::kPushBlockContext, 2, instr); | 5968 CallRuntime(Runtime::kPushBlockContext, 2, instr); |
| 6067 RecordSafepoint(Safepoint::kNoLazyDeopt); | 5969 RecordSafepoint(Safepoint::kNoLazyDeopt); |
| 6068 } | 5970 } |
| 6069 | 5971 |
| 6070 | 5972 |
| 6071 #undef __ | 5973 #undef __ |
| 6072 | 5974 |
| 6073 } // namespace internal | 5975 } // namespace internal |
| 6074 } // namespace v8 | 5976 } // namespace v8 |
| OLD | NEW |