diff --git a/deps/v8/src/arm/assembler-arm-inl.h b/deps/v8/src/arm/assembler-arm-inl.h index 3e19a45385..5ad7b5abae 100644 --- a/deps/v8/src/arm/assembler-arm-inl.h +++ b/deps/v8/src/arm/assembler-arm-inl.h @@ -32,7 +32,7 @@ // The original source code covered by the above license above has been modified // significantly by Google Inc. -// Copyright 2006-2008 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. #ifndef V8_ARM_ASSEMBLER_ARM_INL_H_ #define V8_ARM_ASSEMBLER_ARM_INL_H_ @@ -46,6 +46,13 @@ namespace v8 { namespace internal { +int DwVfpRegister::ToAllocationIndex(DwVfpRegister reg) { + ASSERT(!reg.is(kDoubleRegZero)); + ASSERT(!reg.is(kScratchDoubleReg)); + return reg.code(); +} + + void RelocInfo::apply(intptr_t delta) { if (RelocInfo::IsInternalReference(rmode_)) { // absolute code pointer inside code object moves with the code object. diff --git a/deps/v8/src/arm/assembler-arm.h b/deps/v8/src/arm/assembler-arm.h index 9a586936fe..eeadaca8a8 100644 --- a/deps/v8/src/arm/assembler-arm.h +++ b/deps/v8/src/arm/assembler-arm.h @@ -32,7 +32,7 @@ // The original source code covered by the above license above has been // modified significantly by Google Inc. -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // A light-weight ARM Assembler // Generates user mode instructions for the ARM architecture up to version 5 @@ -176,14 +176,11 @@ struct DwVfpRegister { static const int kNumAllocatableRegisters = kNumRegisters - kNumReservedRegisters; - static int ToAllocationIndex(DwVfpRegister reg) { - ASSERT(reg.code() != 0); - return reg.code() - 1; - } + inline static int ToAllocationIndex(DwVfpRegister reg); static DwVfpRegister FromAllocationIndex(int index) { ASSERT(index >= 0 && index < kNumAllocatableRegisters); - return from_code(index + 1); + return from_code(index); } static const char* AllocationIndexToString(int index) { @@ -307,6 +304,7 @@ const DwVfpRegister d15 = { 15 }; const DwVfpRegister kFirstCalleeSavedDoubleReg = d8; const DwVfpRegister kLastCalleeSavedDoubleReg = d15; const DwVfpRegister kDoubleRegZero = d14; +const DwVfpRegister kScratchDoubleReg = d15; // Coprocessor register diff --git a/deps/v8/src/arm/code-stubs-arm.cc b/deps/v8/src/arm/code-stubs-arm.cc index a59b6fd633..36450c945f 100644 --- a/deps/v8/src/arm/code-stubs-arm.cc +++ b/deps/v8/src/arm/code-stubs-arm.cc @@ -5392,13 +5392,12 @@ void StringHelper::GenerateHashGetHash(MacroAssembler* masm, // hash ^= hash >> 11; __ eor(hash, hash, Operand(hash, LSR, 11)); // hash += hash << 15; - __ add(hash, hash, Operand(hash, LSL, 15), SetCC); + __ add(hash, hash, Operand(hash, LSL, 15)); - uint32_t kHashShiftCutOffMask = (1 << (32 - String::kHashShift)) - 1; - __ and_(hash, hash, Operand(kHashShiftCutOffMask)); + __ and_(hash, hash, Operand(String::kHashBitMask), SetCC); // if (hash == 0) hash = 27; - __ mov(hash, Operand(27), LeaveCC, eq); + __ mov(hash, Operand(StringHasher::kZeroHash), LeaveCC, eq); } diff --git a/deps/v8/src/arm/deoptimizer-arm.cc b/deps/v8/src/arm/deoptimizer-arm.cc index 21e2d0fee1..d4f251f760 100644 --- a/deps/v8/src/arm/deoptimizer-arm.cc +++ b/deps/v8/src/arm/deoptimizer-arm.cc @@ -44,12 +44,6 @@ int Deoptimizer::patch_size() { } -void Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(Handle code) { - // Nothing to do. No new relocation information is written for lazy - // deoptimization on ARM. -} - - void Deoptimizer::DeoptimizeFunction(JSFunction* function) { HandleScope scope; AssertNoAllocation no_allocation; @@ -58,59 +52,38 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { // Get the optimized code. Code* code = function->code(); + Address code_start_address = code->instruction_start(); // Invalidate the relocation information, as it will become invalid by the // code patching below, and is not needed any more. code->InvalidateRelocation(); - // For each return after a safepoint insert an absolute call to the - // corresponding deoptimization entry. - unsigned last_pc_offset = 0; - SafepointTable table(function->code()); - for (unsigned i = 0; i < table.length(); i++) { - unsigned pc_offset = table.GetPcOffset(i); - SafepointEntry safepoint_entry = table.GetEntry(i); - int deoptimization_index = safepoint_entry.deoptimization_index(); - int gap_code_size = safepoint_entry.gap_code_size(); - // Check that we did not shoot past next safepoint. - CHECK(pc_offset >= last_pc_offset); + // For each LLazyBailout instruction insert a call to the corresponding + // deoptimization entry. + DeoptimizationInputData* deopt_data = + DeoptimizationInputData::cast(code->deoptimization_data()); #ifdef DEBUG - // Destroy the code which is not supposed to be run again. - int instructions = (pc_offset - last_pc_offset) / Assembler::kInstrSize; - CodePatcher destroyer(code->instruction_start() + last_pc_offset, - instructions); - for (int x = 0; x < instructions; x++) { - destroyer.masm()->bkpt(0); - } + Address prev_call_address = NULL; #endif - last_pc_offset = pc_offset; - if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) { - Address deoptimization_entry = Deoptimizer::GetDeoptimizationEntry( - deoptimization_index, Deoptimizer::LAZY); - last_pc_offset += gap_code_size; - int call_size_in_bytes = MacroAssembler::CallSize(deoptimization_entry, - RelocInfo::NONE); - int call_size_in_words = call_size_in_bytes / Assembler::kInstrSize; - ASSERT(call_size_in_bytes % Assembler::kInstrSize == 0); - ASSERT(call_size_in_bytes <= patch_size()); - CodePatcher patcher(code->instruction_start() + last_pc_offset, - call_size_in_words); - patcher.masm()->Call(deoptimization_entry, RelocInfo::NONE); - last_pc_offset += call_size_in_bytes; - } - } - + for (int i = 0; i < deopt_data->DeoptCount(); i++) { + if (deopt_data->Pc(i)->value() == -1) continue; + Address call_address = code_start_address + deopt_data->Pc(i)->value(); + Address deopt_entry = GetDeoptimizationEntry(i, LAZY); + int call_size_in_bytes = MacroAssembler::CallSize(deopt_entry, + RelocInfo::NONE); + int call_size_in_words = call_size_in_bytes / Assembler::kInstrSize; + ASSERT(call_size_in_bytes % Assembler::kInstrSize == 0); + ASSERT(call_size_in_bytes <= patch_size()); + CodePatcher patcher(call_address, call_size_in_words); + patcher.masm()->Call(deopt_entry, RelocInfo::NONE); + ASSERT(prev_call_address == NULL || + call_address >= prev_call_address + patch_size()); + ASSERT(call_address + patch_size() <= code->instruction_end()); #ifdef DEBUG - // Destroy the code which is not supposed to be run again. - int instructions = - (code->safepoint_table_offset() - last_pc_offset) / Assembler::kInstrSize; - CodePatcher destroyer(code->instruction_start() + last_pc_offset, - instructions); - for (int x = 0; x < instructions; x++) { - destroyer.masm()->bkpt(0); - } + prev_call_address = call_address; #endif + } // Add the deoptimizing code to the list. DeoptimizingCodeListNode* node = new DeoptimizingCodeListNode(code); @@ -125,11 +98,6 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { PrintF("[forced deoptimization: "); function->PrintName(); PrintF(" / %x]\n", reinterpret_cast(function)); -#ifdef DEBUG - if (FLAG_print_code) { - code->PrintLn(); - } -#endif } } diff --git a/deps/v8/src/arm/lithium-codegen-arm.cc b/deps/v8/src/arm/lithium-codegen-arm.cc index ee155e4de1..4a201ab987 100644 --- a/deps/v8/src/arm/lithium-codegen-arm.cc +++ b/deps/v8/src/arm/lithium-codegen-arm.cc @@ -40,37 +40,22 @@ class SafepointGenerator : public CallWrapper { public: SafepointGenerator(LCodeGen* codegen, LPointerMap* pointers, - int deoptimization_index) + Safepoint::DeoptMode mode) : codegen_(codegen), pointers_(pointers), - deoptimization_index_(deoptimization_index) { } + deopt_mode_(mode) { } virtual ~SafepointGenerator() { } - virtual void BeforeCall(int call_size) const { - ASSERT(call_size >= 0); - // Ensure that we have enough space after the previous safepoint position - // for the generated code there. - int call_end = codegen_->masm()->pc_offset() + call_size; - int prev_jump_end = - codegen_->LastSafepointEnd() + Deoptimizer::patch_size(); - if (call_end < prev_jump_end) { - int padding_size = prev_jump_end - call_end; - ASSERT_EQ(0, padding_size % Assembler::kInstrSize); - while (padding_size > 0) { - codegen_->masm()->nop(); - padding_size -= Assembler::kInstrSize; - } - } - } + virtual void BeforeCall(int call_size) const { } virtual void AfterCall() const { - codegen_->RecordSafepoint(pointers_, deoptimization_index_); + codegen_->RecordSafepoint(pointers_, deopt_mode_); } private: LCodeGen* codegen_; LPointerMap* pointers_; - int deoptimization_index_; + Safepoint::DeoptMode deopt_mode_; }; @@ -95,7 +80,6 @@ void LCodeGen::FinishCode(Handle code) { code->set_stack_slots(GetStackSlotCount()); code->set_safepoint_table_offset(safepoints_.GetCodeOffset()); PopulateDeoptimizationData(code); - Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(code); } @@ -192,7 +176,7 @@ bool LCodeGen::GeneratePrologue() { } else { __ CallRuntime(Runtime::kNewFunctionContext, 1); } - RecordSafepoint(Safepoint::kNoDeoptimizationIndex); + RecordSafepoint(Safepoint::kNoLazyDeopt); // Context is returned in both r0 and cp. It replaces the context // passed to us. It's saved in the stack and kept live in cp. __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); @@ -243,19 +227,11 @@ bool LCodeGen::GenerateBody() { instr->CompileToNative(this); } } + EnsureSpaceForLazyDeopt(); return !is_aborted(); } -LInstruction* LCodeGen::GetNextInstruction() { - if (current_instruction_ < instructions_->length() - 1) { - return instructions_->at(current_instruction_ + 1); - } else { - return NULL; - } -} - - bool LCodeGen::GenerateDeferredCode() { ASSERT(is_generating()); if (deferred_.length() > 0) { @@ -265,13 +241,6 @@ bool LCodeGen::GenerateDeferredCode() { code->Generate(); __ jmp(code->exit()); } - - // Pad code to ensure that the last piece of deferred code have - // room for lazy bailout. - while ((masm()->pc_offset() - LastSafepointEnd()) - < Deoptimizer::patch_size()) { - __ nop(); - } } // Force constant pool emission at the end of the deferred code to make @@ -551,7 +520,7 @@ void LCodeGen::CallCodeGeneric(Handle code, LPointerMap* pointers = instr->pointer_map(); RecordPosition(pointers->position()); __ Call(code, mode); - RegisterLazyDeoptimization(instr, safepoint_mode); + RecordSafepointWithLazyDeopt(instr, safepoint_mode); // Signal that we don't inline smi code before these stubs in the // optimizing code generator. @@ -571,7 +540,7 @@ void LCodeGen::CallRuntime(const Runtime::Function* function, RecordPosition(pointers->position()); __ CallRuntime(function, num_arguments); - RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT); + RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); } @@ -580,37 +549,12 @@ void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id, LInstruction* instr) { __ CallRuntimeSaveDoubles(id); RecordSafepointWithRegisters( - instr->pointer_map(), argc, Safepoint::kNoDeoptimizationIndex); + instr->pointer_map(), argc, Safepoint::kNoLazyDeopt); } -void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr, - SafepointMode safepoint_mode) { - // Create the environment to bailout to. If the call has side effects - // execution has to continue after the call otherwise execution can continue - // from a previous bailout point repeating the call. - LEnvironment* deoptimization_environment; - if (instr->HasDeoptimizationEnvironment()) { - deoptimization_environment = instr->deoptimization_environment(); - } else { - deoptimization_environment = instr->environment(); - } - - RegisterEnvironmentForDeoptimization(deoptimization_environment); - if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) { - RecordSafepoint(instr->pointer_map(), - deoptimization_environment->deoptimization_index()); - } else { - ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); - RecordSafepointWithRegisters( - instr->pointer_map(), - 0, - deoptimization_environment->deoptimization_index()); - } -} - - -void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment) { +void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment, + Safepoint::DeoptMode mode) { if (!environment->HasBeenRegistered()) { // Physical stack frame layout: // -x ............. -4 0 ..................................... y @@ -632,14 +576,17 @@ void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment) { Translation translation(&translations_, frame_count); WriteTranslation(environment, &translation); int deoptimization_index = deoptimizations_.length(); - environment->Register(deoptimization_index, translation.index()); + int pc_offset = masm()->pc_offset(); + environment->Register(deoptimization_index, + translation.index(), + (mode == Safepoint::kLazyDeopt) ? pc_offset : -1); deoptimizations_.Add(environment); } } void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) { - RegisterEnvironmentForDeoptimization(environment); + RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); ASSERT(environment->HasBeenRegistered()); int id = environment->deoptimization_index(); Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER); @@ -701,6 +648,7 @@ void LCodeGen::PopulateDeoptimizationData(Handle code) { data->SetTranslationIndex(i, Smi::FromInt(env->translation_index())); data->SetArgumentsStackHeight(i, Smi::FromInt(env->arguments_stack_height())); + data->SetPc(i, Smi::FromInt(env->pc_offset())); } code->set_deoptimization_data(*data); } @@ -732,16 +680,28 @@ void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() { } +void LCodeGen::RecordSafepointWithLazyDeopt( + LInstruction* instr, SafepointMode safepoint_mode) { + if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) { + RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt); + } else { + ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); + RecordSafepointWithRegisters( + instr->pointer_map(), 0, Safepoint::kLazyDeopt); + } +} + + void LCodeGen::RecordSafepoint( LPointerMap* pointers, Safepoint::Kind kind, int arguments, - int deoptimization_index) { + Safepoint::DeoptMode deopt_mode) { ASSERT(expected_safepoint_kind_ == kind); const ZoneList* operands = pointers->operands(); Safepoint safepoint = safepoints_.DefineSafepoint(masm(), - kind, arguments, deoptimization_index); + kind, arguments, deopt_mode); for (int i = 0; i < operands->length(); i++) { LOperand* pointer = operands->at(i); if (pointer->IsStackSlot()) { @@ -758,31 +718,31 @@ void LCodeGen::RecordSafepoint( void LCodeGen::RecordSafepoint(LPointerMap* pointers, - int deoptimization_index) { - RecordSafepoint(pointers, Safepoint::kSimple, 0, deoptimization_index); + Safepoint::DeoptMode deopt_mode) { + RecordSafepoint(pointers, Safepoint::kSimple, 0, deopt_mode); } -void LCodeGen::RecordSafepoint(int deoptimization_index) { +void LCodeGen::RecordSafepoint(Safepoint::DeoptMode deopt_mode) { LPointerMap empty_pointers(RelocInfo::kNoPosition); - RecordSafepoint(&empty_pointers, deoptimization_index); + RecordSafepoint(&empty_pointers, deopt_mode); } void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers, int arguments, - int deoptimization_index) { - RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, - deoptimization_index); + Safepoint::DeoptMode deopt_mode) { + RecordSafepoint( + pointers, Safepoint::kWithRegisters, arguments, deopt_mode); } void LCodeGen::RecordSafepointWithRegistersAndDoubles( LPointerMap* pointers, int arguments, - int deoptimization_index) { - RecordSafepoint(pointers, Safepoint::kWithRegistersAndDoubles, arguments, - deoptimization_index); + Safepoint::DeoptMode deopt_mode) { + RecordSafepoint( + pointers, Safepoint::kWithRegistersAndDoubles, arguments, deopt_mode); } @@ -817,12 +777,6 @@ void LCodeGen::DoGap(LGap* gap) { LParallelMove* move = gap->GetParallelMove(inner_pos); if (move != NULL) DoParallelMove(move); } - - LInstruction* next = GetNextInstruction(); - if (next != NULL && next->IsLazyBailout()) { - int pc = masm()->pc_offset(); - safepoints_.SetPcAfterGap(pc); - } } @@ -1129,7 +1083,7 @@ void LCodeGen::DoDeferredBinaryOpStub(LTemplateInstruction<1, 2, T>* instr, __ CallStub(&stub); RecordSafepointWithRegistersAndDoubles(instr->pointer_map(), 0, - Safepoint::kNoDeoptimizationIndex); + Safepoint::kNoLazyDeopt); // Overwrite the stored value of r0 with the result of the stub. __ StoreToSafepointRegistersAndDoublesSlot(r0, r0); } @@ -2014,7 +1968,7 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { LInstanceOfKnownGlobal* instr) : LDeferredCode(codegen), instr_(instr) { } virtual void Generate() { - codegen()->DoDeferredLInstanceOfKnownGlobal(instr_, &map_check_); + codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_); } Label* map_check() { return &map_check_; } @@ -2082,8 +2036,8 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { } -void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, - Label* map_check) { +void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, + Label* map_check) { Register result = ToRegister(instr->result()); ASSERT(result.is(r0)); @@ -2115,6 +2069,9 @@ void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, RelocInfo::CODE_TARGET, instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); + ASSERT(instr->HasDeoptimizationEnvironment()); + LEnvironment* env = instr->deoptimization_environment(); + safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); // Put the result value into the result register slot and // restore all registers. __ StoreToSafepointRegisterSlot(result, result); @@ -2712,12 +2669,9 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) { __ bind(&invoke); ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); LPointerMap* pointers = instr->pointer_map(); - LEnvironment* env = instr->deoptimization_environment(); RecordPosition(pointers->position()); - RegisterEnvironmentForDeoptimization(env); - SafepointGenerator safepoint_generator(this, - pointers, - env->deoptimization_index()); + SafepointGenerator safepoint_generator( + this, pointers, Safepoint::kLazyDeopt); // The number of arguments is stored in receiver which is r0, as expected // by InvokeFunction. v8::internal::ParameterCount actual(receiver); @@ -2799,7 +2753,7 @@ void LCodeGen::CallKnownFunction(Handle function, __ Call(ip); // Setup deoptimization. - RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT); + RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); // Restore context. __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); @@ -3163,10 +3117,8 @@ void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) { ASSERT(instr->HasPointerMap()); ASSERT(instr->HasDeoptimizationEnvironment()); LPointerMap* pointers = instr->pointer_map(); - LEnvironment* env = instr->deoptimization_environment(); RecordPosition(pointers->position()); - RegisterEnvironmentForDeoptimization(env); - SafepointGenerator generator(this, pointers, env->deoptimization_index()); + SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); ParameterCount count(instr->arity()); __ InvokeFunction(r1, count, CALL_FUNCTION, generator, CALL_AS_METHOD); __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); @@ -4403,9 +4355,29 @@ void LCodeGen::EmitIsConstructCall(Register temp1, Register temp2) { } +void LCodeGen::EnsureSpaceForLazyDeopt() { + // Ensure that we have enough space after the previous lazy-bailout + // instruction for patching the code here. + int current_pc = masm()->pc_offset(); + int patch_size = Deoptimizer::patch_size(); + if (current_pc < last_lazy_deopt_pc_ + patch_size) { + int padding_size = last_lazy_deopt_pc_ + patch_size - current_pc; + ASSERT_EQ(0, padding_size % Assembler::kInstrSize); + while (padding_size > 0) { + __ nop(); + padding_size -= Assembler::kInstrSize; + } + } + last_lazy_deopt_pc_ = masm()->pc_offset(); +} + + void LCodeGen::DoLazyBailout(LLazyBailout* instr) { - // No code for lazy bailout instruction. Used to capture environment after a - // call for populating the safepoint data with deoptimization data. + EnsureSpaceForLazyDeopt(); + ASSERT(instr->HasEnvironment()); + LEnvironment* env = instr->environment(); + RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt); + safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); } @@ -4422,12 +4394,9 @@ void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) { __ Push(object, key, strict); ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); LPointerMap* pointers = instr->pointer_map(); - LEnvironment* env = instr->deoptimization_environment(); RecordPosition(pointers->position()); - RegisterEnvironmentForDeoptimization(env); - SafepointGenerator safepoint_generator(this, - pointers, - env->deoptimization_index()); + SafepointGenerator safepoint_generator( + this, pointers, Safepoint::kLazyDeopt); __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator); } @@ -4438,27 +4407,20 @@ void LCodeGen::DoIn(LIn* instr) { __ Push(key, obj); ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); LPointerMap* pointers = instr->pointer_map(); - LEnvironment* env = instr->deoptimization_environment(); RecordPosition(pointers->position()); - RegisterEnvironmentForDeoptimization(env); - SafepointGenerator safepoint_generator(this, - pointers, - env->deoptimization_index()); + SafepointGenerator safepoint_generator(this, pointers, Safepoint::kLazyDeopt); __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator); } void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) { - { - PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); - __ CallRuntimeSaveDoubles(Runtime::kStackGuard); - RegisterLazyDeoptimization( - instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); - } - - // The gap code includes the restoring of the safepoint registers. - int pc = masm()->pc_offset(); - safepoints_.SetPcAfterGap(pc); + PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); + __ CallRuntimeSaveDoubles(Runtime::kStackGuard); + RecordSafepointWithLazyDeopt( + instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); + ASSERT(instr->HasEnvironment()); + LEnvironment* env = instr->environment(); + safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); } @@ -4472,6 +4434,10 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) { LStackCheck* instr_; }; + ASSERT(instr->HasEnvironment()); + LEnvironment* env = instr->environment(); + // There is no LLazyBailout instruction for stack-checks. We have to + // prepare for lazy deoptimization explicitly here. if (instr->hydrogen()->is_function_entry()) { // Perform stack overflow check. Label done; @@ -4480,7 +4446,10 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) { __ b(hs, &done); StackCheckStub stub; CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); + EnsureSpaceForLazyDeopt(); __ bind(&done); + RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt); + safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); } else { ASSERT(instr->hydrogen()->is_backwards_branch()); // Perform stack overflow check if this goto needs it before jumping. @@ -4489,8 +4458,13 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) { __ LoadRoot(ip, Heap::kStackLimitRootIndex); __ cmp(sp, Operand(ip)); __ b(lo, deferred_stack_check->entry()); + EnsureSpaceForLazyDeopt(); __ bind(instr->done_label()); deferred_stack_check->SetExit(instr->done_label()); + RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt); + // Don't record a deoptimization index for the safepoint here. + // This will be done explicitly when emitting call and the safepoint in + // the deferred code. } } @@ -4506,7 +4480,7 @@ void LCodeGen::DoOsrEntry(LOsrEntry* instr) { // If the environment were already registered, we would have no way of // backpatching it with the spill slot operands. ASSERT(!environment->HasBeenRegistered()); - RegisterEnvironmentForDeoptimization(environment); + RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); ASSERT(osr_pc_offset_ == -1); osr_pc_offset_ = masm()->pc_offset(); } diff --git a/deps/v8/src/arm/lithium-codegen-arm.h b/deps/v8/src/arm/lithium-codegen-arm.h index ead8489034..0e34c9f854 100644 --- a/deps/v8/src/arm/lithium-codegen-arm.h +++ b/deps/v8/src/arm/lithium-codegen-arm.h @@ -58,6 +58,7 @@ class LCodeGen BASE_EMBEDDED { status_(UNUSED), deferred_(8), osr_pc_offset_(-1), + last_lazy_deopt_pc_(0), resolver_(this), expected_safepoint_kind_(Safepoint::kSimple) { PopulateDeoptimizationLiteralsWithInlinedFunctions(); @@ -111,8 +112,8 @@ class LCodeGen BASE_EMBEDDED { void DoDeferredStackCheck(LStackCheck* instr); void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr); void DoDeferredStringCharFromCode(LStringCharFromCode* instr); - void DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, - Label* map_check); + void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, + Label* map_check); // Parallel move support. void DoParallelMove(LParallelMove* move); @@ -148,7 +149,7 @@ class LCodeGen BASE_EMBEDDED { HGraph* graph() const { return chunk_->graph(); } Register scratch0() { return r9; } - DwVfpRegister double_scratch0() { return d15; } + DwVfpRegister double_scratch0() { return kScratchDoubleReg; } int GetNextEmittedBlock(int block); LInstruction* GetNextInstruction(); @@ -214,10 +215,11 @@ class LCodeGen BASE_EMBEDDED { void LoadHeapObject(Register result, Handle object); - void RegisterLazyDeoptimization(LInstruction* instr, - SafepointMode safepoint_mode); + void RecordSafepointWithLazyDeopt(LInstruction* instr, + SafepointMode safepoint_mode); - void RegisterEnvironmentForDeoptimization(LEnvironment* environment); + void RegisterEnvironmentForDeoptimization(LEnvironment* environment, + Safepoint::DeoptMode mode); void DeoptimizeIf(Condition cc, LEnvironment* environment); void AddToTranslation(Translation* translation, @@ -246,19 +248,16 @@ class LCodeGen BASE_EMBEDDED { void RecordSafepoint(LPointerMap* pointers, Safepoint::Kind kind, int arguments, - int deoptimization_index); - void RecordSafepoint(LPointerMap* pointers, int deoptimization_index); - void RecordSafepoint(int deoptimization_index); + Safepoint::DeoptMode mode); + void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode); + void RecordSafepoint(Safepoint::DeoptMode mode); void RecordSafepointWithRegisters(LPointerMap* pointers, int arguments, - int deoptimization_index); + Safepoint::DeoptMode mode); void RecordSafepointWithRegistersAndDoubles(LPointerMap* pointers, int arguments, - int deoptimization_index); + Safepoint::DeoptMode mode); void RecordPosition(int position); - int LastSafepointEnd() { - return static_cast(safepoints_.GetPcAfterGap()); - } static Condition TokenToCondition(Token::Value op, bool is_unsigned); void EmitGoto(int block); @@ -300,6 +299,8 @@ class LCodeGen BASE_EMBEDDED { Address address; }; + void EnsureSpaceForLazyDeopt(); + LChunk* const chunk_; MacroAssembler* const masm_; CompilationInfo* const info_; @@ -316,6 +317,7 @@ class LCodeGen BASE_EMBEDDED { TranslationBuffer translations_; ZoneList deferred_; int osr_pc_offset_; + int last_lazy_deopt_pc_; // Builder that keeps track of safepoints in the code. The table // itself is emitted at the end of the generated code. diff --git a/deps/v8/src/arm/lithium-gap-resolver-arm.cc b/deps/v8/src/arm/lithium-gap-resolver-arm.cc index 26f60fac11..1cfdc791cc 100644 --- a/deps/v8/src/arm/lithium-gap-resolver-arm.cc +++ b/deps/v8/src/arm/lithium-gap-resolver-arm.cc @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 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: @@ -34,7 +34,6 @@ namespace v8 { namespace internal { static const Register kSavedValueRegister = { 9 }; -static const DoubleRegister kSavedDoubleValueRegister = { 0 }; LGapResolver::LGapResolver(LCodeGen* owner) : cgen_(owner), moves_(32), root_index_(0), in_cycle_(false), @@ -172,9 +171,9 @@ void LGapResolver::BreakCycle(int index) { } else if (source->IsStackSlot()) { __ ldr(kSavedValueRegister, cgen_->ToMemOperand(source)); } else if (source->IsDoubleRegister()) { - __ vmov(kSavedDoubleValueRegister, cgen_->ToDoubleRegister(source)); + __ vmov(kScratchDoubleReg, cgen_->ToDoubleRegister(source)); } else if (source->IsDoubleStackSlot()) { - __ vldr(kSavedDoubleValueRegister, cgen_->ToMemOperand(source)); + __ vldr(kScratchDoubleReg, cgen_->ToMemOperand(source)); } else { UNREACHABLE(); } @@ -193,11 +192,9 @@ void LGapResolver::RestoreValue() { } else if (saved_destination_->IsStackSlot()) { __ str(kSavedValueRegister, cgen_->ToMemOperand(saved_destination_)); } else if (saved_destination_->IsDoubleRegister()) { - __ vmov(cgen_->ToDoubleRegister(saved_destination_), - kSavedDoubleValueRegister); + __ vmov(cgen_->ToDoubleRegister(saved_destination_), kScratchDoubleReg); } else if (saved_destination_->IsDoubleStackSlot()) { - __ vstr(kSavedDoubleValueRegister, - cgen_->ToMemOperand(saved_destination_)); + __ vstr(kScratchDoubleReg, cgen_->ToMemOperand(saved_destination_)); } else { UNREACHABLE(); } @@ -235,8 +232,8 @@ void LGapResolver::EmitMove(int index) { // ip is overwritten while saving the value to the destination. // Therefore we can't use ip. It is OK if the read from the source // destroys ip, since that happens before the value is read. - __ vldr(kSavedDoubleValueRegister.low(), source_operand); - __ vstr(kSavedDoubleValueRegister.low(), destination_operand); + __ vldr(kScratchDoubleReg.low(), source_operand); + __ vstr(kScratchDoubleReg.low(), destination_operand); } else { __ ldr(ip, source_operand); __ str(ip, destination_operand); @@ -286,8 +283,8 @@ void LGapResolver::EmitMove(int index) { __ ldr(kSavedValueRegister, source_high_operand); __ str(kSavedValueRegister, destination_high_operand); } else { - __ vldr(kSavedDoubleValueRegister, source_operand); - __ vstr(kSavedDoubleValueRegister, destination_operand); + __ vldr(kScratchDoubleReg, source_operand); + __ vstr(kScratchDoubleReg, destination_operand); } } } else { diff --git a/deps/v8/src/deoptimizer.cc b/deps/v8/src/deoptimizer.cc index 5feb73d739..0ada28b015 100644 --- a/deps/v8/src/deoptimizer.cc +++ b/deps/v8/src/deoptimizer.cc @@ -112,25 +112,11 @@ DeoptimizedFrameInfo* Deoptimizer::DebuggerInspectableFrame( // Get the function and code from the frame. JSFunction* function = JSFunction::cast(frame->function()); Code* code = frame->LookupCode(); - Address code_start_address = code->instruction_start(); // Locate the deoptimization point in the code. As we are at a call the // return address must be at a place in the code with deoptimization support. - int deoptimization_index = Safepoint::kNoDeoptimizationIndex; - // Scope this as the safe point constructor will disallow allocation. - { - SafepointTable table(code); - for (unsigned i = 0; i < table.length(); ++i) { - Address address = code_start_address + table.GetPcOffset(i); - if (address == frame->pc()) { - SafepointEntry safepoint_entry = table.GetEntry(i); - ASSERT(safepoint_entry.deoptimization_index() != - Safepoint::kNoDeoptimizationIndex); - deoptimization_index = safepoint_entry.deoptimization_index(); - break; - } - } - } + SafepointEntry safepoint_entry = code->GetSafepointEntry(frame->pc()); + int deoptimization_index = safepoint_entry.deoptimization_index(); ASSERT(deoptimization_index != Safepoint::kNoDeoptimizationIndex); // Always use the actual stack slots when calculating the fp to sp diff --git a/deps/v8/src/hydrogen-instructions.h b/deps/v8/src/hydrogen-instructions.h index 1bc28ba82d..0af5489bed 100644 --- a/deps/v8/src/hydrogen-instructions.h +++ b/deps/v8/src/hydrogen-instructions.h @@ -4058,6 +4058,7 @@ class HRegExpLiteral: public HMaterializedLiteral<1> { pattern_(pattern), flags_(flags) { SetOperandAt(0, context); + SetAllSideEffects(); } HValue* context() { return OperandAt(0); } diff --git a/deps/v8/src/ia32/code-stubs-ia32.cc b/deps/v8/src/ia32/code-stubs-ia32.cc index 2bf486d3a6..8a5bd50ece 100644 --- a/deps/v8/src/ia32/code-stubs-ia32.cc +++ b/deps/v8/src/ia32/code-stubs-ia32.cc @@ -5665,14 +5665,12 @@ void StringHelper::GenerateHashGetHash(MacroAssembler* masm, __ shl(scratch, 15); __ add(hash, Operand(scratch)); - uint32_t kHashShiftCutOffMask = (1 << (32 - String::kHashShift)) - 1; - __ and_(hash, kHashShiftCutOffMask); + __ and_(hash, String::kHashBitMask); // if (hash == 0) hash = 27; Label hash_not_zero; - __ test(hash, Operand(hash)); __ j(not_zero, &hash_not_zero, Label::kNear); - __ mov(hash, Immediate(27)); + __ mov(hash, Immediate(StringHasher::kZeroHash)); __ bind(&hash_not_zero); } diff --git a/deps/v8/src/ia32/deoptimizer-ia32.cc b/deps/v8/src/ia32/deoptimizer-ia32.cc index e23f3e9eff..080ad644dc 100644 --- a/deps/v8/src/ia32/deoptimizer-ia32.cc +++ b/deps/v8/src/ia32/deoptimizer-ia32.cc @@ -45,16 +45,6 @@ int Deoptimizer::patch_size() { } -static void ZapCodeRange(Address start, Address end) { -#ifdef DEBUG - ASSERT(start <= end); - int size = end - start; - CodePatcher destroyer(start, size); - while (size-- > 0) destroyer.masm()->int3(); -#endif -} - - void Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(Handle code) { Isolate* isolate = code->GetIsolate(); HandleScope scope(isolate); @@ -62,30 +52,23 @@ void Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(Handle code) { // Compute the size of relocation information needed for the code // patching in Deoptimizer::DeoptimizeFunction. int min_reloc_size = 0; - Address prev_reloc_address = code->instruction_start(); - Address code_start_address = code->instruction_start(); - SafepointTable table(*code); - for (unsigned i = 0; i < table.length(); ++i) { - Address curr_reloc_address = code_start_address + table.GetPcOffset(i); - ASSERT_GE(curr_reloc_address, prev_reloc_address); - SafepointEntry safepoint_entry = table.GetEntry(i); - int deoptimization_index = safepoint_entry.deoptimization_index(); - if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) { - // The gap code is needed to get to the state expected at the - // bailout and we need to skip the call opcode to get to the - // address that needs reloc. - curr_reloc_address += safepoint_entry.gap_code_size() + 1; - int pc_delta = curr_reloc_address - prev_reloc_address; - // We use RUNTIME_ENTRY reloc info which has a size of 2 bytes - // if encodable with small pc delta encoding and up to 6 bytes - // otherwise. - if (pc_delta <= RelocInfo::kMaxSmallPCDelta) { - min_reloc_size += 2; - } else { - min_reloc_size += 6; - } - prev_reloc_address = curr_reloc_address; + int prev_pc_offset = 0; + DeoptimizationInputData* deopt_data = + DeoptimizationInputData::cast(code->deoptimization_data()); + for (int i = 0; i < deopt_data->DeoptCount(); i++) { + int pc_offset = deopt_data->Pc(i)->value(); + if (pc_offset == -1) continue; + ASSERT_GE(pc_offset, prev_pc_offset); + int pc_delta = pc_offset - prev_pc_offset; + // We use RUNTIME_ENTRY reloc info which has a size of 2 bytes + // if encodable with small pc delta encoding and up to 6 bytes + // otherwise. + if (pc_delta <= RelocInfo::kMaxSmallPCDelta) { + min_reloc_size += 2; + } else { + min_reloc_size += 6; } + prev_pc_offset = pc_offset; } // If the relocation information is not big enough we create a new @@ -150,40 +133,40 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { Address reloc_end_address = reloc_info->address() + reloc_info->Size(); RelocInfoWriter reloc_info_writer(reloc_end_address, code_start_address); - // For each return after a safepoint insert a call to the corresponding - // deoptimization entry. Since the call is a relative encoding, write new + // For each LLazyBailout instruction insert a call to the corresponding + // deoptimization entry. + + // Since the call is a relative encoding, write new // reloc info. We do not need any of the existing reloc info because the // existing code will not be used again (we zap it in debug builds). - SafepointTable table(code); - Address prev_address = code_start_address; - for (unsigned i = 0; i < table.length(); ++i) { - Address curr_address = code_start_address + table.GetPcOffset(i); - ASSERT_GE(curr_address, prev_address); - ZapCodeRange(prev_address, curr_address); - - SafepointEntry safepoint_entry = table.GetEntry(i); - int deoptimization_index = safepoint_entry.deoptimization_index(); - if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) { - // The gap code is needed to get to the state expected at the bailout. - curr_address += safepoint_entry.gap_code_size(); - - CodePatcher patcher(curr_address, patch_size()); - Address deopt_entry = GetDeoptimizationEntry(deoptimization_index, LAZY); - patcher.masm()->call(deopt_entry, RelocInfo::NONE); - - // We use RUNTIME_ENTRY for deoptimization bailouts. - RelocInfo rinfo(curr_address + 1, // 1 after the call opcode. - RelocInfo::RUNTIME_ENTRY, - reinterpret_cast(deopt_entry)); - reloc_info_writer.Write(&rinfo); - ASSERT_GE(reloc_info_writer.pos(), - reloc_info->address() + ByteArray::kHeaderSize); - curr_address += patch_size(); - } - prev_address = curr_address; + // + // Emit call to lazy deoptimization at all lazy deopt points. + DeoptimizationInputData* deopt_data = + DeoptimizationInputData::cast(code->deoptimization_data()); +#ifdef DEBUG + Address prev_call_address = NULL; +#endif + for (int i = 0; i < deopt_data->DeoptCount(); i++) { + if (deopt_data->Pc(i)->value() == -1) continue; + // Patch lazy deoptimization entry. + Address call_address = code_start_address + deopt_data->Pc(i)->value(); + CodePatcher patcher(call_address, patch_size()); + Address deopt_entry = GetDeoptimizationEntry(i, LAZY); + patcher.masm()->call(deopt_entry, RelocInfo::NONE); + // We use RUNTIME_ENTRY for deoptimization bailouts. + RelocInfo rinfo(call_address + 1, // 1 after the call opcode. + RelocInfo::RUNTIME_ENTRY, + reinterpret_cast(deopt_entry)); + reloc_info_writer.Write(&rinfo); + ASSERT_GE(reloc_info_writer.pos(), + reloc_info->address() + ByteArray::kHeaderSize); + ASSERT(prev_call_address == NULL || + call_address >= prev_call_address + patch_size()); + ASSERT(call_address + patch_size() <= code->instruction_end()); +#ifdef DEBUG + prev_call_address = call_address; +#endif } - ZapCodeRange(prev_address, - code_start_address + code->safepoint_table_offset()); // Move the relocation info to the beginning of the byte array. int new_reloc_size = reloc_end_address - reloc_info_writer.pos(); @@ -212,11 +195,6 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { PrintF("[forced deoptimization: "); function->PrintName(); PrintF(" / %x]\n", reinterpret_cast(function)); -#ifdef DEBUG - if (FLAG_print_code) { - code->PrintLn(); - } -#endif } } diff --git a/deps/v8/src/ia32/lithium-codegen-ia32.cc b/deps/v8/src/ia32/lithium-codegen-ia32.cc index 71375c33a7..d5a4fe6610 100644 --- a/deps/v8/src/ia32/lithium-codegen-ia32.cc +++ b/deps/v8/src/ia32/lithium-codegen-ia32.cc @@ -44,22 +44,22 @@ class SafepointGenerator : public CallWrapper { public: SafepointGenerator(LCodeGen* codegen, LPointerMap* pointers, - int deoptimization_index) + Safepoint::DeoptMode mode) : codegen_(codegen), pointers_(pointers), - deoptimization_index_(deoptimization_index) {} + deopt_mode_(mode) {} virtual ~SafepointGenerator() { } virtual void BeforeCall(int call_size) const {} virtual void AfterCall() const { - codegen_->RecordSafepoint(pointers_, deoptimization_index_); + codegen_->RecordSafepoint(pointers_, deopt_mode_); } private: LCodeGen* codegen_; LPointerMap* pointers_; - int deoptimization_index_; + Safepoint::DeoptMode deopt_mode_; }; @@ -187,7 +187,7 @@ bool LCodeGen::GeneratePrologue() { } else { __ CallRuntime(Runtime::kNewFunctionContext, 1); } - RecordSafepoint(Safepoint::kNoDeoptimizationIndex); + RecordSafepoint(Safepoint::kNoLazyDeopt); // Context is returned in both eax and esi. It replaces the context // passed to us. It's saved in the stack and kept live in esi. __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); @@ -241,19 +241,11 @@ bool LCodeGen::GenerateBody() { instr->CompileToNative(this); } } + EnsureSpaceForLazyDeopt(); return !is_aborted(); } -LInstruction* LCodeGen::GetNextInstruction() { - if (current_instruction_ < instructions_->length() - 1) { - return instructions_->at(current_instruction_ + 1); - } else { - return NULL; - } -} - - bool LCodeGen::GenerateDeferredCode() { ASSERT(is_generating()); if (deferred_.length() > 0) { @@ -263,13 +255,6 @@ bool LCodeGen::GenerateDeferredCode() { code->Generate(); __ jmp(code->exit()); } - - // Pad code to ensure that the last piece of deferred code have - // room for lazy bailout. - while ((masm()->pc_offset() - LastSafepointEnd()) - < Deoptimizer::patch_size()) { - __ nop(); - } } // Deferred code is the last part of the instruction sequence. Mark @@ -442,10 +427,8 @@ void LCodeGen::CallCodeGeneric(Handle code, ASSERT(instr != NULL); LPointerMap* pointers = instr->pointer_map(); RecordPosition(pointers->position()); - __ call(code, mode); - - RegisterLazyDeoptimization(instr, safepoint_mode); + RecordSafepointWithLazyDeopt(instr, safepoint_mode); // Signal that we don't inline smi code before these stubs in the // optimizing code generator. @@ -473,7 +456,7 @@ void LCodeGen::CallRuntime(const Runtime::Function* fun, __ CallRuntime(fun, argc); - RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT); + RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); } @@ -493,37 +476,12 @@ void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id, __ CallRuntimeSaveDoubles(id); RecordSafepointWithRegisters( - instr->pointer_map(), argc, Safepoint::kNoDeoptimizationIndex); + instr->pointer_map(), argc, Safepoint::kNoLazyDeopt); } -void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr, - SafepointMode safepoint_mode) { - // Create the environment to bailout to. If the call has side effects - // execution has to continue after the call otherwise execution can continue - // from a previous bailout point repeating the call. - LEnvironment* deoptimization_environment; - if (instr->HasDeoptimizationEnvironment()) { - deoptimization_environment = instr->deoptimization_environment(); - } else { - deoptimization_environment = instr->environment(); - } - - RegisterEnvironmentForDeoptimization(deoptimization_environment); - if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) { - RecordSafepoint(instr->pointer_map(), - deoptimization_environment->deoptimization_index()); - } else { - ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); - RecordSafepointWithRegisters( - instr->pointer_map(), - 0, - deoptimization_environment->deoptimization_index()); - } -} - - -void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment) { +void LCodeGen::RegisterEnvironmentForDeoptimization( + LEnvironment* environment, Safepoint::DeoptMode mode) { if (!environment->HasBeenRegistered()) { // Physical stack frame layout: // -x ............. -4 0 ..................................... y @@ -545,14 +503,17 @@ void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment) { Translation translation(&translations_, frame_count); WriteTranslation(environment, &translation); int deoptimization_index = deoptimizations_.length(); - environment->Register(deoptimization_index, translation.index()); + int pc_offset = masm()->pc_offset(); + environment->Register(deoptimization_index, + translation.index(), + (mode == Safepoint::kLazyDeopt) ? pc_offset : -1); deoptimizations_.Add(environment); } } void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) { - RegisterEnvironmentForDeoptimization(environment); + RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); ASSERT(environment->HasBeenRegistered()); int id = environment->deoptimization_index(); Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER); @@ -632,6 +593,7 @@ void LCodeGen::PopulateDeoptimizationData(Handle code) { data->SetTranslationIndex(i, Smi::FromInt(env->translation_index())); data->SetArgumentsStackHeight(i, Smi::FromInt(env->arguments_stack_height())); + data->SetPc(i, Smi::FromInt(env->pc_offset())); } code->set_deoptimization_data(*data); } @@ -663,15 +625,27 @@ void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() { } +void LCodeGen::RecordSafepointWithLazyDeopt( + LInstruction* instr, SafepointMode safepoint_mode) { + if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) { + RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt); + } else { + ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); + RecordSafepointWithRegisters( + instr->pointer_map(), 0, Safepoint::kLazyDeopt); + } +} + + void LCodeGen::RecordSafepoint( LPointerMap* pointers, Safepoint::Kind kind, int arguments, - int deoptimization_index) { + Safepoint::DeoptMode deopt_mode) { ASSERT(kind == expected_safepoint_kind_); const ZoneList* operands = pointers->operands(); - Safepoint safepoint = safepoints_.DefineSafepoint(masm(), - kind, arguments, deoptimization_index); + Safepoint safepoint = + safepoints_.DefineSafepoint(masm(), kind, arguments, deopt_mode); for (int i = 0; i < operands->length(); i++) { LOperand* pointer = operands->at(i); if (pointer->IsStackSlot()) { @@ -684,22 +658,21 @@ void LCodeGen::RecordSafepoint( void LCodeGen::RecordSafepoint(LPointerMap* pointers, - int deoptimization_index) { - RecordSafepoint(pointers, Safepoint::kSimple, 0, deoptimization_index); + Safepoint::DeoptMode mode) { + RecordSafepoint(pointers, Safepoint::kSimple, 0, mode); } -void LCodeGen::RecordSafepoint(int deoptimization_index) { +void LCodeGen::RecordSafepoint(Safepoint::DeoptMode mode) { LPointerMap empty_pointers(RelocInfo::kNoPosition); - RecordSafepoint(&empty_pointers, deoptimization_index); + RecordSafepoint(&empty_pointers, mode); } void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers, int arguments, - int deoptimization_index) { - RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, - deoptimization_index); + Safepoint::DeoptMode mode) { + RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, mode); } @@ -734,12 +707,6 @@ void LCodeGen::DoGap(LGap* gap) { LParallelMove* move = gap->GetParallelMove(inner_pos); if (move != NULL) DoParallelMove(move); } - - LInstruction* next = GetNextInstruction(); - if (next != NULL && next->IsLazyBailout()) { - int pc = masm()->pc_offset(); - safepoints_.SetPcAfterGap(pc); - } } @@ -1849,7 +1816,7 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { LInstanceOfKnownGlobal* instr) : LDeferredCode(codegen), instr_(instr) { } virtual void Generate() { - codegen()->DoDeferredLInstanceOfKnownGlobal(instr_, &map_check_); + codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_); } Label* map_check() { return &map_check_; } @@ -1905,8 +1872,8 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { } -void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, - Label* map_check) { +void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, + Label* map_check) { PushSafepointRegistersScope scope(this); InstanceofStub::Flags flags = InstanceofStub::kNoFlags; @@ -1933,6 +1900,10 @@ void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, RelocInfo::CODE_TARGET, instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); + ASSERT(instr->HasDeoptimizationEnvironment()); + LEnvironment* env = instr->deoptimization_environment(); + safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); + // Put the result value into the eax slot and restore all registers. __ StoreToSafepointRegisterSlot(eax, eax); } @@ -2502,12 +2473,9 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) { __ bind(&invoke); ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); LPointerMap* pointers = instr->pointer_map(); - LEnvironment* env = instr->deoptimization_environment(); RecordPosition(pointers->position()); - RegisterEnvironmentForDeoptimization(env); - SafepointGenerator safepoint_generator(this, - pointers, - env->deoptimization_index()); + SafepointGenerator safepoint_generator( + this, pointers, Safepoint::kLazyDeopt); ParameterCount actual(eax); __ InvokeFunction(function, actual, CALL_FUNCTION, safepoint_generator, CALL_AS_METHOD); @@ -2590,8 +2558,7 @@ void LCodeGen::CallKnownFunction(Handle function, __ call(FieldOperand(edi, JSFunction::kCodeEntryOffset)); } - // Setup deoptimization. - RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT); + RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); } @@ -2966,10 +2933,9 @@ void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) { ASSERT(instr->HasPointerMap()); ASSERT(instr->HasDeoptimizationEnvironment()); LPointerMap* pointers = instr->pointer_map(); - LEnvironment* env = instr->deoptimization_environment(); RecordPosition(pointers->position()); - RegisterEnvironmentForDeoptimization(env); - SafepointGenerator generator(this, pointers, env->deoptimization_index()); + SafepointGenerator generator( + this, pointers, Safepoint::kLazyDeopt); ParameterCount count(instr->arity()); __ InvokeFunction(edi, count, CALL_FUNCTION, generator, CALL_AS_METHOD); } @@ -3463,7 +3429,7 @@ void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) { __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); RecordSafepointWithRegisters( - instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); + instr->pointer_map(), 0, Safepoint::kNoLazyDeopt); if (!reg.is(eax)) __ mov(reg, eax); // Done. Put the value in xmm0 into the value of the allocated heap @@ -3514,8 +3480,8 @@ void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) { // not have easy access to the local context. __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); - RecordSafepointWithRegisters(instr->pointer_map(), 0, - Safepoint::kNoDeoptimizationIndex); + RecordSafepointWithRegisters( + instr->pointer_map(), 0, Safepoint::kNoLazyDeopt); __ StoreToSafepointRegisterSlot(reg, eax); } @@ -4246,9 +4212,27 @@ void LCodeGen::EmitIsConstructCall(Register temp) { } +void LCodeGen::EnsureSpaceForLazyDeopt() { + // Ensure that we have enough space after the previous lazy-bailout + // instruction for patching the code here. + int current_pc = masm()->pc_offset(); + int patch_size = Deoptimizer::patch_size(); + if (current_pc < last_lazy_deopt_pc_ + patch_size) { + int padding_size = last_lazy_deopt_pc_ + patch_size - current_pc; + while (padding_size-- > 0) { + __ nop(); + } + } + last_lazy_deopt_pc_ = masm()->pc_offset(); +} + + void LCodeGen::DoLazyBailout(LLazyBailout* instr) { - // No code for lazy bailout instruction. Used to capture environment after a - // call for populating the safepoint data with deoptimization data. + EnsureSpaceForLazyDeopt(); + ASSERT(instr->HasEnvironment()); + LEnvironment* env = instr->environment(); + RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt); + safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); } @@ -4268,32 +4252,26 @@ void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) { } ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); LPointerMap* pointers = instr->pointer_map(); - LEnvironment* env = instr->deoptimization_environment(); RecordPosition(pointers->position()); - RegisterEnvironmentForDeoptimization(env); // Create safepoint generator that will also ensure enough space in the // reloc info for patching in deoptimization (since this is invoking a // builtin) - SafepointGenerator safepoint_generator(this, - pointers, - env->deoptimization_index()); + SafepointGenerator safepoint_generator( + this, pointers, Safepoint::kLazyDeopt); __ push(Immediate(Smi::FromInt(strict_mode_flag()))); __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator); } void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) { - { - PushSafepointRegistersScope scope(this); - __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); - __ CallRuntimeSaveDoubles(Runtime::kStackGuard); - RegisterLazyDeoptimization( - instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); - } - - // The gap code includes the restoring of the safepoint registers. - int pc = masm()->pc_offset(); - safepoints_.SetPcAfterGap(pc); + PushSafepointRegistersScope scope(this); + __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); + __ CallRuntimeSaveDoubles(Runtime::kStackGuard); + RecordSafepointWithLazyDeopt( + instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); + ASSERT(instr->HasEnvironment()); + LEnvironment* env = instr->environment(); + safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); } @@ -4307,6 +4285,10 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) { LStackCheck* instr_; }; + ASSERT(instr->HasEnvironment()); + LEnvironment* env = instr->environment(); + // There is no LLazyBailout instruction for stack-checks. We have to + // prepare for lazy deoptimization explicitly here. if (instr->hydrogen()->is_function_entry()) { // Perform stack overflow check. Label done; @@ -4319,7 +4301,10 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) { ASSERT(ToRegister(instr->context()).is(esi)); StackCheckStub stub; CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); + EnsureSpaceForLazyDeopt(); __ bind(&done); + RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt); + safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); } else { ASSERT(instr->hydrogen()->is_backwards_branch()); // Perform stack overflow check if this goto needs it before jumping. @@ -4329,8 +4314,13 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) { ExternalReference::address_of_stack_limit(isolate()); __ cmp(esp, Operand::StaticVariable(stack_limit)); __ j(below, deferred_stack_check->entry()); + EnsureSpaceForLazyDeopt(); __ bind(instr->done_label()); deferred_stack_check->SetExit(instr->done_label()); + RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt); + // Don't record a deoptimization index for the safepoint here. + // This will be done explicitly when emitting call and the safepoint in + // the deferred code. } } @@ -4346,7 +4336,7 @@ void LCodeGen::DoOsrEntry(LOsrEntry* instr) { // If the environment were already registered, we would have no way of // backpatching it with the spill slot operands. ASSERT(!environment->HasBeenRegistered()); - RegisterEnvironmentForDeoptimization(environment); + RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); ASSERT(osr_pc_offset_ == -1); osr_pc_offset_ = masm()->pc_offset(); } @@ -4367,15 +4357,9 @@ void LCodeGen::DoIn(LIn* instr) { } ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); LPointerMap* pointers = instr->pointer_map(); - LEnvironment* env = instr->deoptimization_environment(); RecordPosition(pointers->position()); - RegisterEnvironmentForDeoptimization(env); - // Create safepoint generator that will also ensure enough space in the - // reloc info for patching in deoptimization (since this is invoking a - // builtin) - SafepointGenerator safepoint_generator(this, - pointers, - env->deoptimization_index()); + SafepointGenerator safepoint_generator( + this, pointers, Safepoint::kLazyDeopt); __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator); } diff --git a/deps/v8/src/ia32/lithium-codegen-ia32.h b/deps/v8/src/ia32/lithium-codegen-ia32.h index 6156327420..d9554501dc 100644 --- a/deps/v8/src/ia32/lithium-codegen-ia32.h +++ b/deps/v8/src/ia32/lithium-codegen-ia32.h @@ -60,7 +60,7 @@ class LCodeGen BASE_EMBEDDED { status_(UNUSED), deferred_(8), osr_pc_offset_(-1), - deoptimization_reloc_size(), + last_lazy_deopt_pc_(0), resolver_(this), expected_safepoint_kind_(Safepoint::kSimple) { PopulateDeoptimizationLiteralsWithInlinedFunctions(); @@ -100,8 +100,8 @@ class LCodeGen BASE_EMBEDDED { void DoDeferredStackCheck(LStackCheck* instr); void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr); void DoDeferredStringCharFromCode(LStringCharFromCode* instr); - void DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, - Label* map_check); + void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, + Label* map_check); // Parallel move support. void DoParallelMove(LParallelMove* move); @@ -139,7 +139,6 @@ class LCodeGen BASE_EMBEDDED { HGraph* graph() const { return chunk_->graph(); } int GetNextEmittedBlock(int block); - LInstruction* GetNextInstruction(); void EmitClassOfTest(Label* if_true, Label* if_false, @@ -205,10 +204,11 @@ class LCodeGen BASE_EMBEDDED { void LoadHeapObject(Register result, Handle object); - void RegisterLazyDeoptimization(LInstruction* instr, - SafepointMode safepoint_mode); + void RecordSafepointWithLazyDeopt(LInstruction* instr, + SafepointMode safepoint_mode); - void RegisterEnvironmentForDeoptimization(LEnvironment* environment); + void RegisterEnvironmentForDeoptimization(LEnvironment* environment, + Safepoint::DeoptMode mode); void DeoptimizeIf(Condition cc, LEnvironment* environment); void AddToTranslation(Translation* translation, @@ -242,16 +242,13 @@ class LCodeGen BASE_EMBEDDED { void RecordSafepoint(LPointerMap* pointers, Safepoint::Kind kind, int arguments, - int deoptimization_index); - void RecordSafepoint(LPointerMap* pointers, int deoptimization_index); - void RecordSafepoint(int deoptimization_index); + Safepoint::DeoptMode mode); + void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode); + void RecordSafepoint(Safepoint::DeoptMode mode); void RecordSafepointWithRegisters(LPointerMap* pointers, int arguments, - int deoptimization_index); + Safepoint::DeoptMode mode); void RecordPosition(int position); - int LastSafepointEnd() { - return static_cast(safepoints_.GetPcAfterGap()); - } static Condition TokenToCondition(Token::Value op, bool is_unsigned); void EmitGoto(int block); @@ -284,6 +281,7 @@ class LCodeGen BASE_EMBEDDED { Register object, Handle type, Handle name); + void EnsureSpaceForLazyDeopt(); LChunk* const chunk_; MacroAssembler* const masm_; @@ -300,13 +298,7 @@ class LCodeGen BASE_EMBEDDED { TranslationBuffer translations_; ZoneList deferred_; int osr_pc_offset_; - - struct DeoptimizationRelocSize { - int min_size; - int last_pc_offset; - }; - - DeoptimizationRelocSize deoptimization_reloc_size; + int last_lazy_deopt_pc_; // Builder that keeps track of safepoints in the code. The table // itself is emitted at the end of the generated code. diff --git a/deps/v8/src/ia32/lithium-ia32.h b/deps/v8/src/ia32/lithium-ia32.h index 038049ca06..b0ab6b416e 100644 --- a/deps/v8/src/ia32/lithium-ia32.h +++ b/deps/v8/src/ia32/lithium-ia32.h @@ -368,17 +368,7 @@ class LGoto: public LTemplateInstruction<0, 0, 0> { class LLazyBailout: public LTemplateInstruction<0, 0, 0> { public: - LLazyBailout() : gap_instructions_size_(0) { } - DECLARE_CONCRETE_INSTRUCTION(LazyBailout, "lazy-bailout") - - void set_gap_instructions_size(int gap_instructions_size) { - gap_instructions_size_ = gap_instructions_size; - } - int gap_instructions_size() { return gap_instructions_size_; } - - private: - int gap_instructions_size_; }; diff --git a/deps/v8/src/lithium.h b/deps/v8/src/lithium.h index 20da21a63c..a933f72aef 100644 --- a/deps/v8/src/lithium.h +++ b/deps/v8/src/lithium.h @@ -442,6 +442,7 @@ class LEnvironment: public ZoneObject { translation_index_(-1), ast_id_(ast_id), parameter_count_(parameter_count), + pc_offset_(-1), values_(value_count), representations_(value_count), spilled_registers_(NULL), @@ -455,6 +456,7 @@ class LEnvironment: public ZoneObject { int translation_index() const { return translation_index_; } int ast_id() const { return ast_id_; } 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_; @@ -471,10 +473,13 @@ class LEnvironment: public ZoneObject { return representations_[index].IsTagged(); } - void Register(int deoptimization_index, int translation_index) { + void Register(int deoptimization_index, + int translation_index, + int pc_offset) { ASSERT(!HasBeenRegistered()); deoptimization_index_ = deoptimization_index; translation_index_ = translation_index; + pc_offset_ = pc_offset; } bool HasBeenRegistered() const { return deoptimization_index_ != Safepoint::kNoDeoptimizationIndex; @@ -495,6 +500,7 @@ class LEnvironment: public ZoneObject { int translation_index_; int ast_id_; int parameter_count_; + int pc_offset_; ZoneList values_; ZoneList representations_; diff --git a/deps/v8/src/mips/code-stubs-mips.cc b/deps/v8/src/mips/code-stubs-mips.cc index 6838e54478..c3c3874422 100644 --- a/deps/v8/src/mips/code-stubs-mips.cc +++ b/deps/v8/src/mips/code-stubs-mips.cc @@ -5607,7 +5607,7 @@ void StringHelper::GenerateHashAddCharacter(MacroAssembler* masm, void StringHelper::GenerateHashGetHash(MacroAssembler* masm, - Register hash) { + Register hash) { // hash += hash << 3; __ sll(at, hash, 3); __ addu(hash, hash, at); diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc index 42245d48b0..88ebbf4e9d 100644 --- a/deps/v8/src/objects.cc +++ b/deps/v8/src/objects.cc @@ -6995,11 +6995,14 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) { PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count); if (0 == deopt_count) return; - PrintF(out, "%6s %6s %6s %12s\n", "index", "ast id", "argc", + PrintF(out, "%6s %6s %6s %6s %12s\n", "index", "ast id", "argc", "pc", FLAG_print_code_verbose ? "commands" : ""); for (int i = 0; i < deopt_count; i++) { - PrintF(out, "%6d %6d %6d", - i, AstId(i)->value(), ArgumentsStackHeight(i)->value()); + PrintF(out, "%6d %6d %6d %6d", + i, + AstId(i)->value(), + ArgumentsStackHeight(i)->value(), + Pc(i)->value()); if (!FLAG_print_code_verbose) { PrintF(out, "\n"); @@ -10542,7 +10545,7 @@ class TwoCharHashTableKey : public HashTableKey { hash += hash << 3; hash ^= hash >> 11; hash += hash << 15; - if ((hash & String::kHashBitMask) == 0) hash = 27; + if ((hash & String::kHashBitMask) == 0) hash = String::kZeroHash; #ifdef DEBUG StringHasher hasher(2, seed); hasher.AddCharacter(c1); diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h index be35401d03..1245ed0c12 100644 --- a/deps/v8/src/objects.h +++ b/deps/v8/src/objects.h @@ -3535,7 +3535,8 @@ class DeoptimizationInputData: public FixedArray { static const int kAstIdOffset = 0; static const int kTranslationIndexOffset = 1; static const int kArgumentsStackHeightOffset = 2; - static const int kDeoptEntrySize = 3; + static const int kPcOffset = 3; + static const int kDeoptEntrySize = 4; // Simple element accessors. #define DEFINE_ELEMENT_ACCESSORS(name, type) \ @@ -3571,6 +3572,7 @@ class DeoptimizationInputData: public FixedArray { DEFINE_ENTRY_ACCESSORS(AstId, Smi) DEFINE_ENTRY_ACCESSORS(TranslationIndex, Smi) DEFINE_ENTRY_ACCESSORS(ArgumentsStackHeight, Smi) + DEFINE_ENTRY_ACCESSORS(Pc, Smi) #undef DEFINE_ENTRY_ACCESSORS @@ -5832,6 +5834,11 @@ class StringHasher { // value is represented decimal value. static uint32_t MakeArrayIndexHash(uint32_t value, int length); + // No string is allowed to have a hash of zero. That value is reserved + // for internal properties. If the hash calculation yields zero then we + // use 27 instead. + static const int kZeroHash = 27; + private: uint32_t array_index() { ASSERT(is_array_index()); diff --git a/deps/v8/src/safepoint-table.cc b/deps/v8/src/safepoint-table.cc index bcd0a1d63d..89ad8afabe 100644 --- a/deps/v8/src/safepoint-table.cc +++ b/deps/v8/src/safepoint-table.cc @@ -122,17 +122,20 @@ void Safepoint::DefinePointerRegister(Register reg) { Safepoint SafepointTableBuilder::DefineSafepoint( - Assembler* assembler, Safepoint::Kind kind, int arguments, - int deoptimization_index) { - ASSERT(deoptimization_index != -1); + Assembler* assembler, + Safepoint::Kind kind, + int arguments, + Safepoint::DeoptMode deopt_mode) { ASSERT(arguments >= 0); - DeoptimizationInfo pc_and_deoptimization_index; - pc_and_deoptimization_index.pc = assembler->pc_offset(); - pc_and_deoptimization_index.deoptimization_index = deoptimization_index; - pc_and_deoptimization_index.pc_after_gap = assembler->pc_offset(); - pc_and_deoptimization_index.arguments = arguments; - pc_and_deoptimization_index.has_doubles = (kind & Safepoint::kWithDoubles); - deoptimization_info_.Add(pc_and_deoptimization_index); + DeoptimizationInfo info; + info.pc = assembler->pc_offset(); + info.arguments = arguments; + info.has_doubles = (kind & Safepoint::kWithDoubles); + deoptimization_info_.Add(info); + deopt_index_list_.Add(Safepoint::kNoDeoptimizationIndex); + if (deopt_mode == Safepoint::kNoLazyDeopt) { + last_lazy_safepoint_ = deopt_index_list_.length(); + } indexes_.Add(new ZoneList(8)); registers_.Add((kind & Safepoint::kWithRegisters) ? new ZoneList(4) @@ -141,6 +144,12 @@ Safepoint SafepointTableBuilder::DefineSafepoint( } +void SafepointTableBuilder::RecordLazyDeoptimizationIndex(int index) { + while (last_lazy_safepoint_ < deopt_index_list_.length()) { + deopt_index_list_[last_lazy_safepoint_++] = index; + } +} + unsigned SafepointTableBuilder::GetCodeOffset() const { ASSERT(emitted_); return offset_; @@ -173,11 +182,11 @@ void SafepointTableBuilder::Emit(Assembler* assembler, int bits_per_entry) { assembler->dd(length); assembler->dd(bytes_per_entry); - // Emit sorted table of pc offsets together with deoptimization indexes and - // pc after gap information. + // Emit sorted table of pc offsets together with deoptimization indexes. for (int i = 0; i < length; i++) { assembler->dd(deoptimization_info_[i].pc); - assembler->dd(EncodeExceptPC(deoptimization_info_[i])); + assembler->dd(EncodeExceptPC(deoptimization_info_[i], + deopt_index_list_[i])); } // Emit table of bitmaps. @@ -222,35 +231,14 @@ void SafepointTableBuilder::Emit(Assembler* assembler, int bits_per_entry) { } -uint32_t SafepointTableBuilder::EncodeExceptPC(const DeoptimizationInfo& info) { - unsigned index = info.deoptimization_index; - unsigned gap_size = info.pc_after_gap - info.pc; +uint32_t SafepointTableBuilder::EncodeExceptPC(const DeoptimizationInfo& info, + unsigned index) { uint32_t encoding = SafepointEntry::DeoptimizationIndexField::encode(index); - encoding |= SafepointEntry::GapCodeSizeField::encode(gap_size); encoding |= SafepointEntry::ArgumentsField::encode(info.arguments); encoding |= SafepointEntry::SaveDoublesField::encode(info.has_doubles); return encoding; } -int SafepointTableBuilder::CountShortDeoptimizationIntervals(unsigned limit) { - int result = 0; - if (!deoptimization_info_.is_empty()) { - unsigned previous_gap_end = deoptimization_info_[0].pc_after_gap; - for (int i = 1, n = deoptimization_info_.length(); i < n; i++) { - DeoptimizationInfo info = deoptimization_info_[i]; - if (static_cast(info.deoptimization_index) != - Safepoint::kNoDeoptimizationIndex) { - if (previous_gap_end + limit > info.pc) { - result++; - } - previous_gap_end = info.pc_after_gap; - } - } - } - return result; -} - - } } // namespace v8::internal diff --git a/deps/v8/src/safepoint-table.h b/deps/v8/src/safepoint-table.h index de537f9828..57fceecd92 100644 --- a/deps/v8/src/safepoint-table.h +++ b/deps/v8/src/safepoint-table.h @@ -62,10 +62,20 @@ class SafepointEntry BASE_EMBEDDED { return DeoptimizationIndexField::decode(info_); } - int gap_code_size() const { - ASSERT(is_valid()); - return GapCodeSizeField::decode(info_); - } + static const int kArgumentsFieldBits = 3; + static const int kSaveDoublesFieldBits = 1; + static const int kDeoptIndexBits = + 32 - kArgumentsFieldBits - kSaveDoublesFieldBits; + class DeoptimizationIndexField: + public BitField {}; // NOLINT + class ArgumentsField: + public BitField {}; // NOLINT + class SaveDoublesField: + public BitField { }; // NOLINT int argument_count() const { ASSERT(is_valid()); @@ -85,27 +95,6 @@ class SafepointEntry BASE_EMBEDDED { bool HasRegisters() const; bool HasRegisterAt(int reg_index) const; - // Reserve 13 bits for the gap code size. On ARM a constant pool can be - // emitted when generating the gap code. The size of the const pool is less - // than what can be represented in 12 bits, so 13 bits gives room for having - // instructions before potentially emitting a constant pool. - static const int kGapCodeSizeBits = 13; - static const int kArgumentsFieldBits = 3; - static const int kSaveDoublesFieldBits = 1; - static const int kDeoptIndexBits = - 32 - kGapCodeSizeBits - kArgumentsFieldBits - kSaveDoublesFieldBits; - class GapCodeSizeField: public BitField {}; - class DeoptimizationIndexField: public BitField {}; // NOLINT - class ArgumentsField: public BitField {}; // NOLINT - class SaveDoublesField: public BitField { }; // NOLINT - private: unsigned info_; uint8_t* bits_; @@ -186,6 +175,11 @@ class Safepoint BASE_EMBEDDED { kWithRegistersAndDoubles = kWithRegisters | kWithDoubles } Kind; + enum DeoptMode { + kNoLazyDeopt, + kLazyDeopt + }; + static const int kNoDeoptimizationIndex = (1 << (SafepointEntry::kDeoptIndexBits)) - 1; @@ -206,9 +200,11 @@ class SafepointTableBuilder BASE_EMBEDDED { public: SafepointTableBuilder() : deoptimization_info_(32), + deopt_index_list_(32), indexes_(32), registers_(32), - emitted_(false) { } + emitted_(false), + last_lazy_safepoint_(0) { } // Get the offset of the emitted safepoint table in the code. unsigned GetCodeOffset() const; @@ -217,50 +213,34 @@ class SafepointTableBuilder BASE_EMBEDDED { Safepoint DefineSafepoint(Assembler* assembler, Safepoint::Kind kind, int arguments, - int deoptimization_index); - - // Update the last safepoint with the size of the code generated until the - // end of the gap following it. - void SetPcAfterGap(int pc) { - ASSERT(!deoptimization_info_.is_empty()); - int index = deoptimization_info_.length() - 1; - deoptimization_info_[index].pc_after_gap = pc; - } + Safepoint::DeoptMode mode); - // Get the end pc offset of the last safepoint, including the code generated - // until the end of the gap following it. - unsigned GetPcAfterGap() { - int index = deoptimization_info_.length(); - if (index == 0) return 0; - return deoptimization_info_[index - 1].pc_after_gap; - } + // Record deoptimization index for lazy deoptimization for the last + // outstanding safepoints. + void RecordLazyDeoptimizationIndex(int index); // Emit the safepoint table after the body. The number of bits per // entry must be enough to hold all the pointer indexes. void Emit(Assembler* assembler, int bits_per_entry); - // Count the number of deoptimization points where the next - // following deoptimization point comes less than limit bytes - // after the end of this point's gap. - int CountShortDeoptimizationIntervals(unsigned limit); private: struct DeoptimizationInfo { unsigned pc; - unsigned deoptimization_index; - unsigned pc_after_gap; unsigned arguments; bool has_doubles; }; - uint32_t EncodeExceptPC(const DeoptimizationInfo& info); + uint32_t EncodeExceptPC(const DeoptimizationInfo& info, unsigned index); ZoneList deoptimization_info_; + ZoneList deopt_index_list_; ZoneList*> indexes_; ZoneList*> registers_; unsigned offset_; bool emitted_; + int last_lazy_safepoint_; DISALLOW_COPY_AND_ASSIGN(SafepointTableBuilder); }; diff --git a/deps/v8/src/version.cc b/deps/v8/src/version.cc index f09914b43a..2c21152f1b 100644 --- a/deps/v8/src/version.cc +++ b/deps/v8/src/version.cc @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 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: @@ -35,7 +35,7 @@ #define MAJOR_VERSION 3 #define MINOR_VERSION 6 #define BUILD_NUMBER 6 -#define PATCH_LEVEL 15 +#define PATCH_LEVEL 19 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) #define IS_CANDIDATE_VERSION 0 diff --git a/deps/v8/src/x64/code-stubs-x64.cc b/deps/v8/src/x64/code-stubs-x64.cc index 347c17f799..6499ea0214 100644 --- a/deps/v8/src/x64/code-stubs-x64.cc +++ b/deps/v8/src/x64/code-stubs-x64.cc @@ -4654,13 +4654,12 @@ void StringHelper::GenerateHashGetHash(MacroAssembler* masm, __ shll(scratch, Immediate(15)); __ addl(hash, scratch); - uint32_t kHashShiftCutOffMask = (1 << (32 - String::kHashShift)) - 1; - __ andl(hash, Immediate(kHashShiftCutOffMask)); + __ andl(hash, Immediate(String::kHashBitMask)); // if (hash == 0) hash = 27; Label hash_not_zero; __ j(not_zero, &hash_not_zero); - __ Set(hash, 27); + __ Set(hash, StringHasher::kZeroHash); __ bind(&hash_not_zero); } diff --git a/deps/v8/src/x64/deoptimizer-x64.cc b/deps/v8/src/x64/deoptimizer-x64.cc index b52e659320..f322312b41 100644 --- a/deps/v8/src/x64/deoptimizer-x64.cc +++ b/deps/v8/src/x64/deoptimizer-x64.cc @@ -42,67 +42,7 @@ const int Deoptimizer::table_entry_size_ = 10; int Deoptimizer::patch_size() { - return MacroAssembler::kCallInstructionLength; -} - - -#ifdef DEBUG -// Overwrites code with int3 instructions. -static void ZapCodeRange(Address from, Address to) { - CHECK(from <= to); - int length = static_cast(to - from); - CodePatcher destroyer(from, length); - while (length-- > 0) { - destroyer.masm()->int3(); - } -} -#endif - - -// Iterate through the entries of a SafepointTable that corresponds to -// deoptimization points. -class SafepointTableDeoptimiztionEntryIterator { - public: - explicit SafepointTableDeoptimiztionEntryIterator(Code* code) - : code_(code), table_(code), index_(-1), limit_(table_.length()) { - FindNextIndex(); - } - - SafepointEntry Next(Address* pc) { - if (index_ >= limit_) { - *pc = NULL; - return SafepointEntry(); // Invalid entry. - } - *pc = code_->instruction_start() + table_.GetPcOffset(index_); - SafepointEntry entry = table_.GetEntry(index_); - FindNextIndex(); - return entry; - } - - private: - void FindNextIndex() { - ASSERT(index_ < limit_); - while (++index_ < limit_) { - if (table_.GetEntry(index_).deoptimization_index() != - Safepoint::kNoDeoptimizationIndex) { - return; - } - } - } - - Code* code_; - SafepointTable table_; - // Index of next deoptimization entry. If negative after calling - // FindNextIndex, there are no more, and Next will return an invalid - // SafepointEntry. - int index_; - // Table length. - int limit_; -}; - - -void Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(Handle code) { - // TODO(1276): Implement. + return Assembler::kCallInstructionLength; } @@ -119,84 +59,34 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { // code patching below, and is not needed any more. code->InvalidateRelocation(); - // For each return after a safepoint insert a absolute call to the + // For each LLazyBailout instruction insert a absolute call to the // corresponding deoptimization entry, or a short call to an absolute // jump if space is short. The absolute jumps are put in a table just // before the safepoint table (space was allocated there when the Code // object was created, if necessary). Address instruction_start = function->code()->instruction_start(); - Address jump_table_address = - instruction_start + function->code()->safepoint_table_offset(); #ifdef DEBUG - Address previous_pc = instruction_start; -#endif - - SafepointTableDeoptimiztionEntryIterator deoptimizations(function->code()); - Address entry_pc = NULL; - - SafepointEntry current_entry = deoptimizations.Next(&entry_pc); - while (current_entry.is_valid()) { - int gap_code_size = current_entry.gap_code_size(); - unsigned deoptimization_index = current_entry.deoptimization_index(); - -#ifdef DEBUG - // Destroy the code which is not supposed to run again. - ZapCodeRange(previous_pc, entry_pc); + Address prev_call_address = NULL; #endif + DeoptimizationInputData* deopt_data = + DeoptimizationInputData::cast(code->deoptimization_data()); + for (int i = 0; i < deopt_data->DeoptCount(); i++) { + if (deopt_data->Pc(i)->value() == -1) continue; // Position where Call will be patched in. - Address call_address = entry_pc + gap_code_size; - // End of call instruction, if using a direct call to a 64-bit address. - Address call_end_address = - call_address + MacroAssembler::kCallInstructionLength; - - // Find next deoptimization entry, if any. - Address next_pc = NULL; - SafepointEntry next_entry = deoptimizations.Next(&next_pc); - - if (!next_entry.is_valid() || next_pc >= call_end_address) { - // Room enough to write a long call instruction. - CodePatcher patcher(call_address, Assembler::kCallInstructionLength); - patcher.masm()->Call(GetDeoptimizationEntry(deoptimization_index, LAZY), - RelocInfo::NONE); -#ifdef DEBUG - previous_pc = call_end_address; -#endif - } else { - // Not room enough for a long Call instruction. Write a short call - // instruction to a long jump placed elsewhere in the code. + Address call_address = instruction_start + deopt_data->Pc(i)->value(); + // There is room enough to write a long call instruction because we pad + // LLazyBailout instructions with nops if necessary. + CodePatcher patcher(call_address, Assembler::kCallInstructionLength); + patcher.masm()->Call(GetDeoptimizationEntry(i, LAZY), RelocInfo::NONE); + ASSERT(prev_call_address == NULL || + call_address >= prev_call_address + patch_size()); + ASSERT(call_address + patch_size() <= code->instruction_end()); #ifdef DEBUG - Address short_call_end_address = - call_address + MacroAssembler::kShortCallInstructionLength; + prev_call_address = call_address; #endif - ASSERT(next_pc >= short_call_end_address); - - // Write jump in jump-table. - jump_table_address -= MacroAssembler::kJumpInstructionLength; - CodePatcher jump_patcher(jump_table_address, - MacroAssembler::kJumpInstructionLength); - jump_patcher.masm()->Jump( - GetDeoptimizationEntry(deoptimization_index, LAZY), - RelocInfo::NONE); - - // Write call to jump at call_offset. - CodePatcher call_patcher(call_address, - MacroAssembler::kShortCallInstructionLength); - call_patcher.masm()->call(jump_table_address); -#ifdef DEBUG - previous_pc = short_call_end_address; -#endif - } - - // Continue with next deoptimization entry. - current_entry = next_entry; - entry_pc = next_pc; } -#ifdef DEBUG - // Destroy the code which is not supposed to run again. - ZapCodeRange(previous_pc, jump_table_address); -#endif // Add the deoptimizing code to the list. DeoptimizingCodeListNode* node = new DeoptimizingCodeListNode(code); @@ -211,11 +101,6 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { PrintF("[forced deoptimization: "); function->PrintName(); PrintF(" / %" V8PRIxPTR "]\n", reinterpret_cast(function)); -#ifdef DEBUG - if (FLAG_print_code) { - code->PrintLn(); - } -#endif } } diff --git a/deps/v8/src/x64/lithium-codegen-x64.cc b/deps/v8/src/x64/lithium-codegen-x64.cc index 3efbb8bdcb..b82dc54f3b 100644 --- a/deps/v8/src/x64/lithium-codegen-x64.cc +++ b/deps/v8/src/x64/lithium-codegen-x64.cc @@ -43,35 +43,24 @@ class SafepointGenerator : public CallWrapper { public: SafepointGenerator(LCodeGen* codegen, LPointerMap* pointers, - int deoptimization_index) + Safepoint::DeoptMode mode) : codegen_(codegen), pointers_(pointers), - deoptimization_index_(deoptimization_index) { } + deopt_mode_(mode) { } virtual ~SafepointGenerator() { } virtual void BeforeCall(int call_size) const { - ASSERT(call_size >= 0); - // Ensure that we have enough space after the previous safepoint position - // for the jump generated there. - int call_end = codegen_->masm()->pc_offset() + call_size; - int prev_jump_end = codegen_->LastSafepointEnd() + kMinSafepointSize; - if (call_end < prev_jump_end) { - int padding_size = prev_jump_end - call_end; - STATIC_ASSERT(kMinSafepointSize <= 9); // One multibyte nop is enough. - codegen_->masm()->nop(padding_size); - } + codegen_->EnsureSpaceForLazyDeopt(Deoptimizer::patch_size() - call_size); } virtual void AfterCall() const { - codegen_->RecordSafepoint(pointers_, deoptimization_index_); + codegen_->RecordSafepoint(pointers_, deopt_mode_); } private: - static const int kMinSafepointSize = - MacroAssembler::kShortCallInstructionLength; LCodeGen* codegen_; LPointerMap* pointers_; - int deoptimization_index_; + Safepoint::DeoptMode deopt_mode_; }; @@ -94,7 +83,6 @@ void LCodeGen::FinishCode(Handle code) { code->set_stack_slots(GetStackSlotCount()); code->set_safepoint_table_offset(safepoints_.GetCodeOffset()); PopulateDeoptimizationData(code); - Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(code); } @@ -200,7 +188,7 @@ bool LCodeGen::GeneratePrologue() { } else { __ CallRuntime(Runtime::kNewFunctionContext, 1); } - RecordSafepoint(Safepoint::kNoDeoptimizationIndex); + RecordSafepoint(Safepoint::kNoLazyDeopt); // Context is returned in both rax and rsi. It replaces the context // passed to us. It's saved in the stack and kept live in rsi. __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi); @@ -252,19 +240,11 @@ bool LCodeGen::GenerateBody() { instr->CompileToNative(this); } } + EnsureSpaceForLazyDeopt(Deoptimizer::patch_size()); return !is_aborted(); } -LInstruction* LCodeGen::GetNextInstruction() { - if (current_instruction_ < instructions_->length() - 1) { - return instructions_->at(current_instruction_ + 1); - } else { - return NULL; - } -} - - bool LCodeGen::GenerateJumpTable() { for (int i = 0; i < jump_table_.length(); i++) { __ bind(&jump_table_[i].label); @@ -283,18 +263,6 @@ bool LCodeGen::GenerateDeferredCode() { code->Generate(); __ jmp(code->exit()); } - - // Pad code to ensure that the last piece of deferred code have - // room for lazy bailout. - while ((masm()->pc_offset() - LastSafepointEnd()) - < Deoptimizer::patch_size()) { - int padding = masm()->pc_offset() - LastSafepointEnd(); - if (padding > 9) { - __ nop(9); - } else { - __ nop(padding); - } - } } // Deferred code is the last part of the instruction sequence. Mark @@ -306,20 +274,6 @@ bool LCodeGen::GenerateDeferredCode() { bool LCodeGen::GenerateSafepointTable() { ASSERT(is_done()); - // Ensure that there is space at the end of the code to write a number - // of jump instructions, as well as to afford writing a call near the end - // of the code. - // The jumps are used when there isn't room in the code stream to write - // a long call instruction. Instead it writes a shorter call to a - // jump instruction in the same code object. - // The calls are used when lazy deoptimizing a function and calls to a - // deoptimization function. - int short_deopts = safepoints_.CountShortDeoptimizationIntervals( - static_cast(MacroAssembler::kJumpInstructionLength)); - int byte_count = (short_deopts) * MacroAssembler::kJumpInstructionLength; - while (byte_count-- > 0) { - __ int3(); - } safepoints_.Emit(masm(), GetStackSlotCount()); return !is_aborted(); } @@ -475,11 +429,12 @@ void LCodeGen::CallCodeGeneric(Handle code, LInstruction* instr, SafepointMode safepoint_mode, int argc) { + EnsureSpaceForLazyDeopt(Deoptimizer::patch_size() - masm()->CallSize(code)); ASSERT(instr != NULL); LPointerMap* pointers = instr->pointer_map(); RecordPosition(pointers->position()); __ call(code, mode); - RegisterLazyDeoptimization(instr, safepoint_mode, argc); + RecordSafepointWithLazyDeopt(instr, safepoint_mode, argc); // Signal that we don't inline smi code before these stubs in the // optimizing code generator. @@ -506,7 +461,7 @@ void LCodeGen::CallRuntime(const Runtime::Function* function, RecordPosition(pointers->position()); __ CallRuntime(function, num_arguments); - RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT, 0); + RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT, 0); } @@ -516,39 +471,12 @@ void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id, __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); __ CallRuntimeSaveDoubles(id); RecordSafepointWithRegisters( - instr->pointer_map(), argc, Safepoint::kNoDeoptimizationIndex); + instr->pointer_map(), argc, Safepoint::kNoLazyDeopt); } -void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr, - SafepointMode safepoint_mode, - int argc) { - // Create the environment to bailout to. If the call has side effects - // execution has to continue after the call otherwise execution can continue - // from a previous bailout point repeating the call. - LEnvironment* deoptimization_environment; - if (instr->HasDeoptimizationEnvironment()) { - deoptimization_environment = instr->deoptimization_environment(); - } else { - deoptimization_environment = instr->environment(); - } - - RegisterEnvironmentForDeoptimization(deoptimization_environment); - if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) { - ASSERT(argc == 0); - RecordSafepoint(instr->pointer_map(), - deoptimization_environment->deoptimization_index()); - } else { - ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS); - RecordSafepointWithRegisters( - instr->pointer_map(), - argc, - deoptimization_environment->deoptimization_index()); - } -} - - -void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment) { +void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment, + Safepoint::DeoptMode mode) { if (!environment->HasBeenRegistered()) { // Physical stack frame layout: // -x ............. -4 0 ..................................... y @@ -570,14 +498,17 @@ void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment) { Translation translation(&translations_, frame_count); WriteTranslation(environment, &translation); int deoptimization_index = deoptimizations_.length(); - environment->Register(deoptimization_index, translation.index()); + int pc_offset = masm()->pc_offset(); + environment->Register(deoptimization_index, + translation.index(), + (mode == Safepoint::kLazyDeopt) ? pc_offset : -1); deoptimizations_.Add(environment); } } void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) { - RegisterEnvironmentForDeoptimization(environment); + RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); ASSERT(environment->HasBeenRegistered()); int id = environment->deoptimization_index(); Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER); @@ -629,6 +560,7 @@ void LCodeGen::PopulateDeoptimizationData(Handle code) { data->SetTranslationIndex(i, Smi::FromInt(env->translation_index())); data->SetArgumentsStackHeight(i, Smi::FromInt(env->arguments_stack_height())); + data->SetPc(i, Smi::FromInt(env->pc_offset())); } code->set_deoptimization_data(*data); } @@ -660,17 +592,29 @@ void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() { } +void LCodeGen::RecordSafepointWithLazyDeopt( + LInstruction* instr, SafepointMode safepoint_mode, int argc) { + if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) { + RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt); + } else { + ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS); + RecordSafepointWithRegisters( + instr->pointer_map(), argc, Safepoint::kLazyDeopt); + } +} + + void LCodeGen::RecordSafepoint( LPointerMap* pointers, Safepoint::Kind kind, int arguments, - int deoptimization_index) { + Safepoint::DeoptMode deopt_mode) { ASSERT(kind == expected_safepoint_kind_); const ZoneList* operands = pointers->operands(); Safepoint safepoint = safepoints_.DefineSafepoint(masm(), - kind, arguments, deoptimization_index); + kind, arguments, deopt_mode); for (int i = 0; i < operands->length(); i++) { LOperand* pointer = operands->at(i); if (pointer->IsStackSlot()) { @@ -687,22 +631,21 @@ void LCodeGen::RecordSafepoint( void LCodeGen::RecordSafepoint(LPointerMap* pointers, - int deoptimization_index) { - RecordSafepoint(pointers, Safepoint::kSimple, 0, deoptimization_index); + Safepoint::DeoptMode deopt_mode) { + RecordSafepoint(pointers, Safepoint::kSimple, 0, deopt_mode); } -void LCodeGen::RecordSafepoint(int deoptimization_index) { +void LCodeGen::RecordSafepoint(Safepoint::DeoptMode deopt_mode) { LPointerMap empty_pointers(RelocInfo::kNoPosition); - RecordSafepoint(&empty_pointers, deoptimization_index); + RecordSafepoint(&empty_pointers, deopt_mode); } void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers, int arguments, - int deoptimization_index) { - RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, - deoptimization_index); + Safepoint::DeoptMode deopt_mode) { + RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, deopt_mode); } @@ -737,12 +680,6 @@ void LCodeGen::DoGap(LGap* gap) { LParallelMove* move = gap->GetParallelMove(inner_pos); if (move != NULL) DoParallelMove(move); } - - LInstruction* next = GetNextInstruction(); - if (next != NULL && next->IsLazyBailout()) { - int pc = masm()->pc_offset(); - safepoints_.SetPcAfterGap(pc); - } } @@ -1851,7 +1788,7 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { LInstanceOfKnownGlobal* instr) : LDeferredCode(codegen), instr_(instr) { } virtual void Generate() { - codegen()->DoDeferredLInstanceOfKnownGlobal(instr_, &map_check_); + codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_); } Label* map_check() { return &map_check_; } @@ -1910,8 +1847,8 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { } -void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, - Label* map_check) { +void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, + Label* map_check) { { PushSafepointRegistersScope scope(this); InstanceofStub::Flags flags = static_cast( @@ -1937,6 +1874,9 @@ void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, RECORD_SAFEPOINT_WITH_REGISTERS, 2); ASSERT(delta == masm_->SizeOfCodeGeneratedSince(map_check)); + ASSERT(instr->HasDeoptimizationEnvironment()); + LEnvironment* env = instr->deoptimization_environment(); + safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); // Move result to a register that survives the end of the // PushSafepointRegisterScope. __ movq(kScratchRegister, rax); @@ -2508,12 +2448,9 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) { __ bind(&invoke); ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); LPointerMap* pointers = instr->pointer_map(); - LEnvironment* env = instr->deoptimization_environment(); RecordPosition(pointers->position()); - RegisterEnvironmentForDeoptimization(env); - SafepointGenerator safepoint_generator(this, - pointers, - env->deoptimization_index()); + SafepointGenerator safepoint_generator( + this, pointers, Safepoint::kLazyDeopt); v8::internal::ParameterCount actual(rax); __ InvokeFunction(function, actual, CALL_FUNCTION, safepoint_generator, CALL_AS_METHOD); @@ -2591,7 +2528,7 @@ void LCodeGen::CallKnownFunction(Handle function, } // Setup deoptimization. - RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT, 0); + RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT, 0); // Restore context. __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); @@ -2938,10 +2875,8 @@ void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) { ASSERT(instr->HasPointerMap()); ASSERT(instr->HasDeoptimizationEnvironment()); LPointerMap* pointers = instr->pointer_map(); - LEnvironment* env = instr->deoptimization_environment(); RecordPosition(pointers->position()); - RegisterEnvironmentForDeoptimization(env); - SafepointGenerator generator(this, pointers, env->deoptimization_index()); + SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); ParameterCount count(instr->arity()); __ InvokeFunction(rdi, count, CALL_FUNCTION, generator, CALL_AS_METHOD); __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); @@ -4037,9 +3972,28 @@ void LCodeGen::EmitIsConstructCall(Register temp) { } +void LCodeGen::EnsureSpaceForLazyDeopt(int space_needed) { + // Ensure that we have enough space after the previous lazy-bailout + // instruction for patching the code here. + int current_pc = masm()->pc_offset(); + if (current_pc < last_lazy_deopt_pc_ + space_needed) { + int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc; + while (padding_size > 0) { + int nop_size = padding_size > 9 ? 9 : padding_size; + __ nop(nop_size); + padding_size -= nop_size; + } + } +} + + void LCodeGen::DoLazyBailout(LLazyBailout* instr) { - // No code for lazy bailout instruction. Used to capture environment after a - // call for populating the safepoint data with deoptimization data. + EnsureSpaceForLazyDeopt(Deoptimizer::patch_size()); + last_lazy_deopt_pc_ = masm()->pc_offset(); + ASSERT(instr->HasEnvironment()); + LEnvironment* env = instr->environment(); + RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt); + safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); } @@ -4055,15 +4009,12 @@ void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) { EmitPushTaggedOperand(key); ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); LPointerMap* pointers = instr->pointer_map(); - LEnvironment* env = instr->deoptimization_environment(); RecordPosition(pointers->position()); - RegisterEnvironmentForDeoptimization(env); // Create safepoint generator that will also ensure enough space in the // reloc info for patching in deoptimization (since this is invoking a // builtin) - SafepointGenerator safepoint_generator(this, - pointers, - env->deoptimization_index()); + SafepointGenerator safepoint_generator( + this, pointers, Safepoint::kLazyDeopt); __ Push(Smi::FromInt(strict_mode_flag())); __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator); } @@ -4076,30 +4027,21 @@ void LCodeGen::DoIn(LIn* instr) { EmitPushTaggedOperand(obj); ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); LPointerMap* pointers = instr->pointer_map(); - LEnvironment* env = instr->deoptimization_environment(); RecordPosition(pointers->position()); - RegisterEnvironmentForDeoptimization(env); - // Create safepoint generator that will also ensure enough space in the - // reloc info for patching in deoptimization (since this is invoking a - // builtin) - SafepointGenerator safepoint_generator(this, - pointers, - env->deoptimization_index()); + SafepointGenerator safepoint_generator( + this, pointers, Safepoint::kLazyDeopt); __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator); } void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) { - { - PushSafepointRegistersScope scope(this); - __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); - __ CallRuntimeSaveDoubles(Runtime::kStackGuard); - RegisterLazyDeoptimization(instr, RECORD_SAFEPOINT_WITH_REGISTERS, 0); - } - - // The gap code includes the restoring of the safepoint registers. - int pc = masm()->pc_offset(); - safepoints_.SetPcAfterGap(pc); + PushSafepointRegistersScope scope(this); + __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); + __ CallRuntimeSaveDoubles(Runtime::kStackGuard); + RecordSafepointWithLazyDeopt(instr, RECORD_SAFEPOINT_WITH_REGISTERS, 0); + ASSERT(instr->HasEnvironment()); + LEnvironment* env = instr->environment(); + safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); } @@ -4113,6 +4055,10 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) { LStackCheck* instr_; }; + ASSERT(instr->HasEnvironment()); + LEnvironment* env = instr->environment(); + // There is no LLazyBailout instruction for stack-checks. We have to + // prepare for lazy deoptimization explicitly here. if (instr->hydrogen()->is_function_entry()) { // Perform stack overflow check. Label done; @@ -4120,7 +4066,11 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) { __ j(above_equal, &done, Label::kNear); StackCheckStub stub; CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); + EnsureSpaceForLazyDeopt(Deoptimizer::patch_size()); + last_lazy_deopt_pc_ = masm()->pc_offset(); __ bind(&done); + RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt); + safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); } else { ASSERT(instr->hydrogen()->is_backwards_branch()); // Perform stack overflow check if this goto needs it before jumping. @@ -4128,8 +4078,14 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) { new DeferredStackCheck(this, instr); __ CompareRoot(rsp, Heap::kStackLimitRootIndex); __ j(below, deferred_stack_check->entry()); + EnsureSpaceForLazyDeopt(Deoptimizer::patch_size()); + last_lazy_deopt_pc_ = masm()->pc_offset(); __ bind(instr->done_label()); deferred_stack_check->SetExit(instr->done_label()); + RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt); + // Don't record a deoptimization index for the safepoint here. + // This will be done explicitly when emitting call and the safepoint in + // the deferred code. } } @@ -4145,7 +4101,7 @@ void LCodeGen::DoOsrEntry(LOsrEntry* instr) { // If the environment were already registered, we would have no way of // backpatching it with the spill slot operands. ASSERT(!environment->HasBeenRegistered()); - RegisterEnvironmentForDeoptimization(environment); + RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); ASSERT(osr_pc_offset_ == -1); osr_pc_offset_ = masm()->pc_offset(); } diff --git a/deps/v8/src/x64/lithium-codegen-x64.h b/deps/v8/src/x64/lithium-codegen-x64.h index 8cb4cece96..43c045f7bc 100644 --- a/deps/v8/src/x64/lithium-codegen-x64.h +++ b/deps/v8/src/x64/lithium-codegen-x64.h @@ -60,6 +60,7 @@ class LCodeGen BASE_EMBEDDED { status_(UNUSED), deferred_(8), osr_pc_offset_(-1), + last_lazy_deopt_pc_(0), resolver_(this), expected_safepoint_kind_(Safepoint::kSimple) { PopulateDeoptimizationLiteralsWithInlinedFunctions(); @@ -97,8 +98,8 @@ class LCodeGen BASE_EMBEDDED { void DoDeferredStackCheck(LStackCheck* instr); void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr); void DoDeferredStringCharFromCode(LStringCharFromCode* instr); - void DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, - Label* map_check); + void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, + Label* map_check); // Parallel move support. void DoParallelMove(LParallelMove* move); @@ -134,7 +135,6 @@ class LCodeGen BASE_EMBEDDED { HGraph* graph() const { return chunk_->graph(); } int GetNextEmittedBlock(int block); - LInstruction* GetNextInstruction(); void EmitClassOfTest(Label* if_true, Label* if_false, @@ -199,10 +199,11 @@ class LCodeGen BASE_EMBEDDED { void LoadHeapObject(Register result, Handle object); - void RegisterLazyDeoptimization(LInstruction* instr, - SafepointMode safepoint_mode, - int argc); - void RegisterEnvironmentForDeoptimization(LEnvironment* environment); + void RecordSafepointWithLazyDeopt(LInstruction* instr, + SafepointMode safepoint_mode, + int argc); + void RegisterEnvironmentForDeoptimization(LEnvironment* environment, + Safepoint::DeoptMode mode); void DeoptimizeIf(Condition cc, LEnvironment* environment); void AddToTranslation(Translation* translation, @@ -236,16 +237,13 @@ class LCodeGen BASE_EMBEDDED { void RecordSafepoint(LPointerMap* pointers, Safepoint::Kind kind, int arguments, - int deoptimization_index); - void RecordSafepoint(LPointerMap* pointers, int deoptimization_index); - void RecordSafepoint(int deoptimization_index); + Safepoint::DeoptMode mode); + void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode); + void RecordSafepoint(Safepoint::DeoptMode mode); void RecordSafepointWithRegisters(LPointerMap* pointers, int arguments, - int deoptimization_index); + Safepoint::DeoptMode mode); void RecordPosition(int position); - int LastSafepointEnd() { - return static_cast(safepoints_.GetPcAfterGap()); - } static Condition TokenToCondition(Token::Value op, bool is_unsigned); void EmitGoto(int block); @@ -290,6 +288,8 @@ class LCodeGen BASE_EMBEDDED { Address address; }; + void EnsureSpaceForLazyDeopt(int space_needed); + LChunk* const chunk_; MacroAssembler* const masm_; CompilationInfo* const info_; @@ -306,6 +306,7 @@ class LCodeGen BASE_EMBEDDED { TranslationBuffer translations_; ZoneList deferred_; int osr_pc_offset_; + int last_lazy_deopt_pc_; // Builder that keeps track of safepoints in the code. The table // itself is emitted at the end of the generated code. diff --git a/deps/v8/test/mjsunit/compiler/regress-funcaller.js b/deps/v8/test/mjsunit/compiler/regress-funcaller.js index 88db147a8f..5c2a59720b 100644 --- a/deps/v8/test/mjsunit/compiler/regress-funcaller.js +++ b/deps/v8/test/mjsunit/compiler/regress-funcaller.js @@ -25,6 +25,8 @@ // (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: --allow-natives-syntax + // Test function.caller. function A() {} @@ -40,9 +42,10 @@ A.prototype.g = gee; var o = new A(); -for (var i=0; i<5000000; i++) { +for (var i=0; i<5; i++) { o.g(i); } +%OptimizeFunctionOnNextCall(o.g); assertEquals(gee, o.g(0)); assertEquals(null, o.g(1)); @@ -53,9 +56,10 @@ function hej(x) { return o.g(x); } -for (var j=0; j<5000000; j++) { +for (var j=0; j<5; j++) { hej(j); } +%OptimizeFunctionOnNextCall(hej); assertEquals(gee, hej(0)); assertEquals(hej, hej(1)); @@ -66,8 +70,9 @@ function from_eval(x) { return o.g(x); } -for (var j=0; j<5000000; j++) { +for (var j=0; j<5; j++) { from_eval(j); } +%OptimizeFunctionOnNextCall(from_eval); assertEquals(gee, from_eval(0)); assertEquals(from_eval, from_eval(1)); diff --git a/deps/v8/test/mjsunit/compiler/regress-lazy-deopt.js b/deps/v8/test/mjsunit/compiler/regress-lazy-deopt.js new file mode 100644 index 0000000000..d1c3d01dc6 --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/regress-lazy-deopt.js @@ -0,0 +1,48 @@ +// Copyright 2011 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: --allow-natives-syntax + +// Test lazy deoptimization after CallFunctionStub. + +function foo() { return 1; } + +function f(x, y) { + var a = [0]; + if (x == 0) { + %DeoptimizeFunction(f); + return 1; + } + a[0] = %_CallFunction(null, x - 1, f); + return x >> a[0]; +} + +f(42); +f(42); +assertEquals(42, f(42)); +%OptimizeFunctionOnNextCall(f); +assertEquals(42, f(42));