From: titzer@chromium.org Date: Wed, 26 Jun 2013 08:43:27 +0000 (+0000) Subject: Change PC for OSR entries to point to something more sensible (i.e. the first Unknown... X-Git-Tag: upstream/4.7.83~13679 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=bfa9fe95dca19a535c397ecdbe929ab8ab3d4882;p=platform%2Fupstream%2Fv8.git Change PC for OSR entries to point to something more sensible (i.e. the first UnknownOsrValue), removing the need to record spilled OSR values and the need for duplicate deopt entries. Review URL: https://codereview.chromium.org/16381006 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15331 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc index 9ea572b..c85238f 100644 --- a/src/arm/lithium-arm.cc +++ b/src/arm/lithium-arm.cc @@ -41,24 +41,6 @@ namespace internal { LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE) #undef DEFINE_COMPILE -LOsrEntry::LOsrEntry() { - for (int i = 0; i < Register::NumAllocatableRegisters(); ++i) { - register_spills_[i] = NULL; - } - for (int i = 0; i < DoubleRegister::NumAllocatableRegisters(); ++i) { - double_register_spills_[i] = NULL; - } -} - - -void LOsrEntry::MarkSpilledRegister(int allocation_index, - LOperand* spill_operand) { - ASSERT(spill_operand->IsStackSlot()); - ASSERT(register_spills_[allocation_index] == NULL); - register_spills_[allocation_index] = spill_operand; -} - - #ifdef DEBUG void LInstruction::VerifyCall() { // Call instructions can use only fixed registers as temporaries and @@ -81,14 +63,6 @@ void LInstruction::VerifyCall() { #endif -void LOsrEntry::MarkSpilledDoubleRegister(int allocation_index, - LOperand* spill_operand) { - ASSERT(spill_operand->IsDoubleStackSlot()); - ASSERT(double_register_spills_[allocation_index] == NULL); - double_register_spills_[allocation_index] = spill_operand; -} - - void LInstruction::PrintTo(StringStream* stream) { stream->Add("%s ", this->Mnemonic()); diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h index d3695b9..ec5e731 100644 --- a/src/arm/lithium-arm.h +++ b/src/arm/lithium-arm.h @@ -2581,26 +2581,10 @@ class LDeleteProperty: public LTemplateInstruction<1, 2, 0> { class LOsrEntry: public LTemplateInstruction<0, 0, 0> { public: - LOsrEntry(); + LOsrEntry() {} virtual bool HasInterestingComment(LCodeGen* gen) const { return false; } DECLARE_CONCRETE_INSTRUCTION(OsrEntry, "osr-entry") - - LOperand** SpilledRegisterArray() { return register_spills_; } - LOperand** SpilledDoubleRegisterArray() { return double_register_spills_; } - - void MarkSpilledRegister(int allocation_index, LOperand* spill_operand); - void MarkSpilledDoubleRegister(int allocation_index, - LOperand* spill_operand); - - private: - // Arrays of spill slot operands for registers with an assigned spill - // slot, i.e., that must also be restored to the spill slot on OSR entry. - // NULL if the register has no assigned spill slot. Indexed by allocation - // index. - LOperand* register_spills_[Register::kMaxNumAllocatableRegisters]; - LOperand* double_register_spills_[ - DoubleRegister::kMaxNumAllocatableRegisters]; }; diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index 8133ff2..abf93ba 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -622,27 +622,6 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, for (int i = 0; i < translation_size; ++i) { LOperand* value = environment->values()->at(i); - // spilled_registers_ and spilled_double_registers_ are either - // both NULL or both set. - if (environment->spilled_registers() != NULL && value != NULL) { - if (value->IsRegister() && - environment->spilled_registers()[value->index()] != NULL) { - translation->MarkDuplicate(); - AddToTranslation(translation, - environment->spilled_registers()[value->index()], - environment->HasTaggedValueAt(i), - environment->HasUint32ValueAt(i)); - } else if ( - value->IsDoubleRegister() && - environment->spilled_double_registers()[value->index()] != NULL) { - translation->MarkDuplicate(); - AddToTranslation( - translation, - environment->spilled_double_registers()[value->index()], - false, - false); - } - } // TODO(mstarzinger): Introduce marker operands to indicate that this value // is not present and must be reconstructed from the deoptimizer. Currently @@ -652,12 +631,6 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, translation->BeginArgumentsObject(arguments_count); for (int i = 0; i < arguments_count; ++i) { LOperand* value = environment->values()->at(translation_size + i); - ASSERT(environment->spilled_registers() == NULL || - !value->IsRegister() || - environment->spilled_registers()[value->index()] == NULL); - ASSERT(environment->spilled_registers() == NULL || - !value->IsDoubleRegister() || - environment->spilled_double_registers()[value->index()] == NULL); AddToTranslation(translation, value, environment->HasTaggedValueAt(translation_size + i), @@ -1120,7 +1093,8 @@ void LCodeGen::DoCallStub(LCallStub* instr) { void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { - // Nothing to do. + // Record the address of the first unknown OSR value as the place to enter. + if (osr_pc_offset_ == -1) osr_pc_offset_ = masm()->pc_offset(); } @@ -5818,15 +5792,15 @@ void LCodeGen::DoOsrEntry(LOsrEntry* instr) { // properly registered for deoptimization and records the assembler's PC // offset. LEnvironment* environment = instr->environment(); - environment->SetSpilledRegisters(instr->SpilledRegisterArray(), - instr->SpilledDoubleRegisterArray()); // If the environment were already registered, we would have no way of // backpatching it with the spill slot operands. ASSERT(!environment->HasBeenRegistered()); RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); - ASSERT(osr_pc_offset_ == -1); - osr_pc_offset_ = masm()->pc_offset(); + + // Normally we record the first unknown OSR value as the entrypoint to the OSR + // code, but if there were none, record the entrypoint here. + if (osr_pc_offset_ == -1) osr_pc_offset_ = masm()->pc_offset(); } diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc index eec8697..0a933df 100644 --- a/src/deoptimizer.cc +++ b/src/deoptimizer.cc @@ -789,7 +789,6 @@ void Deoptimizer::DoComputeOutputFrames() { case Translation::DOUBLE_STACK_SLOT: case Translation::LITERAL: case Translation::ARGUMENTS_OBJECT: - case Translation::DUPLICATE: default: UNREACHABLE(); break; @@ -1725,14 +1724,8 @@ void Deoptimizer::DoTranslateObject(TranslationIterator* iterator, disasm::NameConverter converter; Address object_slot = deferred_objects_.last().slot_address(); - // Ignore commands marked as duplicate and act on the first non-duplicate. Translation::Opcode opcode = static_cast(iterator->Next()); - while (opcode == Translation::DUPLICATE) { - opcode = static_cast(iterator->Next()); - iterator->Skip(Translation::NumberOfOperandsFor(opcode)); - opcode = static_cast(iterator->Next()); - } switch (opcode) { case Translation::BEGIN: @@ -1743,7 +1736,6 @@ void Deoptimizer::DoTranslateObject(TranslationIterator* iterator, case Translation::SETTER_STUB_FRAME: case Translation::COMPILED_STUB_FRAME: case Translation::ARGUMENTS_OBJECT: - case Translation::DUPLICATE: UNREACHABLE(); return; @@ -1926,14 +1918,8 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, const intptr_t kPlaceholder = reinterpret_cast(Smi::FromInt(0)); bool is_native = value_type == TRANSLATED_VALUE_IS_NATIVE; - // Ignore commands marked as duplicate and act on the first non-duplicate. Translation::Opcode opcode = static_cast(iterator->Next()); - while (opcode == Translation::DUPLICATE) { - opcode = static_cast(iterator->Next()); - iterator->Skip(Translation::NumberOfOperandsFor(opcode)); - opcode = static_cast(iterator->Next()); - } switch (opcode) { case Translation::BEGIN: @@ -1943,7 +1929,6 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, case Translation::GETTER_STUB_FRAME: case Translation::SETTER_STUB_FRAME: case Translation::COMPILED_STUB_FRAME: - case Translation::DUPLICATE: UNREACHABLE(); return; @@ -2197,10 +2182,6 @@ bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator, Translation::Opcode opcode = static_cast(iterator->Next()); - bool duplicate = (opcode == Translation::DUPLICATE); - if (duplicate) { - opcode = static_cast(iterator->Next()); - } switch (opcode) { case Translation::BEGIN: @@ -2210,21 +2191,20 @@ bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator, case Translation::GETTER_STUB_FRAME: case Translation::SETTER_STUB_FRAME: case Translation::COMPILED_STUB_FRAME: - case Translation::DUPLICATE: UNREACHABLE(); // Malformed input. - return false; - - case Translation::REGISTER: { - int output_reg = iterator->Next(); - if (FLAG_trace_osr) { - PrintF(" %s <- 0x%08" V8PRIxPTR " ; [sp + %d]\n", - converter.NameOfCPURegister(output_reg), - input_value, - *input_offset); - } - output->SetRegister(output_reg, input_value); - break; - } + return false; + + case Translation::REGISTER: { + int output_reg = iterator->Next(); + if (FLAG_trace_osr) { + PrintF(" %s <- 0x%08" V8PRIxPTR " ; [sp + %d]\n", + converter.NameOfCPURegister(output_reg), + input_value, + *input_offset); + } + output->SetRegister(output_reg, input_value); + break; + } case Translation::INT32_REGISTER: { int32_t int32_value = 0; @@ -2369,7 +2349,7 @@ bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator, } } - if (!duplicate) *input_offset -= kPointerSize; + *input_offset -= kPointerSize; return true; } @@ -2823,15 +2803,18 @@ void Translation::StoreLiteral(int literal_id) { } -void Translation::MarkDuplicate() { - buffer_->Add(DUPLICATE, zone()); +void Translation::StoreArgumentsObject(bool args_known, + int args_index, + int args_length) { + buffer_->Add(ARGUMENTS_OBJECT, zone()); + buffer_->Add(args_known, zone()); + buffer_->Add(args_index, zone()); + buffer_->Add(args_length, zone()); } int Translation::NumberOfOperandsFor(Opcode opcode) { switch (opcode) { - case DUPLICATE: - return 0; case GETTER_STUB_FRAME: case SETTER_STUB_FRAME: case ARGUMENTS_OBJECT: @@ -2896,8 +2879,6 @@ const char* Translation::StringFor(Opcode opcode) { return "LITERAL"; case ARGUMENTS_OBJECT: return "ARGUMENTS_OBJECT"; - case DUPLICATE: - return "DUPLICATE"; } UNREACHABLE(); return ""; @@ -2949,7 +2930,6 @@ SlotRef SlotRef::ComputeSlotForNextArgument(TranslationIterator* iterator, case Translation::INT32_REGISTER: case Translation::UINT32_REGISTER: case Translation::DOUBLE_REGISTER: - case Translation::DUPLICATE: // We are at safepoint which corresponds to call. All registers are // saved by caller so there would be no live registers at this // point. Thus these translation commands should not be used. diff --git a/src/deoptimizer.h b/src/deoptimizer.h index 5ca635c..d28be23 100644 --- a/src/deoptimizer.h +++ b/src/deoptimizer.h @@ -713,11 +713,7 @@ class Translation BASE_EMBEDDED { INT32_STACK_SLOT, UINT32_STACK_SLOT, DOUBLE_STACK_SLOT, - LITERAL, - - // A prefix indicating that the next command is a duplicate of the one - // that follows it. - DUPLICATE + LITERAL }; Translation(TranslationBuffer* buffer, int frame_count, int jsframe_count, @@ -749,7 +745,7 @@ class Translation BASE_EMBEDDED { void StoreUint32StackSlot(int index); void StoreDoubleStackSlot(int index); void StoreLiteral(int literal_id); - void MarkDuplicate(); + void StoreArgumentsObject(bool args_known, int args_index, int args_length); Zone* zone() const { return zone_; } diff --git a/src/flag-definitions.h b/src/flag-definitions.h index 6ea131e..91186de 100644 --- a/src/flag-definitions.h +++ b/src/flag-definitions.h @@ -394,6 +394,7 @@ DEFINE_bool(trace_opt, false, "trace lazy optimization") DEFINE_bool(trace_opt_stats, false, "trace lazy optimization statistics") DEFINE_bool(opt, true, "use adaptive optimizations") DEFINE_bool(always_opt, false, "always try to optimize functions") +DEFINE_bool(always_osr, false, "always try to OSR functions") DEFINE_bool(prepare_always_opt, false, "prepare for turning on always opt") DEFINE_bool(trace_deopt, false, "trace optimize function deoptimization") DEFINE_bool(trace_stub_failures, false, diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index be1f7b6..c388fe7 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -657,27 +657,6 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, for (int i = 0; i < translation_size; ++i) { LOperand* value = environment->values()->at(i); - // spilled_registers_ and spilled_double_registers_ are either - // both NULL or both set. - if (environment->spilled_registers() != NULL && value != NULL) { - if (value->IsRegister() && - environment->spilled_registers()[value->index()] != NULL) { - translation->MarkDuplicate(); - AddToTranslation(translation, - environment->spilled_registers()[value->index()], - environment->HasTaggedValueAt(i), - environment->HasUint32ValueAt(i)); - } else if ( - value->IsDoubleRegister() && - environment->spilled_double_registers()[value->index()] != NULL) { - translation->MarkDuplicate(); - AddToTranslation( - translation, - environment->spilled_double_registers()[value->index()], - false, - false); - } - } // TODO(mstarzinger): Introduce marker operands to indicate that this value // is not present and must be reconstructed from the deoptimizer. Currently @@ -687,12 +666,6 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, translation->BeginArgumentsObject(arguments_count); for (int i = 0; i < arguments_count; ++i) { LOperand* value = environment->values()->at(translation_size + i); - ASSERT(environment->spilled_registers() == NULL || - !value->IsRegister() || - environment->spilled_registers()[value->index()] == NULL); - ASSERT(environment->spilled_registers() == NULL || - !value->IsDoubleRegister() || - environment->spilled_double_registers()[value->index()] == NULL); AddToTranslation(translation, value, environment->HasTaggedValueAt(translation_size + i), @@ -1189,7 +1162,8 @@ void LCodeGen::DoCallStub(LCallStub* instr) { void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { - // Nothing to do. + // Record the address of the first unknown OSR value as the place to enter. + if (osr_pc_offset_ == -1) osr_pc_offset_ = masm()->pc_offset(); } @@ -6445,15 +6419,15 @@ void LCodeGen::DoOsrEntry(LOsrEntry* instr) { // properly registered for deoptimization and records the assembler's PC // offset. LEnvironment* environment = instr->environment(); - environment->SetSpilledRegisters(instr->SpilledRegisterArray(), - instr->SpilledDoubleRegisterArray()); // If the environment were already registered, we would have no way of // backpatching it with the spill slot operands. ASSERT(!environment->HasBeenRegistered()); RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); - ASSERT(osr_pc_offset_ == -1); - osr_pc_offset_ = masm()->pc_offset(); + + // Normally we record the first unknown OSR value as the entrypoint to the OSR + // code, but if there were none, record the entrypoint here. + if (osr_pc_offset_ == -1) osr_pc_offset_ = masm()->pc_offset(); } diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc index f3071ce..0a786e5 100644 --- a/src/ia32/lithium-ia32.cc +++ b/src/ia32/lithium-ia32.cc @@ -43,31 +43,6 @@ namespace internal { LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE) #undef DEFINE_COMPILE -LOsrEntry::LOsrEntry() { - for (int i = 0; i < Register::NumAllocatableRegisters(); ++i) { - register_spills_[i] = NULL; - } - for (int i = 0; i < DoubleRegister::NumAllocatableRegisters(); ++i) { - double_register_spills_[i] = NULL; - } -} - - -void LOsrEntry::MarkSpilledRegister(int allocation_index, - LOperand* spill_operand) { - ASSERT(spill_operand->IsStackSlot()); - ASSERT(register_spills_[allocation_index] == NULL); - register_spills_[allocation_index] = spill_operand; -} - - -void LOsrEntry::MarkSpilledDoubleRegister(int allocation_index, - LOperand* spill_operand) { - ASSERT(spill_operand->IsDoubleStackSlot()); - ASSERT(double_register_spills_[allocation_index] == NULL); - double_register_spills_[allocation_index] = spill_operand; -} - #ifdef DEBUG void LInstruction::VerifyCall() { diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h index b04f3ee..2c71b63 100644 --- a/src/ia32/lithium-ia32.h +++ b/src/ia32/lithium-ia32.h @@ -2691,26 +2691,10 @@ class LDeleteProperty: public LTemplateInstruction<1, 3, 0> { class LOsrEntry: public LTemplateInstruction<0, 0, 0> { public: - LOsrEntry(); + LOsrEntry() {} virtual bool HasInterestingComment(LCodeGen* gen) const { return false; } DECLARE_CONCRETE_INSTRUCTION(OsrEntry, "osr-entry") - - LOperand** SpilledRegisterArray() { return register_spills_; } - LOperand** SpilledDoubleRegisterArray() { return double_register_spills_; } - - void MarkSpilledRegister(int allocation_index, LOperand* spill_operand); - void MarkSpilledDoubleRegister(int allocation_index, - LOperand* spill_operand); - - private: - // Arrays of spill slot operands for registers with an assigned spill - // slot, i.e., that must also be restored to the spill slot on OSR entry. - // NULL if the register has no assigned spill slot. Indexed by allocation - // index. - LOperand* register_spills_[Register::kMaxNumAllocatableRegisters]; - LOperand* double_register_spills_[ - DoubleRegister::kMaxNumAllocatableRegisters]; }; diff --git a/src/lithium-allocator.cc b/src/lithium-allocator.cc index 5e2474c..265d464 100644 --- a/src/lithium-allocator.cc +++ b/src/lithium-allocator.cc @@ -1093,7 +1093,6 @@ bool LAllocator::Allocate(LChunk* chunk) { AllocateDoubleRegisters(); if (!AllocationOk()) return false; PopulatePointerMaps(); - if (has_osr_entry_) ProcessOsrEntry(); ConnectRanges(); ResolveControlFlow(); return true; @@ -1464,37 +1463,6 @@ void LAllocator::PopulatePointerMaps() { } -void LAllocator::ProcessOsrEntry() { - const ZoneList* instrs = chunk_->instructions(); - - // Linear search for the OSR entry instruction in the chunk. - int index = -1; - while (++index < instrs->length() && - !instrs->at(index)->IsOsrEntry()) { - } - ASSERT(index < instrs->length()); - LOsrEntry* instruction = LOsrEntry::cast(instrs->at(index)); - - LifetimePosition position = LifetimePosition::FromInstructionIndex(index); - for (int i = 0; i < live_ranges()->length(); ++i) { - LiveRange* range = live_ranges()->at(i); - if (range != NULL) { - if (range->Covers(position) && - range->HasRegisterAssigned() && - range->TopLevel()->HasAllocatedSpillOperand()) { - int reg_index = range->assigned_register(); - LOperand* spill_operand = range->TopLevel()->GetSpillOperand(); - if (range->IsDouble()) { - instruction->MarkSpilledDoubleRegister(reg_index, spill_operand); - } else { - instruction->MarkSpilledRegister(reg_index, spill_operand); - } - } - } - } -} - - void LAllocator::AllocateGeneralRegisters() { LAllocatorPhase phase("L_Allocate general registers", this); num_registers_ = Register::NumAllocatableRegisters(); diff --git a/src/lithium-allocator.h b/src/lithium-allocator.h index afcf2da..ce9101d 100644 --- a/src/lithium-allocator.h +++ b/src/lithium-allocator.h @@ -474,7 +474,6 @@ class LAllocator BASE_EMBEDDED { void ConnectRanges(); void ResolveControlFlow(); void PopulatePointerMaps(); - void ProcessOsrEntry(); void AllocateRegisters(); bool CanEagerlyResolveControlFlow(HBasicBlock* block) const; inline bool SafePointsAreInOrder() const; diff --git a/src/lithium.h b/src/lithium.h index 200773a..1f31b90 100644 --- a/src/lithium.h +++ b/src/lithium.h @@ -533,8 +533,6 @@ class LEnvironment: public ZoneObject { values_(value_count, zone), is_tagged_(value_count, zone), is_uint32_(value_count, zone), - spilled_registers_(NULL), - spilled_double_registers_(NULL), outer_(outer), entry_(entry), zone_(zone) { } @@ -548,10 +546,6 @@ class LEnvironment: public ZoneObject { int translation_size() const { return translation_size_; } int parameter_count() const { return parameter_count_; } int pc_offset() const { return pc_offset_; } - LOperand** spilled_registers() const { return spilled_registers_; } - LOperand** spilled_double_registers() const { - return spilled_double_registers_; - } const ZoneList* values() const { return &values_; } LEnvironment* outer() const { return outer_; } HEnterInlined* entry() { return entry_; } @@ -591,12 +585,6 @@ class LEnvironment: public ZoneObject { return deoptimization_index_ != Safepoint::kNoDeoptimizationIndex; } - void SetSpilledRegisters(LOperand** registers, - LOperand** double_registers) { - spilled_registers_ = registers; - spilled_double_registers_ = double_registers; - } - void PrintTo(StringStream* stream); private: @@ -615,13 +603,6 @@ class LEnvironment: public ZoneObject { ZoneList values_; GrowableBitVector is_tagged_; GrowableBitVector is_uint32_; - - // Allocation index indexed arrays of spill slot operands for registers - // that are also in spill slots at an OSR entry. NULL for environments - // that do not correspond to an OSR entry. - LOperand** spilled_registers_; - LOperand** spilled_double_registers_; - LEnvironment* outer_; HEnterInlined* entry_; Zone* zone_; diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc index 83a6816..27a38ea 100644 --- a/src/mips/lithium-codegen-mips.cc +++ b/src/mips/lithium-codegen-mips.cc @@ -603,27 +603,6 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, for (int i = 0; i < translation_size; ++i) { LOperand* value = environment->values()->at(i); - // spilled_registers_ and spilled_double_registers_ are either - // both NULL or both set. - if (environment->spilled_registers() != NULL && value != NULL) { - if (value->IsRegister() && - environment->spilled_registers()[value->index()] != NULL) { - translation->MarkDuplicate(); - AddToTranslation(translation, - environment->spilled_registers()[value->index()], - environment->HasTaggedValueAt(i), - environment->HasUint32ValueAt(i)); - } else if ( - value->IsDoubleRegister() && - environment->spilled_double_registers()[value->index()] != NULL) { - translation->MarkDuplicate(); - AddToTranslation( - translation, - environment->spilled_double_registers()[value->index()], - false, - false); - } - } // TODO(mstarzinger): Introduce marker operands to indicate that this value // is not present and must be reconstructed from the deoptimizer. Currently @@ -633,12 +612,6 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, translation->BeginArgumentsObject(arguments_count); for (int i = 0; i < arguments_count; ++i) { LOperand* value = environment->values()->at(translation_size + i); - ASSERT(environment->spilled_registers() == NULL || - !value->IsRegister() || - environment->spilled_registers()[value->index()] == NULL); - ASSERT(environment->spilled_registers() == NULL || - !value->IsDoubleRegister() || - environment->spilled_double_registers()[value->index()] == NULL); AddToTranslation(translation, value, environment->HasTaggedValueAt(translation_size + i), @@ -1101,7 +1074,8 @@ void LCodeGen::DoCallStub(LCallStub* instr) { void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { - // Nothing to do. + // Record the address of the first unknown OSR value as the place to enter. + if (osr_pc_offset_ == -1) osr_pc_offset_ = masm()->pc_offset(); } @@ -5816,15 +5790,15 @@ void LCodeGen::DoOsrEntry(LOsrEntry* instr) { // properly registered for deoptimization and records the assembler's PC // offset. LEnvironment* environment = instr->environment(); - environment->SetSpilledRegisters(instr->SpilledRegisterArray(), - instr->SpilledDoubleRegisterArray()); // If the environment were already registered, we would have no way of // backpatching it with the spill slot operands. ASSERT(!environment->HasBeenRegistered()); RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); - ASSERT(osr_pc_offset_ == -1); - osr_pc_offset_ = masm()->pc_offset(); + + // Normally we record the first unknown OSR value as the entrypoint to the OSR + // code, but if there were none, record the entrypoint here. + if (osr_pc_offset_ == -1) osr_pc_offset_ = masm()->pc_offset(); } diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc index 324381f..ef48bd3 100644 --- a/src/mips/lithium-mips.cc +++ b/src/mips/lithium-mips.cc @@ -41,24 +41,6 @@ namespace internal { LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE) #undef DEFINE_COMPILE -LOsrEntry::LOsrEntry() { - for (int i = 0; i < Register::NumAllocatableRegisters(); ++i) { - register_spills_[i] = NULL; - } - for (int i = 0; i < DoubleRegister::NumAllocatableRegisters(); ++i) { - double_register_spills_[i] = NULL; - } -} - - -void LOsrEntry::MarkSpilledRegister(int allocation_index, - LOperand* spill_operand) { - ASSERT(spill_operand->IsStackSlot()); - ASSERT(register_spills_[allocation_index] == NULL); - register_spills_[allocation_index] = spill_operand; -} - - #ifdef DEBUG void LInstruction::VerifyCall() { // Call instructions can use only fixed registers as temporaries and @@ -81,14 +63,6 @@ void LInstruction::VerifyCall() { #endif -void LOsrEntry::MarkSpilledDoubleRegister(int allocation_index, - LOperand* spill_operand) { - ASSERT(spill_operand->IsDoubleStackSlot()); - ASSERT(double_register_spills_[allocation_index] == NULL); - double_register_spills_[allocation_index] = spill_operand; -} - - void LInstruction::PrintTo(StringStream* stream) { stream->Add("%s ", this->Mnemonic()); diff --git a/src/mips/lithium-mips.h b/src/mips/lithium-mips.h index 358eca9..0902fdc 100644 --- a/src/mips/lithium-mips.h +++ b/src/mips/lithium-mips.h @@ -2554,26 +2554,10 @@ class LDeleteProperty: public LTemplateInstruction<1, 2, 0> { class LOsrEntry: public LTemplateInstruction<0, 0, 0> { public: - LOsrEntry(); + LOsrEntry() {} virtual bool HasInterestingComment(LCodeGen* gen) const { return false; } DECLARE_CONCRETE_INSTRUCTION(OsrEntry, "osr-entry") - - LOperand** SpilledRegisterArray() { return register_spills_; } - LOperand** SpilledDoubleRegisterArray() { return double_register_spills_; } - - void MarkSpilledRegister(int allocation_index, LOperand* spill_operand); - void MarkSpilledDoubleRegister(int allocation_index, - LOperand* spill_operand); - - private: - // Arrays of spill slot operands for registers with an assigned spill - // slot, i.e., that must also be restored to the spill slot on OSR entry. - // NULL if the register has no assigned spill slot. Indexed by allocation - // index. - LOperand* register_spills_[Register::kMaxNumAllocatableRegisters]; - LOperand* double_register_spills_[ - DoubleRegister::kMaxNumAllocatableRegisters]; }; diff --git a/src/objects.cc b/src/objects.cc index 5265901..0dc26b4 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -10447,9 +10447,6 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) { break; } - case Translation::DUPLICATE: - break; - case Translation::REGISTER: { int reg_code = iterator.Next(); PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code)); diff --git a/src/runtime-profiler.cc b/src/runtime-profiler.cc index 9b7dd34..00f7de4 100644 --- a/src/runtime-profiler.cc +++ b/src/runtime-profiler.cc @@ -153,9 +153,6 @@ void RuntimeProfiler::Optimize(JSFunction* function, const char* reason) { void RuntimeProfiler::AttemptOnStackReplacement(JSFunction* function) { // See AlwaysFullCompiler (in compiler.cc) comment on why we need // Debug::has_break_points(). - ASSERT(function->IsMarkedForLazyRecompilation() || - function->IsMarkedForParallelRecompilation() || - function->IsOptimized()); if (!FLAG_use_osr || isolate_->DebuggerHasBreakPoints() || function->IsBuiltin()) { @@ -273,12 +270,21 @@ void RuntimeProfiler::OptimizeNow() { if (shared_code->kind() != Code::FUNCTION) continue; if (function->IsInRecompileQueue()) continue; - // Attempt OSR if we are still running unoptimized code even though the - // the function has long been marked or even already been optimized. - if (!frame->is_optimized() && + if (FLAG_always_osr && + shared_code->allow_osr_at_loop_nesting_level() == 0) { + // Testing mode: always try an OSR compile for every function. + for (int i = 0; i < Code::kMaxLoopNestingMarker; i++) { + // TODO(titzer): fix AttemptOnStackReplacement to avoid this dumb loop. + shared_code->set_allow_osr_at_loop_nesting_level(i); + AttemptOnStackReplacement(function); + } + // Fall through and do a normal optimized compile as well. + } else if (!frame->is_optimized() && (function->IsMarkedForLazyRecompilation() || function->IsMarkedForParallelRecompilation() || function->IsOptimized())) { + // Attempt OSR if we are still running unoptimized code even though the + // the function has long been marked or even already been optimized. int ticks = shared_code->profiler_ticks(); int allowance = kOSRCodeSizeAllowanceBase + ticks * kOSRCodeSizeAllowancePerTick; diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index 42d7558..f37b2e6 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc @@ -511,27 +511,6 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, for (int i = 0; i < translation_size; ++i) { LOperand* value = environment->values()->at(i); - // spilled_registers_ and spilled_double_registers_ are either - // both NULL or both set. - if (environment->spilled_registers() != NULL && value != NULL) { - if (value->IsRegister() && - environment->spilled_registers()[value->index()] != NULL) { - translation->MarkDuplicate(); - AddToTranslation(translation, - environment->spilled_registers()[value->index()], - environment->HasTaggedValueAt(i), - environment->HasUint32ValueAt(i)); - } else if ( - value->IsDoubleRegister() && - environment->spilled_double_registers()[value->index()] != NULL) { - translation->MarkDuplicate(); - AddToTranslation( - translation, - environment->spilled_double_registers()[value->index()], - false, - false); - } - } // TODO(mstarzinger): Introduce marker operands to indicate that this value // is not present and must be reconstructed from the deoptimizer. Currently @@ -541,12 +520,6 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, translation->BeginArgumentsObject(arguments_count); for (int i = 0; i < arguments_count; ++i) { LOperand* value = environment->values()->at(translation_size + i); - ASSERT(environment->spilled_registers() == NULL || - !value->IsRegister() || - environment->spilled_registers()[value->index()] == NULL); - ASSERT(environment->spilled_registers() == NULL || - !value->IsDoubleRegister() || - environment->spilled_double_registers()[value->index()] == NULL); AddToTranslation(translation, value, environment->HasTaggedValueAt(translation_size + i), @@ -1000,7 +973,8 @@ void LCodeGen::DoCallStub(LCallStub* instr) { void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { - // Nothing to do. + // Record the address of the first unknown OSR value as the place to enter. + if (osr_pc_offset_ == -1) osr_pc_offset_ = masm()->pc_offset(); } @@ -5559,15 +5533,15 @@ void LCodeGen::DoOsrEntry(LOsrEntry* instr) { // properly registered for deoptimization and records the assembler's PC // offset. LEnvironment* environment = instr->environment(); - environment->SetSpilledRegisters(instr->SpilledRegisterArray(), - instr->SpilledDoubleRegisterArray()); // If the environment were already registered, we would have no way of // backpatching it with the spill slot operands. ASSERT(!environment->HasBeenRegistered()); RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); - ASSERT(osr_pc_offset_ == -1); - osr_pc_offset_ = masm()->pc_offset(); + + // Normally we record the first unknown OSR value as the entrypoint to the OSR + // code, but if there were none, record the entrypoint here. + if (osr_pc_offset_ == -1) osr_pc_offset_ = masm()->pc_offset(); } diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc index 497c15b..afb1c48 100644 --- a/src/x64/lithium-x64.cc +++ b/src/x64/lithium-x64.cc @@ -43,31 +43,6 @@ namespace internal { LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE) #undef DEFINE_COMPILE -LOsrEntry::LOsrEntry() { - for (int i = 0; i < Register::NumAllocatableRegisters(); ++i) { - register_spills_[i] = NULL; - } - for (int i = 0; i < DoubleRegister::NumAllocatableRegisters(); ++i) { - double_register_spills_[i] = NULL; - } -} - - -void LOsrEntry::MarkSpilledRegister(int allocation_index, - LOperand* spill_operand) { - ASSERT(spill_operand->IsStackSlot()); - ASSERT(register_spills_[allocation_index] == NULL); - register_spills_[allocation_index] = spill_operand; -} - - -void LOsrEntry::MarkSpilledDoubleRegister(int allocation_index, - LOperand* spill_operand) { - ASSERT(spill_operand->IsDoubleStackSlot()); - ASSERT(double_register_spills_[allocation_index] == NULL); - double_register_spills_[allocation_index] = spill_operand; -} - #ifdef DEBUG void LInstruction::VerifyCall() { diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h index c1a4817..48d8b5c 100644 --- a/src/x64/lithium-x64.h +++ b/src/x64/lithium-x64.h @@ -2496,26 +2496,10 @@ class LDeleteProperty: public LTemplateInstruction<1, 2, 0> { class LOsrEntry: public LTemplateInstruction<0, 0, 0> { public: - LOsrEntry(); + LOsrEntry() {} virtual bool HasInterestingComment(LCodeGen* gen) const { return false; } DECLARE_CONCRETE_INSTRUCTION(OsrEntry, "osr-entry") - - LOperand** SpilledRegisterArray() { return register_spills_; } - LOperand** SpilledDoubleRegisterArray() { return double_register_spills_; } - - void MarkSpilledRegister(int allocation_index, LOperand* spill_operand); - void MarkSpilledDoubleRegister(int allocation_index, - LOperand* spill_operand); - - private: - // Arrays of spill slot operands for registers with an assigned spill - // slot, i.e., that must also be restored to the spill slot on OSR entry. - // NULL if the register has no assigned spill slot. Indexed by allocation - // index. - LOperand* register_spills_[Register::kMaxNumAllocatableRegisters]; - LOperand* double_register_spills_[ - DoubleRegister::kMaxNumAllocatableRegisters]; }; diff --git a/test/mjsunit/compiler/osr-big.js b/test/mjsunit/compiler/osr-big.js new file mode 100644 index 0000000..ed71744 --- /dev/null +++ b/test/mjsunit/compiler/osr-big.js @@ -0,0 +1,45 @@ +// Copyright 2013 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Flags: --use-osr + +function f(x) { + var sum = 0; + var outer = 1000000; + var a = 1, b = 2, c = 3, d = 4, e = 5; + while (outer > 0) { + a = a + 5; + b = b + 4; + c = c + 3; + d = d + 2; + e = e + 1; + outer--; + } + return a + b + c + d + e; +} + +assertEquals(15000015, f(5)); diff --git a/test/mjsunit/compiler/osr-nested.js b/test/mjsunit/compiler/osr-nested.js new file mode 100644 index 0000000..4bdb082 --- /dev/null +++ b/test/mjsunit/compiler/osr-nested.js @@ -0,0 +1,46 @@ +// Copyright 2013 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Flags: --use-osr + +function f() { + var sum = 0; + for (var i = 0; i < 10; i++) { + for (var j = 0; j < 100000; j++) { + var x = i + 2; + var y = x + 5; + var z = y + 3; + sum += z; + } + } + return sum; +} + + +assertEquals(14500000, f()); +assertEquals(14500000, f()); +assertEquals(14500000, f()); diff --git a/test/mjsunit/compiler/osr-one.js b/test/mjsunit/compiler/osr-one.js new file mode 100644 index 0000000..2c27192 --- /dev/null +++ b/test/mjsunit/compiler/osr-one.js @@ -0,0 +1,40 @@ +// Copyright 2013 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Flags: --use-osr + +function f(x) { + var sum = 0; + var count = 10000000; + while (count > 0) { + sum += x; + count--; + } + return sum; +} + +assertEquals(50000000, f(5)); diff --git a/test/mjsunit/compiler/regress-max-locals-for-osr.js b/test/mjsunit/compiler/osr-regress-max-locals.js similarity index 100% rename from test/mjsunit/compiler/regress-max-locals-for-osr.js rename to test/mjsunit/compiler/osr-regress-max-locals.js diff --git a/test/mjsunit/compiler/simple-osr.js b/test/mjsunit/compiler/osr-simple.js similarity index 100% rename from test/mjsunit/compiler/simple-osr.js rename to test/mjsunit/compiler/osr-simple.js diff --git a/test/mjsunit/compiler/osr-two.js b/test/mjsunit/compiler/osr-two.js new file mode 100644 index 0000000..8ac4c2c --- /dev/null +++ b/test/mjsunit/compiler/osr-two.js @@ -0,0 +1,44 @@ +// Copyright 2013 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Flags: --use-osr + +function f(x) { + var sum = 0; + var outer = 100; + while (outer > 0) { + var inner = 100000; + while (inner > 0) { + sum += x; + inner--; + } + outer--; + } + return sum; +} + +assertEquals(50000000, f(5)); diff --git a/test/mjsunit/compiler/osr-with-args.js b/test/mjsunit/compiler/osr-with-args.js new file mode 100644 index 0000000..44fa1cb --- /dev/null +++ b/test/mjsunit/compiler/osr-with-args.js @@ -0,0 +1,44 @@ +// Copyright 2013 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Flags: --use-osr + +function f() { + var sum = 0; + for (var i = 0; i < 1000000; i++) { + var t = arguments[0] + 2; + var x = arguments[1] + 2; + var y = t + x + 5; + var z = y + 3; + sum += z; + } + return sum; +} + +for (var i = 0; i < 4; i++) { + assertEquals(17000000, f(2, 3)); +}