| 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 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 55 private: | 55 private: |
| 56 LCodeGen* codegen_; | 56 LCodeGen* codegen_; |
| 57 LPointerMap* pointers_; | 57 LPointerMap* pointers_; |
| 58 Safepoint::DeoptMode deopt_mode_; | 58 Safepoint::DeoptMode deopt_mode_; |
| 59 }; | 59 }; |
| 60 | 60 |
| 61 | 61 |
| 62 #define __ masm()-> | 62 #define __ masm()-> |
| 63 | 63 |
| 64 bool LCodeGen::GenerateCode() { | 64 bool LCodeGen::GenerateCode() { |
| 65 HPhase phase("Z_Code generation", chunk()); | 65 LPhase phase("Z_Code generation", chunk()); |
| 66 ASSERT(is_unused()); | 66 ASSERT(is_unused()); |
| 67 status_ = GENERATING; | 67 status_ = GENERATING; |
| 68 | 68 |
| 69 // Open a frame scope to indicate that there is a frame on the stack. The | 69 // Open a frame scope to indicate that there is a frame on the stack. The |
| 70 // NONE indicates that the scope shouldn't actually generate code to set up | 70 // NONE indicates that the scope shouldn't actually generate code to set up |
| 71 // the frame (that is done in GeneratePrologue). | 71 // the frame (that is done in GeneratePrologue). |
| 72 FrameScope frame_scope(masm_, StackFrame::NONE); | 72 FrameScope frame_scope(masm_, StackFrame::NONE); |
| 73 | 73 |
| 74 return GeneratePrologue() && | 74 return GeneratePrologue() && |
| 75 GenerateBody() && | 75 GenerateBody() && |
| 76 GenerateDeferredCode() && | 76 GenerateDeferredCode() && |
| 77 GenerateDeoptJumpTable() && | 77 GenerateDeoptJumpTable() && |
| 78 GenerateSafepointTable(); | 78 GenerateSafepointTable(); |
| 79 } | 79 } |
| 80 | 80 |
| 81 | 81 |
| 82 void LCodeGen::FinishCode(Handle<Code> code) { | 82 void LCodeGen::FinishCode(Handle<Code> code) { |
| 83 ASSERT(is_done()); | 83 ASSERT(is_done()); |
| 84 code->set_stack_slots(GetStackSlotCount()); | 84 code->set_stack_slots(GetStackSlotCount()); |
| 85 code->set_safepoint_table_offset(safepoints_.GetCodeOffset()); | 85 code->set_safepoint_table_offset(safepoints_.GetCodeOffset()); |
| 86 if (FLAG_weak_embedded_maps_in_optimized_code) { | 86 if (FLAG_weak_embedded_maps_in_optimized_code) { |
| 87 RegisterDependentCodeForEmbeddedMaps(code); | 87 RegisterDependentCodeForEmbeddedMaps(code); |
| 88 } | 88 } |
| 89 PopulateDeoptimizationData(code); | 89 PopulateDeoptimizationData(code); |
| 90 info()->CommitDependentMaps(code); | 90 info()->CommitDependencies(code); |
| 91 } | 91 } |
| 92 | 92 |
| 93 | 93 |
| 94 void LChunkBuilder::Abort(const char* reason) { | 94 void LChunkBuilder::Abort(const char* reason) { |
| 95 info()->set_bailout_reason(reason); | 95 info()->set_bailout_reason(reason); |
| 96 status_ = ABORTED; | 96 status_ = ABORTED; |
| 97 } | 97 } |
| 98 | 98 |
| 99 | 99 |
| 100 void LCodeGen::Comment(const char* format, ...) { | 100 void LCodeGen::Comment(const char* format, ...) { |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 236 cp, target.offset(), a0, a3, GetRAState(), kSaveFPRegs); | 236 cp, target.offset(), a0, a3, GetRAState(), kSaveFPRegs); |
| 237 } | 237 } |
| 238 } | 238 } |
| 239 Comment(";;; End allocate local context"); | 239 Comment(";;; End allocate local context"); |
| 240 } | 240 } |
| 241 | 241 |
| 242 // Trace the call. | 242 // Trace the call. |
| 243 if (FLAG_trace && info()->IsOptimizing()) { | 243 if (FLAG_trace && info()->IsOptimizing()) { |
| 244 __ CallRuntime(Runtime::kTraceEnter, 0); | 244 __ CallRuntime(Runtime::kTraceEnter, 0); |
| 245 } | 245 } |
| 246 EnsureSpaceForLazyDeopt(); | |
| 247 return !is_aborted(); | 246 return !is_aborted(); |
| 248 } | 247 } |
| 249 | 248 |
| 250 | 249 |
| 251 bool LCodeGen::GenerateBody() { | 250 bool LCodeGen::GenerateBody() { |
| 252 ASSERT(is_generating()); | 251 ASSERT(is_generating()); |
| 253 bool emit_instructions = true; | 252 bool emit_instructions = true; |
| 254 for (current_instruction_ = 0; | 253 for (current_instruction_ = 0; |
| 255 !is_aborted() && current_instruction_ < instructions_->length(); | 254 !is_aborted() && current_instruction_ < instructions_->length(); |
| 256 current_instruction_++) { | 255 current_instruction_++) { |
| 257 LInstruction* instr = instructions_->at(current_instruction_); | 256 LInstruction* instr = instructions_->at(current_instruction_); |
| 258 | 257 |
| 259 // Don't emit code for basic blocks with a replacement. | 258 // Don't emit code for basic blocks with a replacement. |
| 260 if (instr->IsLabel()) { | 259 if (instr->IsLabel()) { |
| 261 emit_instructions = !LLabel::cast(instr)->HasReplacement(); | 260 emit_instructions = !LLabel::cast(instr)->HasReplacement(); |
| 262 } | 261 } |
| 263 if (!emit_instructions) continue; | 262 if (!emit_instructions) continue; |
| 264 | 263 |
| 265 if (FLAG_code_comments && instr->HasInterestingComment(this)) { | 264 if (FLAG_code_comments && instr->HasInterestingComment(this)) { |
| 266 Comment(";;; <@%d,#%d> %s", | 265 Comment(";;; <@%d,#%d> %s", |
| 267 current_instruction_, | 266 current_instruction_, |
| 268 instr->hydrogen_value()->id(), | 267 instr->hydrogen_value()->id(), |
| 269 instr->Mnemonic()); | 268 instr->Mnemonic()); |
| 270 } | 269 } |
| 271 | 270 |
| 272 instr->CompileToNative(this); | 271 instr->CompileToNative(this); |
| 273 } | 272 } |
| 273 EnsureSpaceForLazyDeopt(); |
| 274 return !is_aborted(); | 274 return !is_aborted(); |
| 275 } | 275 } |
| 276 | 276 |
| 277 | 277 |
| 278 bool LCodeGen::GenerateDeferredCode() { | 278 bool LCodeGen::GenerateDeferredCode() { |
| 279 ASSERT(is_generating()); | 279 ASSERT(is_generating()); |
| 280 if (deferred_.length() > 0) { | 280 if (deferred_.length() > 0) { |
| 281 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) { | 281 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) { |
| 282 LDeferredCode* code = deferred_[i]; | 282 LDeferredCode* code = deferred_[i]; |
| 283 Comment(";;; <@%d,#%d> " | 283 Comment(";;; <@%d,#%d> " |
| (...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 596 case STUB: | 596 case STUB: |
| 597 translation->BeginCompiledStubFrame(); | 597 translation->BeginCompiledStubFrame(); |
| 598 break; | 598 break; |
| 599 case ARGUMENTS_ADAPTOR: | 599 case ARGUMENTS_ADAPTOR: |
| 600 translation->BeginArgumentsAdaptorFrame(closure_id, translation_size); | 600 translation->BeginArgumentsAdaptorFrame(closure_id, translation_size); |
| 601 break; | 601 break; |
| 602 } | 602 } |
| 603 | 603 |
| 604 for (int i = 0; i < translation_size; ++i) { | 604 for (int i = 0; i < translation_size; ++i) { |
| 605 LOperand* value = environment->values()->at(i); | 605 LOperand* value = environment->values()->at(i); |
| 606 // spilled_registers_ and spilled_double_registers_ are either | |
| 607 // both NULL or both set. | |
| 608 if (environment->spilled_registers() != NULL && value != NULL) { | |
| 609 if (value->IsRegister() && | |
| 610 environment->spilled_registers()[value->index()] != NULL) { | |
| 611 translation->MarkDuplicate(); | |
| 612 AddToTranslation(translation, | |
| 613 environment->spilled_registers()[value->index()], | |
| 614 environment->HasTaggedValueAt(i), | |
| 615 environment->HasUint32ValueAt(i)); | |
| 616 } else if ( | |
| 617 value->IsDoubleRegister() && | |
| 618 environment->spilled_double_registers()[value->index()] != NULL) { | |
| 619 translation->MarkDuplicate(); | |
| 620 AddToTranslation( | |
| 621 translation, | |
| 622 environment->spilled_double_registers()[value->index()], | |
| 623 false, | |
| 624 false); | |
| 625 } | |
| 626 } | |
| 627 | 606 |
| 628 // TODO(mstarzinger): Introduce marker operands to indicate that this value | 607 // TODO(mstarzinger): Introduce marker operands to indicate that this value |
| 629 // is not present and must be reconstructed from the deoptimizer. Currently | 608 // is not present and must be reconstructed from the deoptimizer. Currently |
| 630 // this is only used for the arguments object. | 609 // this is only used for the arguments object. |
| 631 if (value == NULL) { | 610 if (value == NULL) { |
| 632 int arguments_count = environment->values()->length() - translation_size; | 611 int arguments_count = environment->values()->length() - translation_size; |
| 633 translation->BeginArgumentsObject(arguments_count); | 612 translation->BeginArgumentsObject(arguments_count); |
| 634 for (int i = 0; i < arguments_count; ++i) { | 613 for (int i = 0; i < arguments_count; ++i) { |
| 635 LOperand* value = environment->values()->at(translation_size + i); | 614 LOperand* value = environment->values()->at(translation_size + i); |
| 636 ASSERT(environment->spilled_registers() == NULL || | |
| 637 !value->IsRegister() || | |
| 638 environment->spilled_registers()[value->index()] == NULL); | |
| 639 ASSERT(environment->spilled_registers() == NULL || | |
| 640 !value->IsDoubleRegister() || | |
| 641 environment->spilled_double_registers()[value->index()] == NULL); | |
| 642 AddToTranslation(translation, | 615 AddToTranslation(translation, |
| 643 value, | 616 value, |
| 644 environment->HasTaggedValueAt(translation_size + i), | 617 environment->HasTaggedValueAt(translation_size + i), |
| 645 environment->HasUint32ValueAt(translation_size + i)); | 618 environment->HasUint32ValueAt(translation_size + i)); |
| 646 } | 619 } |
| 647 continue; | 620 continue; |
| 648 } | 621 } |
| 649 | 622 |
| 650 AddToTranslation(translation, | 623 AddToTranslation(translation, |
| 651 value, | 624 value, |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 699 RelocInfo::Mode mode, | 672 RelocInfo::Mode mode, |
| 700 LInstruction* instr) { | 673 LInstruction* instr) { |
| 701 CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT); | 674 CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT); |
| 702 } | 675 } |
| 703 | 676 |
| 704 | 677 |
| 705 void LCodeGen::CallCodeGeneric(Handle<Code> code, | 678 void LCodeGen::CallCodeGeneric(Handle<Code> code, |
| 706 RelocInfo::Mode mode, | 679 RelocInfo::Mode mode, |
| 707 LInstruction* instr, | 680 LInstruction* instr, |
| 708 SafepointMode safepoint_mode) { | 681 SafepointMode safepoint_mode) { |
| 682 EnsureSpaceForLazyDeopt(); |
| 709 ASSERT(instr != NULL); | 683 ASSERT(instr != NULL); |
| 710 LPointerMap* pointers = instr->pointer_map(); | 684 LPointerMap* pointers = instr->pointer_map(); |
| 711 RecordPosition(pointers->position()); | 685 RecordPosition(pointers->position()); |
| 712 __ Call(code, mode); | 686 __ Call(code, mode); |
| 713 RecordSafepointWithLazyDeopt(instr, safepoint_mode); | 687 RecordSafepointWithLazyDeopt(instr, safepoint_mode); |
| 714 } | 688 } |
| 715 | 689 |
| 716 | 690 |
| 717 void LCodeGen::CallRuntime(const Runtime::Function* function, | 691 void LCodeGen::CallRuntime(const Runtime::Function* function, |
| 718 int num_arguments, | 692 int num_arguments, |
| (...skipping 374 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1093 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); | 1067 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); |
| 1094 break; | 1068 break; |
| 1095 } | 1069 } |
| 1096 default: | 1070 default: |
| 1097 UNREACHABLE(); | 1071 UNREACHABLE(); |
| 1098 } | 1072 } |
| 1099 } | 1073 } |
| 1100 | 1074 |
| 1101 | 1075 |
| 1102 void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { | 1076 void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { |
| 1103 // Nothing to do. | 1077 // Record the address of the first unknown OSR value as the place to enter. |
| 1078 if (osr_pc_offset_ == -1) osr_pc_offset_ = masm()->pc_offset(); |
| 1104 } | 1079 } |
| 1105 | 1080 |
| 1106 | 1081 |
| 1107 void LCodeGen::DoModI(LModI* instr) { | 1082 void LCodeGen::DoModI(LModI* instr) { |
| 1108 HMod* hmod = instr->hydrogen(); | 1083 HMod* hmod = instr->hydrogen(); |
| 1109 HValue* left = hmod->left(); | 1084 HValue* left = hmod->left(); |
| 1110 HValue* right = hmod->right(); | 1085 HValue* right = hmod->right(); |
| 1111 if (hmod->HasPowerOf2Divisor()) { | 1086 if (hmod->HasPowerOf2Divisor()) { |
| 1112 const Register scratch = scratch0(); | 1087 const Register scratch = scratch0(); |
| 1113 const Register left_reg = ToRegister(instr->left()); | 1088 const Register left_reg = ToRegister(instr->left()); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1129 DeoptimizeIf(eq, instr->environment(), result_reg, Operand(zero_reg)); | 1104 DeoptimizeIf(eq, instr->environment(), result_reg, Operand(zero_reg)); |
| 1130 } | 1105 } |
| 1131 __ Branch(USE_DELAY_SLOT, &done); | 1106 __ Branch(USE_DELAY_SLOT, &done); |
| 1132 __ subu(result_reg, zero_reg, result_reg); | 1107 __ subu(result_reg, zero_reg, result_reg); |
| 1133 } | 1108 } |
| 1134 | 1109 |
| 1135 __ bind(&left_is_not_negative); | 1110 __ bind(&left_is_not_negative); |
| 1136 __ And(result_reg, scratch, divisor - 1); | 1111 __ And(result_reg, scratch, divisor - 1); |
| 1137 __ bind(&done); | 1112 __ bind(&done); |
| 1138 | 1113 |
| 1139 } else { | 1114 } else if (hmod->fixed_right_arg().has_value) { |
| 1140 // TODO(svenpanne) Add right->has_fixed_right_arg() case. | |
| 1141 | |
| 1142 const Register scratch = scratch0(); | 1115 const Register scratch = scratch0(); |
| 1143 const Register left_reg = ToRegister(instr->left()); | 1116 const Register left_reg = ToRegister(instr->left()); |
| 1144 const Register result_reg = ToRegister(instr->result()); | 1117 const Register result_reg = ToRegister(instr->result()); |
| 1118 |
| 1119 Register right_reg = EmitLoadRegister(instr->right(), scratch); |
| 1120 |
| 1121 int32_t divisor = hmod->fixed_right_arg().value; |
| 1122 ASSERT(IsPowerOf2(divisor)); |
| 1123 |
| 1124 // Check if our assumption of a fixed right operand still holds. |
| 1125 DeoptimizeIf(ne, instr->environment(), right_reg, Operand(divisor)); |
| 1126 |
| 1127 Label left_is_not_negative, done; |
| 1128 if (left->CanBeNegative()) { |
| 1129 __ Branch(USE_DELAY_SLOT, &left_is_not_negative, |
| 1130 ge, left_reg, Operand(zero_reg)); |
| 1131 __ subu(result_reg, zero_reg, left_reg); |
| 1132 __ And(result_reg, result_reg, divisor - 1); |
| 1133 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 1134 DeoptimizeIf(eq, instr->environment(), result_reg, Operand(zero_reg)); |
| 1135 } |
| 1136 __ Branch(USE_DELAY_SLOT, &done); |
| 1137 __ subu(result_reg, zero_reg, result_reg); |
| 1138 } |
| 1139 |
| 1140 __ bind(&left_is_not_negative); |
| 1141 __ And(result_reg, left_reg, divisor - 1); |
| 1142 __ bind(&done); |
| 1143 |
| 1144 } else { |
| 1145 const Register scratch = scratch0(); |
| 1146 const Register left_reg = ToRegister(instr->left()); |
| 1147 const Register result_reg = ToRegister(instr->result()); |
| 1145 | 1148 |
| 1146 // div runs in the background while we check for special cases. | 1149 // div runs in the background while we check for special cases. |
| 1147 Register right_reg = EmitLoadRegister(instr->right(), scratch); | 1150 Register right_reg = EmitLoadRegister(instr->right(), scratch); |
| 1148 __ div(left_reg, right_reg); | 1151 __ div(left_reg, right_reg); |
| 1149 | 1152 |
| 1150 Label done; | 1153 Label done; |
| 1151 // Check for x % 0, we have to deopt in this case because we can't return a | 1154 // Check for x % 0, we have to deopt in this case because we can't return a |
| 1152 // NaN. | 1155 // NaN. |
| 1153 if (right->CanBeZero()) { | 1156 if (right->CanBeZero()) { |
| 1154 DeoptimizeIf(eq, instr->environment(), right_reg, Operand(zero_reg)); | 1157 DeoptimizeIf(eq, instr->environment(), right_reg, Operand(zero_reg)); |
| (...skipping 544 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1699 __ Ext(result, result, Map::kElementsKindShift, Map::kElementsKindBitCount); | 1702 __ Ext(result, result, Map::kElementsKindShift, Map::kElementsKindBitCount); |
| 1700 } | 1703 } |
| 1701 | 1704 |
| 1702 | 1705 |
| 1703 void LCodeGen::DoValueOf(LValueOf* instr) { | 1706 void LCodeGen::DoValueOf(LValueOf* instr) { |
| 1704 Register input = ToRegister(instr->value()); | 1707 Register input = ToRegister(instr->value()); |
| 1705 Register result = ToRegister(instr->result()); | 1708 Register result = ToRegister(instr->result()); |
| 1706 Register map = ToRegister(instr->temp()); | 1709 Register map = ToRegister(instr->temp()); |
| 1707 Label done; | 1710 Label done; |
| 1708 | 1711 |
| 1709 // If the object is a smi return the object. | 1712 if (!instr->hydrogen()->value()->IsHeapObject()) { |
| 1710 __ Move(result, input); | 1713 // If the object is a smi return the object. |
| 1711 __ JumpIfSmi(input, &done); | 1714 __ Move(result, input); |
| 1715 __ JumpIfSmi(input, &done); |
| 1716 } |
| 1712 | 1717 |
| 1713 // If the object is not a value type, return the object. | 1718 // If the object is not a value type, return the object. |
| 1714 __ GetObjectType(input, map, map); | 1719 __ GetObjectType(input, map, map); |
| 1715 __ Branch(&done, ne, map, Operand(JS_VALUE_TYPE)); | 1720 __ Branch(&done, ne, map, Operand(JS_VALUE_TYPE)); |
| 1716 __ lw(result, FieldMemOperand(input, JSValue::kValueOffset)); | 1721 __ lw(result, FieldMemOperand(input, JSValue::kValueOffset)); |
| 1717 | 1722 |
| 1718 __ bind(&done); | 1723 __ bind(&done); |
| 1719 } | 1724 } |
| 1720 | 1725 |
| 1721 | 1726 |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1963 } | 1968 } |
| 1964 | 1969 |
| 1965 | 1970 |
| 1966 int LCodeGen::GetNextEmittedBlock() const { | 1971 int LCodeGen::GetNextEmittedBlock() const { |
| 1967 for (int i = current_block_ + 1; i < graph()->blocks()->length(); ++i) { | 1972 for (int i = current_block_ + 1; i < graph()->blocks()->length(); ++i) { |
| 1968 if (!chunk_->GetLabel(i)->HasReplacement()) return i; | 1973 if (!chunk_->GetLabel(i)->HasReplacement()) return i; |
| 1969 } | 1974 } |
| 1970 return -1; | 1975 return -1; |
| 1971 } | 1976 } |
| 1972 | 1977 |
| 1978 template<class InstrType> |
| 1979 void LCodeGen::EmitBranch(InstrType instr, |
| 1980 Condition cc, Register src1, const Operand& src2) { |
| 1981 int right_block = instr->FalseDestination(chunk_); |
| 1982 int left_block = instr->TrueDestination(chunk_); |
| 1973 | 1983 |
| 1974 void LCodeGen::EmitBranch(int left_block, int right_block, | |
| 1975 Condition cc, Register src1, const Operand& src2) { | |
| 1976 int next_block = GetNextEmittedBlock(); | 1984 int next_block = GetNextEmittedBlock(); |
| 1977 right_block = chunk_->LookupDestination(right_block); | |
| 1978 left_block = chunk_->LookupDestination(left_block); | |
| 1979 if (right_block == left_block) { | 1985 if (right_block == left_block) { |
| 1980 EmitGoto(left_block); | 1986 EmitGoto(left_block); |
| 1981 } else if (left_block == next_block) { | 1987 } else if (left_block == next_block) { |
| 1982 __ Branch(chunk_->GetAssemblyLabel(right_block), | 1988 __ Branch(chunk_->GetAssemblyLabel(right_block), |
| 1983 NegateCondition(cc), src1, src2); | 1989 NegateCondition(cc), src1, src2); |
| 1984 } else if (right_block == next_block) { | 1990 } else if (right_block == next_block) { |
| 1985 __ Branch(chunk_->GetAssemblyLabel(left_block), cc, src1, src2); | 1991 __ Branch(chunk_->GetAssemblyLabel(left_block), cc, src1, src2); |
| 1986 } else { | 1992 } else { |
| 1987 __ Branch(chunk_->GetAssemblyLabel(left_block), cc, src1, src2); | 1993 __ Branch(chunk_->GetAssemblyLabel(left_block), cc, src1, src2); |
| 1988 __ Branch(chunk_->GetAssemblyLabel(right_block)); | 1994 __ Branch(chunk_->GetAssemblyLabel(right_block)); |
| 1989 } | 1995 } |
| 1990 } | 1996 } |
| 1991 | 1997 |
| 1992 | 1998 |
| 1993 void LCodeGen::EmitBranchF(int left_block, int right_block, | 1999 template<class InstrType> |
| 2000 void LCodeGen::EmitBranchF(InstrType instr, |
| 1994 Condition cc, FPURegister src1, FPURegister src2) { | 2001 Condition cc, FPURegister src1, FPURegister src2) { |
| 2002 int right_block = instr->FalseDestination(chunk_); |
| 2003 int left_block = instr->TrueDestination(chunk_); |
| 2004 |
| 1995 int next_block = GetNextEmittedBlock(); | 2005 int next_block = GetNextEmittedBlock(); |
| 1996 right_block = chunk_->LookupDestination(right_block); | |
| 1997 left_block = chunk_->LookupDestination(left_block); | |
| 1998 if (right_block == left_block) { | 2006 if (right_block == left_block) { |
| 1999 EmitGoto(left_block); | 2007 EmitGoto(left_block); |
| 2000 } else if (left_block == next_block) { | 2008 } else if (left_block == next_block) { |
| 2001 __ BranchF(chunk_->GetAssemblyLabel(right_block), NULL, | 2009 __ BranchF(chunk_->GetAssemblyLabel(right_block), NULL, |
| 2002 NegateCondition(cc), src1, src2); | 2010 NegateCondition(cc), src1, src2); |
| 2003 } else if (right_block == next_block) { | 2011 } else if (right_block == next_block) { |
| 2004 __ BranchF(chunk_->GetAssemblyLabel(left_block), NULL, cc, src1, src2); | 2012 __ BranchF(chunk_->GetAssemblyLabel(left_block), NULL, cc, src1, src2); |
| 2005 } else { | 2013 } else { |
| 2006 __ BranchF(chunk_->GetAssemblyLabel(left_block), NULL, cc, src1, src2); | 2014 __ BranchF(chunk_->GetAssemblyLabel(left_block), NULL, cc, src1, src2); |
| 2007 __ Branch(chunk_->GetAssemblyLabel(right_block)); | 2015 __ Branch(chunk_->GetAssemblyLabel(right_block)); |
| 2008 } | 2016 } |
| 2009 } | 2017 } |
| 2010 | 2018 |
| 2011 | 2019 |
| 2012 void LCodeGen::DoDebugBreak(LDebugBreak* instr) { | 2020 void LCodeGen::DoDebugBreak(LDebugBreak* instr) { |
| 2013 __ stop("LDebugBreak"); | 2021 __ stop("LDebugBreak"); |
| 2014 } | 2022 } |
| 2015 | 2023 |
| 2016 | 2024 |
| 2017 void LCodeGen::DoBranch(LBranch* instr) { | 2025 void LCodeGen::DoBranch(LBranch* instr) { |
| 2018 int true_block = chunk_->LookupDestination(instr->true_block_id()); | |
| 2019 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
| 2020 | |
| 2021 Representation r = instr->hydrogen()->value()->representation(); | 2026 Representation r = instr->hydrogen()->value()->representation(); |
| 2022 if (r.IsInteger32() || r.IsSmi()) { | 2027 if (r.IsInteger32() || r.IsSmi()) { |
| 2023 ASSERT(!info()->IsStub()); | 2028 ASSERT(!info()->IsStub()); |
| 2024 Register reg = ToRegister(instr->value()); | 2029 Register reg = ToRegister(instr->value()); |
| 2025 EmitBranch(true_block, false_block, ne, reg, Operand(zero_reg)); | 2030 EmitBranch(instr, ne, reg, Operand(zero_reg)); |
| 2026 } else if (r.IsDouble()) { | 2031 } else if (r.IsDouble()) { |
| 2027 ASSERT(!info()->IsStub()); | 2032 ASSERT(!info()->IsStub()); |
| 2028 DoubleRegister reg = ToDoubleRegister(instr->value()); | 2033 DoubleRegister reg = ToDoubleRegister(instr->value()); |
| 2029 // Test the double value. Zero and NaN are false. | 2034 // Test the double value. Zero and NaN are false. |
| 2030 EmitBranchF(true_block, false_block, nue, reg, kDoubleRegZero); | 2035 EmitBranchF(instr, nue, reg, kDoubleRegZero); |
| 2031 } else { | 2036 } else { |
| 2032 ASSERT(r.IsTagged()); | 2037 ASSERT(r.IsTagged()); |
| 2033 Register reg = ToRegister(instr->value()); | 2038 Register reg = ToRegister(instr->value()); |
| 2034 HType type = instr->hydrogen()->value()->type(); | 2039 HType type = instr->hydrogen()->value()->type(); |
| 2035 if (type.IsBoolean()) { | 2040 if (type.IsBoolean()) { |
| 2036 ASSERT(!info()->IsStub()); | 2041 ASSERT(!info()->IsStub()); |
| 2037 __ LoadRoot(at, Heap::kTrueValueRootIndex); | 2042 __ LoadRoot(at, Heap::kTrueValueRootIndex); |
| 2038 EmitBranch(true_block, false_block, eq, reg, Operand(at)); | 2043 EmitBranch(instr, eq, reg, Operand(at)); |
| 2039 } else if (type.IsSmi()) { | 2044 } else if (type.IsSmi()) { |
| 2040 ASSERT(!info()->IsStub()); | 2045 ASSERT(!info()->IsStub()); |
| 2041 EmitBranch(true_block, false_block, ne, reg, Operand(zero_reg)); | 2046 EmitBranch(instr, ne, reg, Operand(zero_reg)); |
| 2047 } else if (type.IsJSArray()) { |
| 2048 ASSERT(!info()->IsStub()); |
| 2049 EmitBranch(instr, al, zero_reg, Operand(zero_reg)); |
| 2050 } else if (type.IsHeapNumber()) { |
| 2051 ASSERT(!info()->IsStub()); |
| 2052 DoubleRegister dbl_scratch = double_scratch0(); |
| 2053 __ ldc1(dbl_scratch, FieldMemOperand(reg, HeapNumber::kValueOffset)); |
| 2054 // Test the double value. Zero and NaN are false. |
| 2055 EmitBranchF(instr, nue, dbl_scratch, kDoubleRegZero); |
| 2056 } else if (type.IsString()) { |
| 2057 ASSERT(!info()->IsStub()); |
| 2058 __ lw(at, FieldMemOperand(reg, String::kLengthOffset)); |
| 2059 EmitBranch(instr, ne, at, Operand(zero_reg)); |
| 2042 } else { | 2060 } else { |
| 2043 Label* true_label = chunk_->GetAssemblyLabel(true_block); | |
| 2044 Label* false_label = chunk_->GetAssemblyLabel(false_block); | |
| 2045 | |
| 2046 ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types(); | 2061 ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types(); |
| 2047 // Avoid deopts in the case where we've never executed this path before. | 2062 // Avoid deopts in the case where we've never executed this path before. |
| 2048 if (expected.IsEmpty()) expected = ToBooleanStub::all_types(); | 2063 if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic(); |
| 2049 | 2064 |
| 2050 if (expected.Contains(ToBooleanStub::UNDEFINED)) { | 2065 if (expected.Contains(ToBooleanStub::UNDEFINED)) { |
| 2051 // undefined -> false. | 2066 // undefined -> false. |
| 2052 __ LoadRoot(at, Heap::kUndefinedValueRootIndex); | 2067 __ LoadRoot(at, Heap::kUndefinedValueRootIndex); |
| 2053 __ Branch(false_label, eq, reg, Operand(at)); | 2068 __ Branch(instr->FalseLabel(chunk_), eq, reg, Operand(at)); |
| 2054 } | 2069 } |
| 2055 if (expected.Contains(ToBooleanStub::BOOLEAN)) { | 2070 if (expected.Contains(ToBooleanStub::BOOLEAN)) { |
| 2056 // Boolean -> its value. | 2071 // Boolean -> its value. |
| 2057 __ LoadRoot(at, Heap::kTrueValueRootIndex); | 2072 __ LoadRoot(at, Heap::kTrueValueRootIndex); |
| 2058 __ Branch(true_label, eq, reg, Operand(at)); | 2073 __ Branch(instr->TrueLabel(chunk_), eq, reg, Operand(at)); |
| 2059 __ LoadRoot(at, Heap::kFalseValueRootIndex); | 2074 __ LoadRoot(at, Heap::kFalseValueRootIndex); |
| 2060 __ Branch(false_label, eq, reg, Operand(at)); | 2075 __ Branch(instr->FalseLabel(chunk_), eq, reg, Operand(at)); |
| 2061 } | 2076 } |
| 2062 if (expected.Contains(ToBooleanStub::NULL_TYPE)) { | 2077 if (expected.Contains(ToBooleanStub::NULL_TYPE)) { |
| 2063 // 'null' -> false. | 2078 // 'null' -> false. |
| 2064 __ LoadRoot(at, Heap::kNullValueRootIndex); | 2079 __ LoadRoot(at, Heap::kNullValueRootIndex); |
| 2065 __ Branch(false_label, eq, reg, Operand(at)); | 2080 __ Branch(instr->FalseLabel(chunk_), eq, reg, Operand(at)); |
| 2066 } | 2081 } |
| 2067 | 2082 |
| 2068 if (expected.Contains(ToBooleanStub::SMI)) { | 2083 if (expected.Contains(ToBooleanStub::SMI)) { |
| 2069 // Smis: 0 -> false, all other -> true. | 2084 // Smis: 0 -> false, all other -> true. |
| 2070 __ Branch(false_label, eq, reg, Operand(zero_reg)); | 2085 __ Branch(instr->FalseLabel(chunk_), eq, reg, Operand(zero_reg)); |
| 2071 __ JumpIfSmi(reg, true_label); | 2086 __ JumpIfSmi(reg, instr->TrueLabel(chunk_)); |
| 2072 } else if (expected.NeedsMap()) { | 2087 } else if (expected.NeedsMap()) { |
| 2073 // If we need a map later and have a Smi -> deopt. | 2088 // If we need a map later and have a Smi -> deopt. |
| 2074 __ And(at, reg, Operand(kSmiTagMask)); | 2089 __ And(at, reg, Operand(kSmiTagMask)); |
| 2075 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg)); | 2090 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg)); |
| 2076 } | 2091 } |
| 2077 | 2092 |
| 2078 const Register map = scratch0(); | 2093 const Register map = scratch0(); |
| 2079 if (expected.NeedsMap()) { | 2094 if (expected.NeedsMap()) { |
| 2080 __ lw(map, FieldMemOperand(reg, HeapObject::kMapOffset)); | 2095 __ lw(map, FieldMemOperand(reg, HeapObject::kMapOffset)); |
| 2081 if (expected.CanBeUndetectable()) { | 2096 if (expected.CanBeUndetectable()) { |
| 2082 // Undetectable -> false. | 2097 // Undetectable -> false. |
| 2083 __ lbu(at, FieldMemOperand(map, Map::kBitFieldOffset)); | 2098 __ lbu(at, FieldMemOperand(map, Map::kBitFieldOffset)); |
| 2084 __ And(at, at, Operand(1 << Map::kIsUndetectable)); | 2099 __ And(at, at, Operand(1 << Map::kIsUndetectable)); |
| 2085 __ Branch(false_label, ne, at, Operand(zero_reg)); | 2100 __ Branch(instr->FalseLabel(chunk_), ne, at, Operand(zero_reg)); |
| 2086 } | 2101 } |
| 2087 } | 2102 } |
| 2088 | 2103 |
| 2089 if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) { | 2104 if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) { |
| 2090 // spec object -> true. | 2105 // spec object -> true. |
| 2091 __ lbu(at, FieldMemOperand(map, Map::kInstanceTypeOffset)); | 2106 __ lbu(at, FieldMemOperand(map, Map::kInstanceTypeOffset)); |
| 2092 __ Branch(true_label, ge, at, Operand(FIRST_SPEC_OBJECT_TYPE)); | 2107 __ Branch(instr->TrueLabel(chunk_), |
| 2108 ge, at, Operand(FIRST_SPEC_OBJECT_TYPE)); |
| 2093 } | 2109 } |
| 2094 | 2110 |
| 2095 if (expected.Contains(ToBooleanStub::STRING)) { | 2111 if (expected.Contains(ToBooleanStub::STRING)) { |
| 2096 // String value -> false iff empty. | 2112 // String value -> false iff empty. |
| 2097 Label not_string; | 2113 Label not_string; |
| 2098 __ lbu(at, FieldMemOperand(map, Map::kInstanceTypeOffset)); | 2114 __ lbu(at, FieldMemOperand(map, Map::kInstanceTypeOffset)); |
| 2099 __ Branch(¬_string, ge , at, Operand(FIRST_NONSTRING_TYPE)); | 2115 __ Branch(¬_string, ge , at, Operand(FIRST_NONSTRING_TYPE)); |
| 2100 __ lw(at, FieldMemOperand(reg, String::kLengthOffset)); | 2116 __ lw(at, FieldMemOperand(reg, String::kLengthOffset)); |
| 2101 __ Branch(true_label, ne, at, Operand(zero_reg)); | 2117 __ Branch(instr->TrueLabel(chunk_), ne, at, Operand(zero_reg)); |
| 2102 __ Branch(false_label); | 2118 __ Branch(instr->FalseLabel(chunk_)); |
| 2103 __ bind(¬_string); | 2119 __ bind(¬_string); |
| 2104 } | 2120 } |
| 2105 | 2121 |
| 2106 if (expected.Contains(ToBooleanStub::SYMBOL)) { | 2122 if (expected.Contains(ToBooleanStub::SYMBOL)) { |
| 2107 // Symbol value -> true. | 2123 // Symbol value -> true. |
| 2108 const Register scratch = scratch1(); | 2124 const Register scratch = scratch1(); |
| 2109 __ lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset)); | 2125 __ lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset)); |
| 2110 __ Branch(true_label, eq, scratch, Operand(SYMBOL_TYPE)); | 2126 __ Branch(instr->TrueLabel(chunk_), eq, scratch, Operand(SYMBOL_TYPE)); |
| 2111 } | 2127 } |
| 2112 | 2128 |
| 2113 if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) { | 2129 if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) { |
| 2114 // heap number -> false iff +0, -0, or NaN. | 2130 // heap number -> false iff +0, -0, or NaN. |
| 2115 DoubleRegister dbl_scratch = double_scratch0(); | 2131 DoubleRegister dbl_scratch = double_scratch0(); |
| 2116 Label not_heap_number; | 2132 Label not_heap_number; |
| 2117 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex); | 2133 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex); |
| 2118 __ Branch(¬_heap_number, ne, map, Operand(at)); | 2134 __ Branch(¬_heap_number, ne, map, Operand(at)); |
| 2119 __ ldc1(dbl_scratch, FieldMemOperand(reg, HeapNumber::kValueOffset)); | 2135 __ ldc1(dbl_scratch, FieldMemOperand(reg, HeapNumber::kValueOffset)); |
| 2120 __ BranchF(true_label, false_label, ne, dbl_scratch, kDoubleRegZero); | 2136 __ BranchF(instr->TrueLabel(chunk_), instr->FalseLabel(chunk_), |
| 2137 ne, dbl_scratch, kDoubleRegZero); |
| 2121 // Falls through if dbl_scratch == 0. | 2138 // Falls through if dbl_scratch == 0. |
| 2122 __ Branch(false_label); | 2139 __ Branch(instr->FalseLabel(chunk_)); |
| 2123 __ bind(¬_heap_number); | 2140 __ bind(¬_heap_number); |
| 2124 } | 2141 } |
| 2125 | 2142 |
| 2126 // We've seen something for the first time -> deopt. | 2143 if (!expected.IsGeneric()) { |
| 2127 DeoptimizeIf(al, instr->environment(), zero_reg, Operand(zero_reg)); | 2144 // We've seen something for the first time -> deopt. |
| 2145 // This can only happen if we are not generic already. |
| 2146 DeoptimizeIf(al, instr->environment(), zero_reg, Operand(zero_reg)); |
| 2147 } |
| 2128 } | 2148 } |
| 2129 } | 2149 } |
| 2130 } | 2150 } |
| 2131 | 2151 |
| 2132 | 2152 |
| 2133 void LCodeGen::EmitGoto(int block) { | 2153 void LCodeGen::EmitGoto(int block) { |
| 2134 if (!IsNextEmittedBlock(block)) { | 2154 if (!IsNextEmittedBlock(block)) { |
| 2135 __ jmp(chunk_->GetAssemblyLabel(chunk_->LookupDestination(block))); | 2155 __ jmp(chunk_->GetAssemblyLabel(LookupDestination(block))); |
| 2136 } | 2156 } |
| 2137 } | 2157 } |
| 2138 | 2158 |
| 2139 | 2159 |
| 2140 void LCodeGen::DoGoto(LGoto* instr) { | 2160 void LCodeGen::DoGoto(LGoto* instr) { |
| 2141 EmitGoto(instr->block_id()); | 2161 EmitGoto(instr->block_id()); |
| 2142 } | 2162 } |
| 2143 | 2163 |
| 2144 | 2164 |
| 2145 Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) { | 2165 Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 2166 default: | 2186 default: |
| 2167 UNREACHABLE(); | 2187 UNREACHABLE(); |
| 2168 } | 2188 } |
| 2169 return cond; | 2189 return cond; |
| 2170 } | 2190 } |
| 2171 | 2191 |
| 2172 | 2192 |
| 2173 void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { | 2193 void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { |
| 2174 LOperand* left = instr->left(); | 2194 LOperand* left = instr->left(); |
| 2175 LOperand* right = instr->right(); | 2195 LOperand* right = instr->right(); |
| 2176 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
| 2177 int true_block = chunk_->LookupDestination(instr->true_block_id()); | |
| 2178 | |
| 2179 Condition cond = TokenToCondition(instr->op(), false); | 2196 Condition cond = TokenToCondition(instr->op(), false); |
| 2180 | 2197 |
| 2181 if (left->IsConstantOperand() && right->IsConstantOperand()) { | 2198 if (left->IsConstantOperand() && right->IsConstantOperand()) { |
| 2182 // We can statically evaluate the comparison. | 2199 // We can statically evaluate the comparison. |
| 2183 double left_val = ToDouble(LConstantOperand::cast(left)); | 2200 double left_val = ToDouble(LConstantOperand::cast(left)); |
| 2184 double right_val = ToDouble(LConstantOperand::cast(right)); | 2201 double right_val = ToDouble(LConstantOperand::cast(right)); |
| 2185 int next_block = | 2202 int next_block = EvalComparison(instr->op(), left_val, right_val) ? |
| 2186 EvalComparison(instr->op(), left_val, right_val) ? true_block | 2203 instr->TrueDestination(chunk_) : instr->FalseDestination(chunk_); |
| 2187 : false_block; | |
| 2188 EmitGoto(next_block); | 2204 EmitGoto(next_block); |
| 2189 } else { | 2205 } else { |
| 2190 if (instr->is_double()) { | 2206 if (instr->is_double()) { |
| 2191 // Compare left and right as doubles and load the | 2207 // Compare left and right as doubles and load the |
| 2192 // resulting flags into the normal status register. | 2208 // resulting flags into the normal status register. |
| 2193 FPURegister left_reg = ToDoubleRegister(left); | 2209 FPURegister left_reg = ToDoubleRegister(left); |
| 2194 FPURegister right_reg = ToDoubleRegister(right); | 2210 FPURegister right_reg = ToDoubleRegister(right); |
| 2195 | 2211 |
| 2196 // If a NaN is involved, i.e. the result is unordered, | 2212 // If a NaN is involved, i.e. the result is unordered, |
| 2197 // jump to false block label. | 2213 // jump to false block label. |
| 2198 __ BranchF(NULL, chunk_->GetAssemblyLabel(false_block), eq, | 2214 __ BranchF(NULL, instr->FalseLabel(chunk_), eq, |
| 2199 left_reg, right_reg); | 2215 left_reg, right_reg); |
| 2200 | 2216 |
| 2201 EmitBranchF(true_block, false_block, cond, left_reg, right_reg); | 2217 EmitBranchF(instr, cond, left_reg, right_reg); |
| 2202 } else { | 2218 } else { |
| 2203 Register cmp_left; | 2219 Register cmp_left; |
| 2204 Operand cmp_right = Operand(0); | 2220 Operand cmp_right = Operand(0); |
| 2205 | 2221 |
| 2206 if (right->IsConstantOperand()) { | 2222 if (right->IsConstantOperand()) { |
| 2207 int32_t value = ToInteger32(LConstantOperand::cast(right)); | 2223 int32_t value = ToInteger32(LConstantOperand::cast(right)); |
| 2208 if (instr->hydrogen_value()->representation().IsSmi()) { | 2224 if (instr->hydrogen_value()->representation().IsSmi()) { |
| 2209 cmp_left = ToRegister(left); | 2225 cmp_left = ToRegister(left); |
| 2210 cmp_right = Operand(Smi::FromInt(value)); | 2226 cmp_right = Operand(Smi::FromInt(value)); |
| 2211 } else { | 2227 } else { |
| 2212 cmp_left = ToRegister(left); | 2228 cmp_left = ToRegister(left); |
| 2213 cmp_right = Operand(value); | 2229 cmp_right = Operand(value); |
| 2214 } | 2230 } |
| 2215 } else if (left->IsConstantOperand()) { | 2231 } else if (left->IsConstantOperand()) { |
| 2216 int32_t value = ToInteger32(LConstantOperand::cast(left)); | 2232 int32_t value = ToInteger32(LConstantOperand::cast(left)); |
| 2217 if (instr->hydrogen_value()->representation().IsSmi()) { | 2233 if (instr->hydrogen_value()->representation().IsSmi()) { |
| 2218 cmp_left = ToRegister(right); | 2234 cmp_left = ToRegister(right); |
| 2219 cmp_right = Operand(Smi::FromInt(value)); | 2235 cmp_right = Operand(Smi::FromInt(value)); |
| 2220 } else { | 2236 } else { |
| 2221 cmp_left = ToRegister(right); | 2237 cmp_left = ToRegister(right); |
| 2222 cmp_right = Operand(value); | 2238 cmp_right = Operand(value); |
| 2223 } | 2239 } |
| 2224 // We transposed the operands. Reverse the condition. | 2240 // We transposed the operands. Reverse the condition. |
| 2225 cond = ReverseCondition(cond); | 2241 cond = ReverseCondition(cond); |
| 2226 } else { | 2242 } else { |
| 2227 cmp_left = ToRegister(left); | 2243 cmp_left = ToRegister(left); |
| 2228 cmp_right = Operand(ToRegister(right)); | 2244 cmp_right = Operand(ToRegister(right)); |
| 2229 } | 2245 } |
| 2230 | 2246 |
| 2231 EmitBranch(true_block, false_block, cond, cmp_left, cmp_right); | 2247 EmitBranch(instr, cond, cmp_left, cmp_right); |
| 2232 } | 2248 } |
| 2233 } | 2249 } |
| 2234 } | 2250 } |
| 2235 | 2251 |
| 2236 | 2252 |
| 2237 void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) { | 2253 void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) { |
| 2238 Register left = ToRegister(instr->left()); | 2254 Register left = ToRegister(instr->left()); |
| 2239 Register right = ToRegister(instr->right()); | 2255 Register right = ToRegister(instr->right()); |
| 2240 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
| 2241 int true_block = chunk_->LookupDestination(instr->true_block_id()); | |
| 2242 | 2256 |
| 2243 EmitBranch(true_block, false_block, eq, left, Operand(right)); | 2257 EmitBranch(instr, eq, left, Operand(right)); |
| 2244 } | 2258 } |
| 2245 | 2259 |
| 2246 | 2260 |
| 2247 void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) { | 2261 void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) { |
| 2248 Register left = ToRegister(instr->left()); | 2262 Register left = ToRegister(instr->left()); |
| 2249 int true_block = chunk_->LookupDestination(instr->true_block_id()); | |
| 2250 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
| 2251 | 2263 |
| 2252 EmitBranch(true_block, false_block, eq, left, | 2264 EmitBranch(instr, eq, left, Operand(instr->hydrogen()->right())); |
| 2253 Operand(instr->hydrogen()->right())); | |
| 2254 } | 2265 } |
| 2255 | 2266 |
| 2256 | 2267 |
| 2257 Condition LCodeGen::EmitIsObject(Register input, | 2268 Condition LCodeGen::EmitIsObject(Register input, |
| 2258 Register temp1, | 2269 Register temp1, |
| 2259 Register temp2, | 2270 Register temp2, |
| 2260 Label* is_not_object, | 2271 Label* is_not_object, |
| 2261 Label* is_object) { | 2272 Label* is_object) { |
| 2262 __ JumpIfSmi(input, is_not_object); | 2273 __ JumpIfSmi(input, is_not_object); |
| 2263 | 2274 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 2278 | 2289 |
| 2279 return le; | 2290 return le; |
| 2280 } | 2291 } |
| 2281 | 2292 |
| 2282 | 2293 |
| 2283 void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) { | 2294 void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) { |
| 2284 Register reg = ToRegister(instr->value()); | 2295 Register reg = ToRegister(instr->value()); |
| 2285 Register temp1 = ToRegister(instr->temp()); | 2296 Register temp1 = ToRegister(instr->temp()); |
| 2286 Register temp2 = scratch0(); | 2297 Register temp2 = scratch0(); |
| 2287 | 2298 |
| 2288 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 2299 Condition true_cond = |
| 2289 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 2300 EmitIsObject(reg, temp1, temp2, |
| 2290 Label* true_label = chunk_->GetAssemblyLabel(true_block); | 2301 instr->FalseLabel(chunk_), instr->TrueLabel(chunk_)); |
| 2291 Label* false_label = chunk_->GetAssemblyLabel(false_block); | |
| 2292 | 2302 |
| 2293 Condition true_cond = | 2303 EmitBranch(instr, true_cond, temp2, |
| 2294 EmitIsObject(reg, temp1, temp2, false_label, true_label); | |
| 2295 | |
| 2296 EmitBranch(true_block, false_block, true_cond, temp2, | |
| 2297 Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE)); | 2304 Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE)); |
| 2298 } | 2305 } |
| 2299 | 2306 |
| 2300 | 2307 |
| 2301 Condition LCodeGen::EmitIsString(Register input, | 2308 Condition LCodeGen::EmitIsString(Register input, |
| 2302 Register temp1, | 2309 Register temp1, |
| 2303 Label* is_not_string) { | 2310 Label* is_not_string, |
| 2304 __ JumpIfSmi(input, is_not_string); | 2311 SmiCheck check_needed = INLINE_SMI_CHECK) { |
| 2312 if (check_needed == INLINE_SMI_CHECK) { |
| 2313 __ JumpIfSmi(input, is_not_string); |
| 2314 } |
| 2305 __ GetObjectType(input, temp1, temp1); | 2315 __ GetObjectType(input, temp1, temp1); |
| 2306 | 2316 |
| 2307 return lt; | 2317 return lt; |
| 2308 } | 2318 } |
| 2309 | 2319 |
| 2310 | 2320 |
| 2311 void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) { | 2321 void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) { |
| 2312 Register reg = ToRegister(instr->value()); | 2322 Register reg = ToRegister(instr->value()); |
| 2313 Register temp1 = ToRegister(instr->temp()); | 2323 Register temp1 = ToRegister(instr->temp()); |
| 2314 | 2324 |
| 2315 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 2325 SmiCheck check_needed = |
| 2316 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 2326 instr->hydrogen()->value()->IsHeapObject() |
| 2317 Label* false_label = chunk_->GetAssemblyLabel(false_block); | 2327 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; |
| 2328 Condition true_cond = |
| 2329 EmitIsString(reg, temp1, instr->FalseLabel(chunk_), check_needed); |
| 2318 | 2330 |
| 2319 Condition true_cond = | 2331 EmitBranch(instr, true_cond, temp1, |
| 2320 EmitIsString(reg, temp1, false_label); | |
| 2321 | |
| 2322 EmitBranch(true_block, false_block, true_cond, temp1, | |
| 2323 Operand(FIRST_NONSTRING_TYPE)); | 2332 Operand(FIRST_NONSTRING_TYPE)); |
| 2324 } | 2333 } |
| 2325 | 2334 |
| 2326 | 2335 |
| 2327 void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { | 2336 void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { |
| 2328 int true_block = chunk_->LookupDestination(instr->true_block_id()); | |
| 2329 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
| 2330 | |
| 2331 Register input_reg = EmitLoadRegister(instr->value(), at); | 2337 Register input_reg = EmitLoadRegister(instr->value(), at); |
| 2332 __ And(at, input_reg, kSmiTagMask); | 2338 __ And(at, input_reg, kSmiTagMask); |
| 2333 EmitBranch(true_block, false_block, eq, at, Operand(zero_reg)); | 2339 EmitBranch(instr, eq, at, Operand(zero_reg)); |
| 2334 } | 2340 } |
| 2335 | 2341 |
| 2336 | 2342 |
| 2337 void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) { | 2343 void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) { |
| 2338 Register input = ToRegister(instr->value()); | 2344 Register input = ToRegister(instr->value()); |
| 2339 Register temp = ToRegister(instr->temp()); | 2345 Register temp = ToRegister(instr->temp()); |
| 2340 | 2346 |
| 2341 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 2347 if (!instr->hydrogen()->value()->IsHeapObject()) { |
| 2342 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 2348 __ JumpIfSmi(input, instr->FalseLabel(chunk_)); |
| 2343 | 2349 } |
| 2344 __ JumpIfSmi(input, chunk_->GetAssemblyLabel(false_block)); | |
| 2345 __ lw(temp, FieldMemOperand(input, HeapObject::kMapOffset)); | 2350 __ lw(temp, FieldMemOperand(input, HeapObject::kMapOffset)); |
| 2346 __ lbu(temp, FieldMemOperand(temp, Map::kBitFieldOffset)); | 2351 __ lbu(temp, FieldMemOperand(temp, Map::kBitFieldOffset)); |
| 2347 __ And(at, temp, Operand(1 << Map::kIsUndetectable)); | 2352 __ And(at, temp, Operand(1 << Map::kIsUndetectable)); |
| 2348 EmitBranch(true_block, false_block, ne, at, Operand(zero_reg)); | 2353 EmitBranch(instr, ne, at, Operand(zero_reg)); |
| 2349 } | 2354 } |
| 2350 | 2355 |
| 2351 | 2356 |
| 2352 static Condition ComputeCompareCondition(Token::Value op) { | 2357 static Condition ComputeCompareCondition(Token::Value op) { |
| 2353 switch (op) { | 2358 switch (op) { |
| 2354 case Token::EQ_STRICT: | 2359 case Token::EQ_STRICT: |
| 2355 case Token::EQ: | 2360 case Token::EQ: |
| 2356 return eq; | 2361 return eq; |
| 2357 case Token::LT: | 2362 case Token::LT: |
| 2358 return lt; | 2363 return lt; |
| 2359 case Token::GT: | 2364 case Token::GT: |
| 2360 return gt; | 2365 return gt; |
| 2361 case Token::LTE: | 2366 case Token::LTE: |
| 2362 return le; | 2367 return le; |
| 2363 case Token::GTE: | 2368 case Token::GTE: |
| 2364 return ge; | 2369 return ge; |
| 2365 default: | 2370 default: |
| 2366 UNREACHABLE(); | 2371 UNREACHABLE(); |
| 2367 return kNoCondition; | 2372 return kNoCondition; |
| 2368 } | 2373 } |
| 2369 } | 2374 } |
| 2370 | 2375 |
| 2371 | 2376 |
| 2372 void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) { | 2377 void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) { |
| 2373 Token::Value op = instr->op(); | 2378 Token::Value op = instr->op(); |
| 2374 int true_block = chunk_->LookupDestination(instr->true_block_id()); | |
| 2375 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
| 2376 | 2379 |
| 2377 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op); | 2380 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op); |
| 2378 CallCode(ic, RelocInfo::CODE_TARGET, instr); | 2381 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 2379 | 2382 |
| 2380 Condition condition = ComputeCompareCondition(op); | 2383 Condition condition = ComputeCompareCondition(op); |
| 2381 | 2384 |
| 2382 EmitBranch(true_block, false_block, condition, v0, Operand(zero_reg)); | 2385 EmitBranch(instr, condition, v0, Operand(zero_reg)); |
| 2383 } | 2386 } |
| 2384 | 2387 |
| 2385 | 2388 |
| 2386 static InstanceType TestType(HHasInstanceTypeAndBranch* instr) { | 2389 static InstanceType TestType(HHasInstanceTypeAndBranch* instr) { |
| 2387 InstanceType from = instr->from(); | 2390 InstanceType from = instr->from(); |
| 2388 InstanceType to = instr->to(); | 2391 InstanceType to = instr->to(); |
| 2389 if (from == FIRST_TYPE) return to; | 2392 if (from == FIRST_TYPE) return to; |
| 2390 ASSERT(from == to || to == LAST_TYPE); | 2393 ASSERT(from == to || to == LAST_TYPE); |
| 2391 return from; | 2394 return from; |
| 2392 } | 2395 } |
| 2393 | 2396 |
| 2394 | 2397 |
| 2395 static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) { | 2398 static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) { |
| 2396 InstanceType from = instr->from(); | 2399 InstanceType from = instr->from(); |
| 2397 InstanceType to = instr->to(); | 2400 InstanceType to = instr->to(); |
| 2398 if (from == to) return eq; | 2401 if (from == to) return eq; |
| 2399 if (to == LAST_TYPE) return hs; | 2402 if (to == LAST_TYPE) return hs; |
| 2400 if (from == FIRST_TYPE) return ls; | 2403 if (from == FIRST_TYPE) return ls; |
| 2401 UNREACHABLE(); | 2404 UNREACHABLE(); |
| 2402 return eq; | 2405 return eq; |
| 2403 } | 2406 } |
| 2404 | 2407 |
| 2405 | 2408 |
| 2406 void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { | 2409 void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { |
| 2407 Register scratch = scratch0(); | 2410 Register scratch = scratch0(); |
| 2408 Register input = ToRegister(instr->value()); | 2411 Register input = ToRegister(instr->value()); |
| 2409 | 2412 |
| 2410 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 2413 if (!instr->hydrogen()->value()->IsHeapObject()) { |
| 2411 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 2414 __ JumpIfSmi(input, instr->FalseLabel(chunk_)); |
| 2412 | 2415 } |
| 2413 Label* false_label = chunk_->GetAssemblyLabel(false_block); | |
| 2414 | |
| 2415 __ JumpIfSmi(input, false_label); | |
| 2416 | 2416 |
| 2417 __ GetObjectType(input, scratch, scratch); | 2417 __ GetObjectType(input, scratch, scratch); |
| 2418 EmitBranch(true_block, | 2418 EmitBranch(instr, |
| 2419 false_block, | |
| 2420 BranchCondition(instr->hydrogen()), | 2419 BranchCondition(instr->hydrogen()), |
| 2421 scratch, | 2420 scratch, |
| 2422 Operand(TestType(instr->hydrogen()))); | 2421 Operand(TestType(instr->hydrogen()))); |
| 2423 } | 2422 } |
| 2424 | 2423 |
| 2425 | 2424 |
| 2426 void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) { | 2425 void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) { |
| 2427 Register input = ToRegister(instr->value()); | 2426 Register input = ToRegister(instr->value()); |
| 2428 Register result = ToRegister(instr->result()); | 2427 Register result = ToRegister(instr->result()); |
| 2429 | 2428 |
| 2430 __ AssertString(input); | 2429 __ AssertString(input); |
| 2431 | 2430 |
| 2432 __ lw(result, FieldMemOperand(input, String::kHashFieldOffset)); | 2431 __ lw(result, FieldMemOperand(input, String::kHashFieldOffset)); |
| 2433 __ IndexFromHash(result, result); | 2432 __ IndexFromHash(result, result); |
| 2434 } | 2433 } |
| 2435 | 2434 |
| 2436 | 2435 |
| 2437 void LCodeGen::DoHasCachedArrayIndexAndBranch( | 2436 void LCodeGen::DoHasCachedArrayIndexAndBranch( |
| 2438 LHasCachedArrayIndexAndBranch* instr) { | 2437 LHasCachedArrayIndexAndBranch* instr) { |
| 2439 Register input = ToRegister(instr->value()); | 2438 Register input = ToRegister(instr->value()); |
| 2440 Register scratch = scratch0(); | 2439 Register scratch = scratch0(); |
| 2441 | 2440 |
| 2442 int true_block = chunk_->LookupDestination(instr->true_block_id()); | |
| 2443 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
| 2444 | |
| 2445 __ lw(scratch, | 2441 __ lw(scratch, |
| 2446 FieldMemOperand(input, String::kHashFieldOffset)); | 2442 FieldMemOperand(input, String::kHashFieldOffset)); |
| 2447 __ And(at, scratch, Operand(String::kContainsCachedArrayIndexMask)); | 2443 __ And(at, scratch, Operand(String::kContainsCachedArrayIndexMask)); |
| 2448 EmitBranch(true_block, false_block, eq, at, Operand(zero_reg)); | 2444 EmitBranch(instr, eq, at, Operand(zero_reg)); |
| 2449 } | 2445 } |
| 2450 | 2446 |
| 2451 | 2447 |
| 2452 // Branches to a label or falls through with the answer in flags. Trashes | 2448 // Branches to a label or falls through with the answer in flags. Trashes |
| 2453 // the temp registers, but not the input. | 2449 // the temp registers, but not the input. |
| 2454 void LCodeGen::EmitClassOfTest(Label* is_true, | 2450 void LCodeGen::EmitClassOfTest(Label* is_true, |
| 2455 Label* is_false, | 2451 Label* is_false, |
| 2456 Handle<String>class_name, | 2452 Handle<String>class_name, |
| 2457 Register input, | 2453 Register input, |
| 2458 Register temp, | 2454 Register temp, |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2514 // On MIPS, the caller must do the comparison with Handle<String>class_name. | 2510 // On MIPS, the caller must do the comparison with Handle<String>class_name. |
| 2515 } | 2511 } |
| 2516 | 2512 |
| 2517 | 2513 |
| 2518 void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { | 2514 void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { |
| 2519 Register input = ToRegister(instr->value()); | 2515 Register input = ToRegister(instr->value()); |
| 2520 Register temp = scratch0(); | 2516 Register temp = scratch0(); |
| 2521 Register temp2 = ToRegister(instr->temp()); | 2517 Register temp2 = ToRegister(instr->temp()); |
| 2522 Handle<String> class_name = instr->hydrogen()->class_name(); | 2518 Handle<String> class_name = instr->hydrogen()->class_name(); |
| 2523 | 2519 |
| 2524 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 2520 EmitClassOfTest(instr->TrueLabel(chunk_), instr->FalseLabel(chunk_), |
| 2525 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 2521 class_name, input, temp, temp2); |
| 2526 | 2522 |
| 2527 Label* true_label = chunk_->GetAssemblyLabel(true_block); | 2523 EmitBranch(instr, eq, temp, Operand(class_name)); |
| 2528 Label* false_label = chunk_->GetAssemblyLabel(false_block); | |
| 2529 | |
| 2530 EmitClassOfTest(true_label, false_label, class_name, input, temp, temp2); | |
| 2531 | |
| 2532 EmitBranch(true_block, false_block, eq, temp, Operand(class_name)); | |
| 2533 } | 2524 } |
| 2534 | 2525 |
| 2535 | 2526 |
| 2536 void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { | 2527 void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { |
| 2537 Register reg = ToRegister(instr->value()); | 2528 Register reg = ToRegister(instr->value()); |
| 2538 Register temp = ToRegister(instr->temp()); | 2529 Register temp = ToRegister(instr->temp()); |
| 2539 int true_block = instr->true_block_id(); | |
| 2540 int false_block = instr->false_block_id(); | |
| 2541 | 2530 |
| 2542 __ lw(temp, FieldMemOperand(reg, HeapObject::kMapOffset)); | 2531 __ lw(temp, FieldMemOperand(reg, HeapObject::kMapOffset)); |
| 2543 EmitBranch(true_block, false_block, eq, temp, Operand(instr->map())); | 2532 EmitBranch(instr, eq, temp, Operand(instr->map())); |
| 2544 } | 2533 } |
| 2545 | 2534 |
| 2546 | 2535 |
| 2547 void LCodeGen::DoInstanceOf(LInstanceOf* instr) { | 2536 void LCodeGen::DoInstanceOf(LInstanceOf* instr) { |
| 2548 Label true_label, done; | 2537 Label true_label, done; |
| 2549 ASSERT(ToRegister(instr->left()).is(a0)); // Object is in a0. | 2538 ASSERT(ToRegister(instr->left()).is(a0)); // Object is in a0. |
| 2550 ASSERT(ToRegister(instr->right()).is(a1)); // Function is in a1. | 2539 ASSERT(ToRegister(instr->right()).is(a1)); // Function is in a1. |
| 2551 Register result = ToRegister(instr->result()); | 2540 Register result = ToRegister(instr->result()); |
| 2552 ASSERT(result.is(v0)); | 2541 ASSERT(result.is(v0)); |
| 2553 | 2542 |
| (...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2853 | 2842 |
| 2854 if (instr->hydrogen()->DeoptimizesOnHole()) { | 2843 if (instr->hydrogen()->DeoptimizesOnHole()) { |
| 2855 DeoptimizeIf(eq, instr->environment(), scratch, Operand(at)); | 2844 DeoptimizeIf(eq, instr->environment(), scratch, Operand(at)); |
| 2856 } else { | 2845 } else { |
| 2857 __ Branch(&skip_assignment, ne, scratch, Operand(at)); | 2846 __ Branch(&skip_assignment, ne, scratch, Operand(at)); |
| 2858 } | 2847 } |
| 2859 } | 2848 } |
| 2860 | 2849 |
| 2861 __ sw(value, target); | 2850 __ sw(value, target); |
| 2862 if (instr->hydrogen()->NeedsWriteBarrier()) { | 2851 if (instr->hydrogen()->NeedsWriteBarrier()) { |
| 2863 HType type = instr->hydrogen()->value()->type(); | |
| 2864 SmiCheck check_needed = | 2852 SmiCheck check_needed = |
| 2865 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; | 2853 instr->hydrogen()->value()->IsHeapObject() |
| 2854 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; |
| 2866 __ RecordWriteContextSlot(context, | 2855 __ RecordWriteContextSlot(context, |
| 2867 target.offset(), | 2856 target.offset(), |
| 2868 value, | 2857 value, |
| 2869 scratch0(), | 2858 scratch0(), |
| 2870 GetRAState(), | 2859 GetRAState(), |
| 2871 kSaveFPRegs, | 2860 kSaveFPRegs, |
| 2872 EMIT_REMEMBERED_SET, | 2861 EMIT_REMEMBERED_SET, |
| 2873 check_needed); | 2862 check_needed); |
| 2874 } | 2863 } |
| 2875 | 2864 |
| (...skipping 742 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3618 } | 3607 } |
| 3619 | 3608 |
| 3620 | 3609 |
| 3621 void LCodeGen::EmitIntegerMathAbs(LMathAbs* instr) { | 3610 void LCodeGen::EmitIntegerMathAbs(LMathAbs* instr) { |
| 3622 Register input = ToRegister(instr->value()); | 3611 Register input = ToRegister(instr->value()); |
| 3623 Register result = ToRegister(instr->result()); | 3612 Register result = ToRegister(instr->result()); |
| 3624 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); | 3613 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); |
| 3625 Label done; | 3614 Label done; |
| 3626 __ Branch(USE_DELAY_SLOT, &done, ge, input, Operand(zero_reg)); | 3615 __ Branch(USE_DELAY_SLOT, &done, ge, input, Operand(zero_reg)); |
| 3627 __ mov(result, input); | 3616 __ mov(result, input); |
| 3617 __ subu(result, zero_reg, input); |
| 3628 // Overflow if result is still negative, i.e. 0x80000000. | 3618 // Overflow if result is still negative, i.e. 0x80000000. |
| 3629 DeoptimizeIf(lt, instr->environment(), result, Operand(zero_reg)); | 3619 DeoptimizeIf(lt, instr->environment(), result, Operand(zero_reg)); |
| 3630 __ bind(&done); | 3620 __ bind(&done); |
| 3631 } | 3621 } |
| 3632 | 3622 |
| 3633 | 3623 |
| 3634 void LCodeGen::DoMathAbs(LMathAbs* instr) { | 3624 void LCodeGen::DoMathAbs(LMathAbs* instr) { |
| 3635 // Class for deferred case. | 3625 // Class for deferred case. |
| 3636 class DeferredMathAbsTaggedHeapNumber: public LDeferredCode { | 3626 class DeferredMathAbsTaggedHeapNumber: public LDeferredCode { |
| 3637 public: | 3627 public: |
| (...skipping 399 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4037 CALL_AS_FUNCTION, | 4027 CALL_AS_FUNCTION, |
| 4038 A1_UNINITIALIZED); | 4028 A1_UNINITIALIZED); |
| 4039 } | 4029 } |
| 4040 | 4030 |
| 4041 | 4031 |
| 4042 void LCodeGen::DoCallNew(LCallNew* instr) { | 4032 void LCodeGen::DoCallNew(LCallNew* instr) { |
| 4043 ASSERT(ToRegister(instr->constructor()).is(a1)); | 4033 ASSERT(ToRegister(instr->constructor()).is(a1)); |
| 4044 ASSERT(ToRegister(instr->result()).is(v0)); | 4034 ASSERT(ToRegister(instr->result()).is(v0)); |
| 4045 | 4035 |
| 4046 __ li(a0, Operand(instr->arity())); | 4036 __ li(a0, Operand(instr->arity())); |
| 4047 if (FLAG_optimize_constructed_arrays) { | 4037 // No cell in a2 for construct type feedback in optimized code |
| 4048 // No cell in a2 for construct type feedback in optimized code | 4038 Handle<Object> undefined_value(isolate()->factory()->undefined_value()); |
| 4049 Handle<Object> undefined_value(isolate()->heap()->undefined_value(), | 4039 __ li(a2, Operand(undefined_value)); |
| 4050 isolate()); | |
| 4051 __ li(a2, Operand(undefined_value)); | |
| 4052 } | |
| 4053 CallConstructStub stub(NO_CALL_FUNCTION_FLAGS); | 4040 CallConstructStub stub(NO_CALL_FUNCTION_FLAGS); |
| 4054 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); | 4041 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); |
| 4055 } | 4042 } |
| 4056 | 4043 |
| 4057 | 4044 |
| 4058 void LCodeGen::DoCallNewArray(LCallNewArray* instr) { | 4045 void LCodeGen::DoCallNewArray(LCallNewArray* instr) { |
| 4059 ASSERT(ToRegister(instr->constructor()).is(a1)); | 4046 ASSERT(ToRegister(instr->constructor()).is(a1)); |
| 4060 ASSERT(ToRegister(instr->result()).is(v0)); | 4047 ASSERT(ToRegister(instr->result()).is(v0)); |
| 4061 ASSERT(FLAG_optimize_constructed_arrays); | |
| 4062 | 4048 |
| 4063 __ li(a0, Operand(instr->arity())); | 4049 __ li(a0, Operand(instr->arity())); |
| 4064 __ li(a2, Operand(instr->hydrogen()->property_cell())); | 4050 __ li(a2, Operand(instr->hydrogen()->property_cell())); |
| 4065 ElementsKind kind = instr->hydrogen()->elements_kind(); | 4051 ElementsKind kind = instr->hydrogen()->elements_kind(); |
| 4066 bool disable_allocation_sites = | 4052 bool disable_allocation_sites = |
| 4067 (AllocationSiteInfo::GetMode(kind) == TRACK_ALLOCATION_SITE); | 4053 (AllocationSiteInfo::GetMode(kind) == TRACK_ALLOCATION_SITE); |
| 4068 | 4054 |
| 4069 if (instr->arity() == 0) { | 4055 if (instr->arity() == 0) { |
| 4070 ArrayNoArgumentConstructorStub stub(kind, disable_allocation_sites); | 4056 ArrayNoArgumentConstructorStub stub(kind, disable_allocation_sites); |
| 4071 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); | 4057 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4146 GetRAState(), | 4132 GetRAState(), |
| 4147 kSaveFPRegs, | 4133 kSaveFPRegs, |
| 4148 OMIT_REMEMBERED_SET, | 4134 OMIT_REMEMBERED_SET, |
| 4149 OMIT_SMI_CHECK); | 4135 OMIT_SMI_CHECK); |
| 4150 } | 4136 } |
| 4151 } | 4137 } |
| 4152 | 4138 |
| 4153 // Do the store. | 4139 // Do the store. |
| 4154 Register value = ToRegister(instr->value()); | 4140 Register value = ToRegister(instr->value()); |
| 4155 ASSERT(!object.is(value)); | 4141 ASSERT(!object.is(value)); |
| 4156 HType type = instr->hydrogen()->value()->type(); | |
| 4157 SmiCheck check_needed = | 4142 SmiCheck check_needed = |
| 4158 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; | 4143 instr->hydrogen()->value()->IsHeapObject() |
| 4144 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; |
| 4159 if (access.IsInobject()) { | 4145 if (access.IsInobject()) { |
| 4160 __ sw(value, FieldMemOperand(object, offset)); | 4146 __ sw(value, FieldMemOperand(object, offset)); |
| 4161 if (instr->hydrogen()->NeedsWriteBarrier()) { | 4147 if (instr->hydrogen()->NeedsWriteBarrier()) { |
| 4162 // Update the write barrier for the object for in-object properties. | 4148 // Update the write barrier for the object for in-object properties. |
| 4163 __ RecordWriteField(object, | 4149 __ RecordWriteField(object, |
| 4164 offset, | 4150 offset, |
| 4165 value, | 4151 value, |
| 4166 scratch, | 4152 scratch, |
| 4167 GetRAState(), | 4153 GetRAState(), |
| 4168 kSaveFPRegs, | 4154 kSaveFPRegs, |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4373 __ addu(scratch, elements, scratch); | 4359 __ addu(scratch, elements, scratch); |
| 4374 } else { | 4360 } else { |
| 4375 __ sll(scratch, key, kPointerSizeLog2); | 4361 __ sll(scratch, key, kPointerSizeLog2); |
| 4376 __ addu(scratch, elements, scratch); | 4362 __ addu(scratch, elements, scratch); |
| 4377 } | 4363 } |
| 4378 offset = FixedArray::OffsetOfElementAt(instr->additional_index()); | 4364 offset = FixedArray::OffsetOfElementAt(instr->additional_index()); |
| 4379 } | 4365 } |
| 4380 __ sw(value, FieldMemOperand(store_base, offset)); | 4366 __ sw(value, FieldMemOperand(store_base, offset)); |
| 4381 | 4367 |
| 4382 if (instr->hydrogen()->NeedsWriteBarrier()) { | 4368 if (instr->hydrogen()->NeedsWriteBarrier()) { |
| 4383 HType type = instr->hydrogen()->value()->type(); | |
| 4384 SmiCheck check_needed = | 4369 SmiCheck check_needed = |
| 4385 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; | 4370 instr->hydrogen()->value()->IsHeapObject() |
| 4371 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; |
| 4386 // Compute address of modified element and store it into key register. | 4372 // Compute address of modified element and store it into key register. |
| 4387 __ Addu(key, store_base, Operand(offset - kHeapObjectTag)); | 4373 __ Addu(key, store_base, Operand(offset - kHeapObjectTag)); |
| 4388 __ RecordWrite(elements, | 4374 __ RecordWrite(elements, |
| 4389 key, | 4375 key, |
| 4390 value, | 4376 value, |
| 4391 GetRAState(), | 4377 GetRAState(), |
| 4392 kSaveFPRegs, | 4378 kSaveFPRegs, |
| 4393 EMIT_REMEMBERED_SET, | 4379 EMIT_REMEMBERED_SET, |
| 4394 check_needed); | 4380 check_needed); |
| 4395 } | 4381 } |
| (...skipping 730 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5126 | 5112 |
| 5127 | 5113 |
| 5128 void LCodeGen::DoCheckSmi(LCheckSmi* instr) { | 5114 void LCodeGen::DoCheckSmi(LCheckSmi* instr) { |
| 5129 LOperand* input = instr->value(); | 5115 LOperand* input = instr->value(); |
| 5130 __ And(at, ToRegister(input), Operand(kSmiTagMask)); | 5116 __ And(at, ToRegister(input), Operand(kSmiTagMask)); |
| 5131 DeoptimizeIf(ne, instr->environment(), at, Operand(zero_reg)); | 5117 DeoptimizeIf(ne, instr->environment(), at, Operand(zero_reg)); |
| 5132 } | 5118 } |
| 5133 | 5119 |
| 5134 | 5120 |
| 5135 void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) { | 5121 void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) { |
| 5136 LOperand* input = instr->value(); | 5122 if (!instr->hydrogen()->value()->IsHeapObject()) { |
| 5137 __ And(at, ToRegister(input), Operand(kSmiTagMask)); | 5123 LOperand* input = instr->value(); |
| 5138 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg)); | 5124 __ And(at, ToRegister(input), Operand(kSmiTagMask)); |
| 5125 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg)); |
| 5126 } |
| 5139 } | 5127 } |
| 5140 | 5128 |
| 5141 | 5129 |
| 5142 void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { | 5130 void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { |
| 5143 Register input = ToRegister(instr->value()); | 5131 Register input = ToRegister(instr->value()); |
| 5144 Register scratch = scratch0(); | 5132 Register scratch = scratch0(); |
| 5145 | 5133 |
| 5146 __ GetObjectType(input, scratch, scratch); | 5134 __ GetObjectType(input, scratch, scratch); |
| 5147 | 5135 |
| 5148 if (instr->hydrogen()->is_interval_check()) { | 5136 if (instr->hydrogen()->is_interval_check()) { |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5286 if (!instr->hydrogen()->CanOmitPrototypeChecks()) { | 5274 if (!instr->hydrogen()->CanOmitPrototypeChecks()) { |
| 5287 for (int i = 0; i < prototypes->length(); i++) { | 5275 for (int i = 0; i < prototypes->length(); i++) { |
| 5288 __ LoadHeapObject(prototype_reg, prototypes->at(i)); | 5276 __ LoadHeapObject(prototype_reg, prototypes->at(i)); |
| 5289 __ lw(map_reg, FieldMemOperand(prototype_reg, HeapObject::kMapOffset)); | 5277 __ lw(map_reg, FieldMemOperand(prototype_reg, HeapObject::kMapOffset)); |
| 5290 DoCheckMapCommon(map_reg, maps->at(i), instr->environment()); | 5278 DoCheckMapCommon(map_reg, maps->at(i), instr->environment()); |
| 5291 } | 5279 } |
| 5292 } | 5280 } |
| 5293 } | 5281 } |
| 5294 | 5282 |
| 5295 | 5283 |
| 5284 void LCodeGen::DoAllocateObject(LAllocateObject* instr) { |
| 5285 class DeferredAllocateObject: public LDeferredCode { |
| 5286 public: |
| 5287 DeferredAllocateObject(LCodeGen* codegen, LAllocateObject* instr) |
| 5288 : LDeferredCode(codegen), instr_(instr) { } |
| 5289 virtual void Generate() { codegen()->DoDeferredAllocateObject(instr_); } |
| 5290 virtual LInstruction* instr() { return instr_; } |
| 5291 private: |
| 5292 LAllocateObject* instr_; |
| 5293 }; |
| 5294 |
| 5295 DeferredAllocateObject* deferred = |
| 5296 new(zone()) DeferredAllocateObject(this, instr); |
| 5297 |
| 5298 Register result = ToRegister(instr->result()); |
| 5299 Register scratch = ToRegister(instr->temp()); |
| 5300 Register scratch2 = ToRegister(instr->temp2()); |
| 5301 Handle<JSFunction> constructor = instr->hydrogen()->constructor(); |
| 5302 Handle<Map> initial_map = instr->hydrogen()->constructor_initial_map(); |
| 5303 int instance_size = initial_map->instance_size(); |
| 5304 ASSERT(initial_map->pre_allocated_property_fields() + |
| 5305 initial_map->unused_property_fields() - |
| 5306 initial_map->inobject_properties() == 0); |
| 5307 |
| 5308 __ Allocate(instance_size, result, scratch, scratch2, deferred->entry(), |
| 5309 TAG_OBJECT); |
| 5310 |
| 5311 __ bind(deferred->exit()); |
| 5312 if (FLAG_debug_code) { |
| 5313 Label is_in_new_space; |
| 5314 __ JumpIfInNewSpace(result, scratch, &is_in_new_space); |
| 5315 __ Abort("Allocated object is not in new-space"); |
| 5316 __ bind(&is_in_new_space); |
| 5317 } |
| 5318 |
| 5319 // Load the initial map. |
| 5320 Register map = scratch; |
| 5321 __ LoadHeapObject(map, constructor); |
| 5322 __ lw(map, FieldMemOperand(map, JSFunction::kPrototypeOrInitialMapOffset)); |
| 5323 |
| 5324 // Initialize map and fields of the newly allocated object. |
| 5325 ASSERT(initial_map->instance_type() == JS_OBJECT_TYPE); |
| 5326 __ sw(map, FieldMemOperand(result, JSObject::kMapOffset)); |
| 5327 __ LoadRoot(scratch, Heap::kEmptyFixedArrayRootIndex); |
| 5328 __ sw(scratch, FieldMemOperand(result, JSObject::kElementsOffset)); |
| 5329 __ sw(scratch, FieldMemOperand(result, JSObject::kPropertiesOffset)); |
| 5330 if (initial_map->inobject_properties() != 0) { |
| 5331 __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex); |
| 5332 for (int i = 0; i < initial_map->inobject_properties(); i++) { |
| 5333 int property_offset = JSObject::kHeaderSize + i * kPointerSize; |
| 5334 __ sw(scratch, FieldMemOperand(result, property_offset)); |
| 5335 } |
| 5336 } |
| 5337 } |
| 5338 |
| 5339 |
| 5340 void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) { |
| 5341 Register result = ToRegister(instr->result()); |
| 5342 Handle<Map> initial_map = instr->hydrogen()->constructor_initial_map(); |
| 5343 int instance_size = initial_map->instance_size(); |
| 5344 |
| 5345 // TODO(3095996): Get rid of this. For now, we need to make the |
| 5346 // result register contain a valid pointer because it is already |
| 5347 // contained in the register pointer map. |
| 5348 __ mov(result, zero_reg); |
| 5349 |
| 5350 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); |
| 5351 __ li(a0, Operand(Smi::FromInt(instance_size))); |
| 5352 __ push(a0); |
| 5353 CallRuntimeFromDeferred(Runtime::kAllocateInNewSpace, 1, instr); |
| 5354 __ StoreToSafepointRegisterSlot(v0, result); |
| 5355 } |
| 5356 |
| 5357 |
| 5296 void LCodeGen::DoAllocate(LAllocate* instr) { | 5358 void LCodeGen::DoAllocate(LAllocate* instr) { |
| 5297 class DeferredAllocate: public LDeferredCode { | 5359 class DeferredAllocate: public LDeferredCode { |
| 5298 public: | 5360 public: |
| 5299 DeferredAllocate(LCodeGen* codegen, LAllocate* instr) | 5361 DeferredAllocate(LCodeGen* codegen, LAllocate* instr) |
| 5300 : LDeferredCode(codegen), instr_(instr) { } | 5362 : LDeferredCode(codegen), instr_(instr) { } |
| 5301 virtual void Generate() { codegen()->DoDeferredAllocate(instr_); } | 5363 virtual void Generate() { codegen()->DoDeferredAllocate(instr_); } |
| 5302 virtual LInstruction* instr() { return instr_; } | 5364 virtual LInstruction* instr() { return instr_; } |
| 5303 private: | 5365 private: |
| 5304 LAllocate* instr_; | 5366 LAllocate* instr_; |
| 5305 }; | 5367 }; |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5453 void LCodeGen::DoTypeof(LTypeof* instr) { | 5515 void LCodeGen::DoTypeof(LTypeof* instr) { |
| 5454 ASSERT(ToRegister(instr->result()).is(v0)); | 5516 ASSERT(ToRegister(instr->result()).is(v0)); |
| 5455 Register input = ToRegister(instr->value()); | 5517 Register input = ToRegister(instr->value()); |
| 5456 __ push(input); | 5518 __ push(input); |
| 5457 CallRuntime(Runtime::kTypeof, 1, instr); | 5519 CallRuntime(Runtime::kTypeof, 1, instr); |
| 5458 } | 5520 } |
| 5459 | 5521 |
| 5460 | 5522 |
| 5461 void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { | 5523 void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { |
| 5462 Register input = ToRegister(instr->value()); | 5524 Register input = ToRegister(instr->value()); |
| 5463 int true_block = chunk_->LookupDestination(instr->true_block_id()); | |
| 5464 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
| 5465 Label* true_label = chunk_->GetAssemblyLabel(true_block); | |
| 5466 Label* false_label = chunk_->GetAssemblyLabel(false_block); | |
| 5467 | 5525 |
| 5468 Register cmp1 = no_reg; | 5526 Register cmp1 = no_reg; |
| 5469 Operand cmp2 = Operand(no_reg); | 5527 Operand cmp2 = Operand(no_reg); |
| 5470 | 5528 |
| 5471 Condition final_branch_condition = EmitTypeofIs(true_label, | 5529 Condition final_branch_condition = EmitTypeofIs(instr->TrueLabel(chunk_), |
| 5472 false_label, | 5530 instr->FalseLabel(chunk_), |
| 5473 input, | 5531 input, |
| 5474 instr->type_literal(), | 5532 instr->type_literal(), |
| 5475 cmp1, | 5533 cmp1, |
| 5476 cmp2); | 5534 cmp2); |
| 5477 | 5535 |
| 5478 ASSERT(cmp1.is_valid()); | 5536 ASSERT(cmp1.is_valid()); |
| 5479 ASSERT(!cmp2.is_reg() || cmp2.rm().is_valid()); | 5537 ASSERT(!cmp2.is_reg() || cmp2.rm().is_valid()); |
| 5480 | 5538 |
| 5481 if (final_branch_condition != kNoCondition) { | 5539 if (final_branch_condition != kNoCondition) { |
| 5482 EmitBranch(true_block, false_block, final_branch_condition, cmp1, cmp2); | 5540 EmitBranch(instr, final_branch_condition, cmp1, cmp2); |
| 5483 } | 5541 } |
| 5484 } | 5542 } |
| 5485 | 5543 |
| 5486 | 5544 |
| 5487 Condition LCodeGen::EmitTypeofIs(Label* true_label, | 5545 Condition LCodeGen::EmitTypeofIs(Label* true_label, |
| 5488 Label* false_label, | 5546 Label* false_label, |
| 5489 Register input, | 5547 Register input, |
| 5490 Handle<String> type_name, | 5548 Handle<String> type_name, |
| 5491 Register& cmp1, | 5549 Register& cmp1, |
| 5492 Operand& cmp2) { | 5550 Operand& cmp2) { |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5585 cmp2 = Operand(zero_reg); // Set to valid regs, to avoid caller assertion. | 5643 cmp2 = Operand(zero_reg); // Set to valid regs, to avoid caller assertion. |
| 5586 __ Branch(false_label); | 5644 __ Branch(false_label); |
| 5587 } | 5645 } |
| 5588 | 5646 |
| 5589 return final_branch_condition; | 5647 return final_branch_condition; |
| 5590 } | 5648 } |
| 5591 | 5649 |
| 5592 | 5650 |
| 5593 void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) { | 5651 void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) { |
| 5594 Register temp1 = ToRegister(instr->temp()); | 5652 Register temp1 = ToRegister(instr->temp()); |
| 5595 int true_block = chunk_->LookupDestination(instr->true_block_id()); | |
| 5596 int false_block = chunk_->LookupDestination(instr->false_block_id()); | |
| 5597 | 5653 |
| 5598 EmitIsConstructCall(temp1, scratch0()); | 5654 EmitIsConstructCall(temp1, scratch0()); |
| 5599 | 5655 |
| 5600 EmitBranch(true_block, false_block, eq, temp1, | 5656 EmitBranch(instr, eq, temp1, |
| 5601 Operand(Smi::FromInt(StackFrame::CONSTRUCT))); | 5657 Operand(Smi::FromInt(StackFrame::CONSTRUCT))); |
| 5602 } | 5658 } |
| 5603 | 5659 |
| 5604 | 5660 |
| 5605 void LCodeGen::EmitIsConstructCall(Register temp1, Register temp2) { | 5661 void LCodeGen::EmitIsConstructCall(Register temp1, Register temp2) { |
| 5606 ASSERT(!temp1.is(temp2)); | 5662 ASSERT(!temp1.is(temp2)); |
| 5607 // Get the frame pointer for the calling frame. | 5663 // Get the frame pointer for the calling frame. |
| 5608 __ lw(temp1, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); | 5664 __ lw(temp1, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); |
| 5609 | 5665 |
| 5610 // Skip the arguments adaptor frame if it exists. | 5666 // Skip the arguments adaptor frame if it exists. |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5741 // the deferred code. | 5797 // the deferred code. |
| 5742 } | 5798 } |
| 5743 } | 5799 } |
| 5744 | 5800 |
| 5745 | 5801 |
| 5746 void LCodeGen::DoOsrEntry(LOsrEntry* instr) { | 5802 void LCodeGen::DoOsrEntry(LOsrEntry* instr) { |
| 5747 // This is a pseudo-instruction that ensures that the environment here is | 5803 // This is a pseudo-instruction that ensures that the environment here is |
| 5748 // properly registered for deoptimization and records the assembler's PC | 5804 // properly registered for deoptimization and records the assembler's PC |
| 5749 // offset. | 5805 // offset. |
| 5750 LEnvironment* environment = instr->environment(); | 5806 LEnvironment* environment = instr->environment(); |
| 5751 environment->SetSpilledRegisters(instr->SpilledRegisterArray(), | |
| 5752 instr->SpilledDoubleRegisterArray()); | |
| 5753 | 5807 |
| 5754 // If the environment were already registered, we would have no way of | 5808 // If the environment were already registered, we would have no way of |
| 5755 // backpatching it with the spill slot operands. | 5809 // backpatching it with the spill slot operands. |
| 5756 ASSERT(!environment->HasBeenRegistered()); | 5810 ASSERT(!environment->HasBeenRegistered()); |
| 5757 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); | 5811 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); |
| 5758 ASSERT(osr_pc_offset_ == -1); | 5812 |
| 5759 osr_pc_offset_ = masm()->pc_offset(); | 5813 // Normally we record the first unknown OSR value as the entrypoint to the OSR |
| 5814 // code, but if there were none, record the entrypoint here. |
| 5815 if (osr_pc_offset_ == -1) osr_pc_offset_ = masm()->pc_offset(); |
| 5760 } | 5816 } |
| 5761 | 5817 |
| 5762 | 5818 |
| 5763 void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) { | 5819 void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) { |
| 5764 Register result = ToRegister(instr->result()); | 5820 Register result = ToRegister(instr->result()); |
| 5765 Register object = ToRegister(instr->object()); | 5821 Register object = ToRegister(instr->object()); |
| 5766 __ LoadRoot(at, Heap::kUndefinedValueRootIndex); | 5822 __ LoadRoot(at, Heap::kUndefinedValueRootIndex); |
| 5767 DeoptimizeIf(eq, instr->environment(), object, Operand(at)); | 5823 DeoptimizeIf(eq, instr->environment(), object, Operand(at)); |
| 5768 | 5824 |
| 5769 Register null_value = t1; | 5825 Register null_value = t1; |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5848 __ Subu(scratch, result, scratch); | 5904 __ Subu(scratch, result, scratch); |
| 5849 __ lw(result, FieldMemOperand(scratch, | 5905 __ lw(result, FieldMemOperand(scratch, |
| 5850 FixedArray::kHeaderSize - kPointerSize)); | 5906 FixedArray::kHeaderSize - kPointerSize)); |
| 5851 __ bind(&done); | 5907 __ bind(&done); |
| 5852 } | 5908 } |
| 5853 | 5909 |
| 5854 | 5910 |
| 5855 #undef __ | 5911 #undef __ |
| 5856 | 5912 |
| 5857 } } // namespace v8::internal | 5913 } } // namespace v8::internal |
| OLD | NEW |