Browse Source

Upgrade V8 to 3.6.6.19

v0.7.4-release
isaacs 13 years ago
parent
commit
4afc46d7bc
  1. 9
      deps/v8/src/arm/assembler-arm-inl.h
  2. 10
      deps/v8/src/arm/assembler-arm.h
  3. 7
      deps/v8/src/arm/code-stubs-arm.cc
  4. 76
      deps/v8/src/arm/deoptimizer-arm.cc
  5. 222
      deps/v8/src/arm/lithium-codegen-arm.cc
  6. 30
      deps/v8/src/arm/lithium-codegen-arm.h
  7. 21
      deps/v8/src/arm/lithium-gap-resolver-arm.cc
  8. 18
      deps/v8/src/deoptimizer.cc
  9. 1
      deps/v8/src/hydrogen-instructions.h
  10. 6
      deps/v8/src/ia32/code-stubs-ia32.cc
  11. 116
      deps/v8/src/ia32/deoptimizer-ia32.cc
  12. 212
      deps/v8/src/ia32/lithium-codegen-ia32.cc
  13. 34
      deps/v8/src/ia32/lithium-codegen-ia32.h
  14. 10
      deps/v8/src/ia32/lithium-ia32.h
  15. 8
      deps/v8/src/lithium.h
  16. 2
      deps/v8/src/mips/code-stubs-mips.cc
  17. 11
      deps/v8/src/objects.cc
  18. 9
      deps/v8/src/objects.h
  19. 60
      deps/v8/src/safepoint-table.cc
  20. 78
      deps/v8/src/safepoint-table.h
  21. 4
      deps/v8/src/version.cc
  22. 5
      deps/v8/src/x64/code-stubs-x64.cc
  23. 147
      deps/v8/src/x64/deoptimizer-x64.cc
  24. 236
      deps/v8/src/x64/lithium-codegen-x64.cc
  25. 29
      deps/v8/src/x64/lithium-codegen-x64.h
  26. 11
      deps/v8/test/mjsunit/compiler/regress-funcaller.js
  27. 48
      deps/v8/test/mjsunit/compiler/regress-lazy-deopt.js

9
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 // The original source code covered by the above license above has been modified
// significantly by Google Inc. // 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_ #ifndef V8_ARM_ASSEMBLER_ARM_INL_H_
#define V8_ARM_ASSEMBLER_ARM_INL_H_ #define V8_ARM_ASSEMBLER_ARM_INL_H_
@ -46,6 +46,13 @@ namespace v8 {
namespace internal { namespace internal {
int DwVfpRegister::ToAllocationIndex(DwVfpRegister reg) {
ASSERT(!reg.is(kDoubleRegZero));
ASSERT(!reg.is(kScratchDoubleReg));
return reg.code();
}
void RelocInfo::apply(intptr_t delta) { void RelocInfo::apply(intptr_t delta) {
if (RelocInfo::IsInternalReference(rmode_)) { if (RelocInfo::IsInternalReference(rmode_)) {
// absolute code pointer inside code object moves with the code object. // absolute code pointer inside code object moves with the code object.

10
deps/v8/src/arm/assembler-arm.h

@ -32,7 +32,7 @@
// The original source code covered by the above license above has been // The original source code covered by the above license above has been
// modified significantly by Google Inc. // 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 // A light-weight ARM Assembler
// Generates user mode instructions for the ARM architecture up to version 5 // Generates user mode instructions for the ARM architecture up to version 5
@ -176,14 +176,11 @@ struct DwVfpRegister {
static const int kNumAllocatableRegisters = kNumRegisters - static const int kNumAllocatableRegisters = kNumRegisters -
kNumReservedRegisters; kNumReservedRegisters;
static int ToAllocationIndex(DwVfpRegister reg) { inline static int ToAllocationIndex(DwVfpRegister reg);
ASSERT(reg.code() != 0);
return reg.code() - 1;
}
static DwVfpRegister FromAllocationIndex(int index) { static DwVfpRegister FromAllocationIndex(int index) {
ASSERT(index >= 0 && index < kNumAllocatableRegisters); ASSERT(index >= 0 && index < kNumAllocatableRegisters);
return from_code(index + 1); return from_code(index);
} }
static const char* AllocationIndexToString(int index) { static const char* AllocationIndexToString(int index) {
@ -307,6 +304,7 @@ const DwVfpRegister d15 = { 15 };
const DwVfpRegister kFirstCalleeSavedDoubleReg = d8; const DwVfpRegister kFirstCalleeSavedDoubleReg = d8;
const DwVfpRegister kLastCalleeSavedDoubleReg = d15; const DwVfpRegister kLastCalleeSavedDoubleReg = d15;
const DwVfpRegister kDoubleRegZero = d14; const DwVfpRegister kDoubleRegZero = d14;
const DwVfpRegister kScratchDoubleReg = d15;
// Coprocessor register // Coprocessor register

7
deps/v8/src/arm/code-stubs-arm.cc

@ -5392,13 +5392,12 @@ void StringHelper::GenerateHashGetHash(MacroAssembler* masm,
// hash ^= hash >> 11; // hash ^= hash >> 11;
__ eor(hash, hash, Operand(hash, LSR, 11)); __ eor(hash, hash, Operand(hash, LSR, 11));
// hash += hash << 15; // 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(String::kHashBitMask), SetCC);
__ and_(hash, hash, Operand(kHashShiftCutOffMask));
// if (hash == 0) hash = 27; // if (hash == 0) hash = 27;
__ mov(hash, Operand(27), LeaveCC, eq); __ mov(hash, Operand(StringHasher::kZeroHash), LeaveCC, eq);
} }

76
deps/v8/src/arm/deoptimizer-arm.cc

@ -44,12 +44,6 @@ int Deoptimizer::patch_size() {
} }
void Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code) {
// Nothing to do. No new relocation information is written for lazy
// deoptimization on ARM.
}
void Deoptimizer::DeoptimizeFunction(JSFunction* function) { void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
HandleScope scope; HandleScope scope;
AssertNoAllocation no_allocation; AssertNoAllocation no_allocation;
@ -58,59 +52,38 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
// Get the optimized code. // Get the optimized code.
Code* code = function->code(); Code* code = function->code();
Address code_start_address = code->instruction_start();
// Invalidate the relocation information, as it will become invalid by the // Invalidate the relocation information, as it will become invalid by the
// code patching below, and is not needed any more. // code patching below, and is not needed any more.
code->InvalidateRelocation(); code->InvalidateRelocation();
// For each return after a safepoint insert an absolute call to the // For each LLazyBailout instruction insert a call to the corresponding
// corresponding deoptimization entry. // deoptimization entry.
unsigned last_pc_offset = 0; DeoptimizationInputData* deopt_data =
SafepointTable table(function->code()); DeoptimizationInputData::cast(code->deoptimization_data());
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);
#ifdef DEBUG #ifdef DEBUG
// Destroy the code which is not supposed to be run again. Address prev_call_address = NULL;
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);
}
#endif #endif
last_pc_offset = pc_offset; for (int i = 0; i < deopt_data->DeoptCount(); i++) {
if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) { if (deopt_data->Pc(i)->value() == -1) continue;
Address deoptimization_entry = Deoptimizer::GetDeoptimizationEntry( Address call_address = code_start_address + deopt_data->Pc(i)->value();
deoptimization_index, Deoptimizer::LAZY); Address deopt_entry = GetDeoptimizationEntry(i, LAZY);
last_pc_offset += gap_code_size; int call_size_in_bytes = MacroAssembler::CallSize(deopt_entry,
int call_size_in_bytes = MacroAssembler::CallSize(deoptimization_entry, RelocInfo::NONE);
RelocInfo::NONE); int call_size_in_words = call_size_in_bytes / Assembler::kInstrSize;
int call_size_in_words = call_size_in_bytes / Assembler::kInstrSize; ASSERT(call_size_in_bytes % Assembler::kInstrSize == 0);
ASSERT(call_size_in_bytes % Assembler::kInstrSize == 0); ASSERT(call_size_in_bytes <= patch_size());
ASSERT(call_size_in_bytes <= patch_size()); CodePatcher patcher(call_address, call_size_in_words);
CodePatcher patcher(code->instruction_start() + last_pc_offset, patcher.masm()->Call(deopt_entry, RelocInfo::NONE);
call_size_in_words); ASSERT(prev_call_address == NULL ||
patcher.masm()->Call(deoptimization_entry, RelocInfo::NONE); call_address >= prev_call_address + patch_size());
last_pc_offset += call_size_in_bytes; ASSERT(call_address + patch_size() <= code->instruction_end());
}
}
#ifdef DEBUG #ifdef DEBUG
// Destroy the code which is not supposed to be run again. prev_call_address = call_address;
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);
}
#endif #endif
}
// Add the deoptimizing code to the list. // Add the deoptimizing code to the list.
DeoptimizingCodeListNode* node = new DeoptimizingCodeListNode(code); DeoptimizingCodeListNode* node = new DeoptimizingCodeListNode(code);
@ -125,11 +98,6 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
PrintF("[forced deoptimization: "); PrintF("[forced deoptimization: ");
function->PrintName(); function->PrintName();
PrintF(" / %x]\n", reinterpret_cast<uint32_t>(function)); PrintF(" / %x]\n", reinterpret_cast<uint32_t>(function));
#ifdef DEBUG
if (FLAG_print_code) {
code->PrintLn();
}
#endif
} }
} }

222
deps/v8/src/arm/lithium-codegen-arm.cc

@ -40,37 +40,22 @@ class SafepointGenerator : public CallWrapper {
public: public:
SafepointGenerator(LCodeGen* codegen, SafepointGenerator(LCodeGen* codegen,
LPointerMap* pointers, LPointerMap* pointers,
int deoptimization_index) Safepoint::DeoptMode mode)
: codegen_(codegen), : codegen_(codegen),
pointers_(pointers), pointers_(pointers),
deoptimization_index_(deoptimization_index) { } deopt_mode_(mode) { }
virtual ~SafepointGenerator() { } virtual ~SafepointGenerator() { }
virtual void BeforeCall(int call_size) const { 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 AfterCall() const { virtual void AfterCall() const {
codegen_->RecordSafepoint(pointers_, deoptimization_index_); codegen_->RecordSafepoint(pointers_, deopt_mode_);
} }
private: private:
LCodeGen* codegen_; LCodeGen* codegen_;
LPointerMap* pointers_; LPointerMap* pointers_;
int deoptimization_index_; Safepoint::DeoptMode deopt_mode_;
}; };
@ -95,7 +80,6 @@ void LCodeGen::FinishCode(Handle<Code> code) {
code->set_stack_slots(GetStackSlotCount()); code->set_stack_slots(GetStackSlotCount());
code->set_safepoint_table_offset(safepoints_.GetCodeOffset()); code->set_safepoint_table_offset(safepoints_.GetCodeOffset());
PopulateDeoptimizationData(code); PopulateDeoptimizationData(code);
Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(code);
} }
@ -192,7 +176,7 @@ bool LCodeGen::GeneratePrologue() {
} else { } else {
__ CallRuntime(Runtime::kNewFunctionContext, 1); __ CallRuntime(Runtime::kNewFunctionContext, 1);
} }
RecordSafepoint(Safepoint::kNoDeoptimizationIndex); RecordSafepoint(Safepoint::kNoLazyDeopt);
// Context is returned in both r0 and cp. It replaces the context // 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. // passed to us. It's saved in the stack and kept live in cp.
__ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
@ -243,19 +227,11 @@ bool LCodeGen::GenerateBody() {
instr->CompileToNative(this); instr->CompileToNative(this);
} }
} }
EnsureSpaceForLazyDeopt();
return !is_aborted(); return !is_aborted();
} }
LInstruction* LCodeGen::GetNextInstruction() {
if (current_instruction_ < instructions_->length() - 1) {
return instructions_->at(current_instruction_ + 1);
} else {
return NULL;
}
}
bool LCodeGen::GenerateDeferredCode() { bool LCodeGen::GenerateDeferredCode() {
ASSERT(is_generating()); ASSERT(is_generating());
if (deferred_.length() > 0) { if (deferred_.length() > 0) {
@ -265,13 +241,6 @@ bool LCodeGen::GenerateDeferredCode() {
code->Generate(); code->Generate();
__ jmp(code->exit()); __ 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 // Force constant pool emission at the end of the deferred code to make
@ -551,7 +520,7 @@ void LCodeGen::CallCodeGeneric(Handle<Code> code,
LPointerMap* pointers = instr->pointer_map(); LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position()); RecordPosition(pointers->position());
__ Call(code, mode); __ Call(code, mode);
RegisterLazyDeoptimization(instr, safepoint_mode); RecordSafepointWithLazyDeopt(instr, safepoint_mode);
// Signal that we don't inline smi code before these stubs in the // Signal that we don't inline smi code before these stubs in the
// optimizing code generator. // optimizing code generator.
@ -571,7 +540,7 @@ void LCodeGen::CallRuntime(const Runtime::Function* function,
RecordPosition(pointers->position()); RecordPosition(pointers->position());
__ CallRuntime(function, num_arguments); __ 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) { LInstruction* instr) {
__ CallRuntimeSaveDoubles(id); __ CallRuntimeSaveDoubles(id);
RecordSafepointWithRegisters( RecordSafepointWithRegisters(
instr->pointer_map(), argc, Safepoint::kNoDeoptimizationIndex); instr->pointer_map(), argc, Safepoint::kNoLazyDeopt);
} }
void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr, void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment,
SafepointMode safepoint_mode) { Safepoint::DeoptMode 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) {
if (!environment->HasBeenRegistered()) { if (!environment->HasBeenRegistered()) {
// Physical stack frame layout: // Physical stack frame layout:
// -x ............. -4 0 ..................................... y // -x ............. -4 0 ..................................... y
@ -632,14 +576,17 @@ void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment) {
Translation translation(&translations_, frame_count); Translation translation(&translations_, frame_count);
WriteTranslation(environment, &translation); WriteTranslation(environment, &translation);
int deoptimization_index = deoptimizations_.length(); 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); deoptimizations_.Add(environment);
} }
} }
void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) { void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) {
RegisterEnvironmentForDeoptimization(environment); RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
ASSERT(environment->HasBeenRegistered()); ASSERT(environment->HasBeenRegistered());
int id = environment->deoptimization_index(); int id = environment->deoptimization_index();
Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER); Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER);
@ -701,6 +648,7 @@ void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
data->SetTranslationIndex(i, Smi::FromInt(env->translation_index())); data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
data->SetArgumentsStackHeight(i, data->SetArgumentsStackHeight(i,
Smi::FromInt(env->arguments_stack_height())); Smi::FromInt(env->arguments_stack_height()));
data->SetPc(i, Smi::FromInt(env->pc_offset()));
} }
code->set_deoptimization_data(*data); 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( void LCodeGen::RecordSafepoint(
LPointerMap* pointers, LPointerMap* pointers,
Safepoint::Kind kind, Safepoint::Kind kind,
int arguments, int arguments,
int deoptimization_index) { Safepoint::DeoptMode deopt_mode) {
ASSERT(expected_safepoint_kind_ == kind); ASSERT(expected_safepoint_kind_ == kind);
const ZoneList<LOperand*>* operands = pointers->operands(); const ZoneList<LOperand*>* operands = pointers->operands();
Safepoint safepoint = safepoints_.DefineSafepoint(masm(), Safepoint safepoint = safepoints_.DefineSafepoint(masm(),
kind, arguments, deoptimization_index); kind, arguments, deopt_mode);
for (int i = 0; i < operands->length(); i++) { for (int i = 0; i < operands->length(); i++) {
LOperand* pointer = operands->at(i); LOperand* pointer = operands->at(i);
if (pointer->IsStackSlot()) { if (pointer->IsStackSlot()) {
@ -758,31 +718,31 @@ void LCodeGen::RecordSafepoint(
void LCodeGen::RecordSafepoint(LPointerMap* pointers, void LCodeGen::RecordSafepoint(LPointerMap* pointers,
int deoptimization_index) { Safepoint::DeoptMode deopt_mode) {
RecordSafepoint(pointers, Safepoint::kSimple, 0, deoptimization_index); 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); LPointerMap empty_pointers(RelocInfo::kNoPosition);
RecordSafepoint(&empty_pointers, deoptimization_index); RecordSafepoint(&empty_pointers, deopt_mode);
} }
void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers, void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
int arguments, int arguments,
int deoptimization_index) { Safepoint::DeoptMode deopt_mode) {
RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, RecordSafepoint(
deoptimization_index); pointers, Safepoint::kWithRegisters, arguments, deopt_mode);
} }
void LCodeGen::RecordSafepointWithRegistersAndDoubles( void LCodeGen::RecordSafepointWithRegistersAndDoubles(
LPointerMap* pointers, LPointerMap* pointers,
int arguments, int arguments,
int deoptimization_index) { Safepoint::DeoptMode deopt_mode) {
RecordSafepoint(pointers, Safepoint::kWithRegistersAndDoubles, arguments, RecordSafepoint(
deoptimization_index); pointers, Safepoint::kWithRegistersAndDoubles, arguments, deopt_mode);
} }
@ -817,12 +777,6 @@ void LCodeGen::DoGap(LGap* gap) {
LParallelMove* move = gap->GetParallelMove(inner_pos); LParallelMove* move = gap->GetParallelMove(inner_pos);
if (move != NULL) DoParallelMove(move); 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); __ CallStub(&stub);
RecordSafepointWithRegistersAndDoubles(instr->pointer_map(), RecordSafepointWithRegistersAndDoubles(instr->pointer_map(),
0, 0,
Safepoint::kNoDeoptimizationIndex); Safepoint::kNoLazyDeopt);
// Overwrite the stored value of r0 with the result of the stub. // Overwrite the stored value of r0 with the result of the stub.
__ StoreToSafepointRegistersAndDoublesSlot(r0, r0); __ StoreToSafepointRegistersAndDoublesSlot(r0, r0);
} }
@ -2014,7 +1968,7 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
LInstanceOfKnownGlobal* instr) LInstanceOfKnownGlobal* instr)
: LDeferredCode(codegen), instr_(instr) { } : LDeferredCode(codegen), instr_(instr) { }
virtual void Generate() { virtual void Generate() {
codegen()->DoDeferredLInstanceOfKnownGlobal(instr_, &map_check_); codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
} }
Label* map_check() { return &map_check_; } Label* map_check() { return &map_check_; }
@ -2082,8 +2036,8 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
} }
void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
Label* map_check) { Label* map_check) {
Register result = ToRegister(instr->result()); Register result = ToRegister(instr->result());
ASSERT(result.is(r0)); ASSERT(result.is(r0));
@ -2115,6 +2069,9 @@ void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
RelocInfo::CODE_TARGET, RelocInfo::CODE_TARGET,
instr, instr,
RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); 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 // Put the result value into the result register slot and
// restore all registers. // restore all registers.
__ StoreToSafepointRegisterSlot(result, result); __ StoreToSafepointRegisterSlot(result, result);
@ -2712,12 +2669,9 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
__ bind(&invoke); __ bind(&invoke);
ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
LPointerMap* pointers = instr->pointer_map(); LPointerMap* pointers = instr->pointer_map();
LEnvironment* env = instr->deoptimization_environment();
RecordPosition(pointers->position()); RecordPosition(pointers->position());
RegisterEnvironmentForDeoptimization(env); SafepointGenerator safepoint_generator(
SafepointGenerator safepoint_generator(this, this, pointers, Safepoint::kLazyDeopt);
pointers,
env->deoptimization_index());
// The number of arguments is stored in receiver which is r0, as expected // The number of arguments is stored in receiver which is r0, as expected
// by InvokeFunction. // by InvokeFunction.
v8::internal::ParameterCount actual(receiver); v8::internal::ParameterCount actual(receiver);
@ -2799,7 +2753,7 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
__ Call(ip); __ Call(ip);
// Setup deoptimization. // Setup deoptimization.
RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT); RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
// Restore context. // Restore context.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
@ -3163,10 +3117,8 @@ void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
ASSERT(instr->HasPointerMap()); ASSERT(instr->HasPointerMap());
ASSERT(instr->HasDeoptimizationEnvironment()); ASSERT(instr->HasDeoptimizationEnvironment());
LPointerMap* pointers = instr->pointer_map(); LPointerMap* pointers = instr->pointer_map();
LEnvironment* env = instr->deoptimization_environment();
RecordPosition(pointers->position()); RecordPosition(pointers->position());
RegisterEnvironmentForDeoptimization(env); SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
SafepointGenerator generator(this, pointers, env->deoptimization_index());
ParameterCount count(instr->arity()); ParameterCount count(instr->arity());
__ InvokeFunction(r1, count, CALL_FUNCTION, generator, CALL_AS_METHOD); __ InvokeFunction(r1, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); __ 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) { void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
// No code for lazy bailout instruction. Used to capture environment after a EnsureSpaceForLazyDeopt();
// call for populating the safepoint data with deoptimization data. 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); __ Push(object, key, strict);
ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
LPointerMap* pointers = instr->pointer_map(); LPointerMap* pointers = instr->pointer_map();
LEnvironment* env = instr->deoptimization_environment();
RecordPosition(pointers->position()); RecordPosition(pointers->position());
RegisterEnvironmentForDeoptimization(env); SafepointGenerator safepoint_generator(
SafepointGenerator safepoint_generator(this, this, pointers, Safepoint::kLazyDeopt);
pointers,
env->deoptimization_index());
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator); __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator);
} }
@ -4438,27 +4407,20 @@ void LCodeGen::DoIn(LIn* instr) {
__ Push(key, obj); __ Push(key, obj);
ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
LPointerMap* pointers = instr->pointer_map(); LPointerMap* pointers = instr->pointer_map();
LEnvironment* env = instr->deoptimization_environment();
RecordPosition(pointers->position()); RecordPosition(pointers->position());
RegisterEnvironmentForDeoptimization(env); SafepointGenerator safepoint_generator(this, pointers, Safepoint::kLazyDeopt);
SafepointGenerator safepoint_generator(this,
pointers,
env->deoptimization_index());
__ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator); __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator);
} }
void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) { void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
{ PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
__ CallRuntimeSaveDoubles(Runtime::kStackGuard); RecordSafepointWithLazyDeopt(
RegisterLazyDeoptimization( instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); ASSERT(instr->HasEnvironment());
} LEnvironment* env = instr->environment();
safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
// The gap code includes the restoring of the safepoint registers.
int pc = masm()->pc_offset();
safepoints_.SetPcAfterGap(pc);
} }
@ -4472,6 +4434,10 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) {
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()) { if (instr->hydrogen()->is_function_entry()) {
// Perform stack overflow check. // Perform stack overflow check.
Label done; Label done;
@ -4480,7 +4446,10 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) {
__ b(hs, &done); __ b(hs, &done);
StackCheckStub stub; StackCheckStub stub;
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
EnsureSpaceForLazyDeopt();
__ bind(&done); __ bind(&done);
RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
} else { } else {
ASSERT(instr->hydrogen()->is_backwards_branch()); ASSERT(instr->hydrogen()->is_backwards_branch());
// Perform stack overflow check if this goto needs it before jumping. // Perform stack overflow check if this goto needs it before jumping.
@ -4489,8 +4458,13 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) {
__ LoadRoot(ip, Heap::kStackLimitRootIndex); __ LoadRoot(ip, Heap::kStackLimitRootIndex);
__ cmp(sp, Operand(ip)); __ cmp(sp, Operand(ip));
__ b(lo, deferred_stack_check->entry()); __ b(lo, deferred_stack_check->entry());
EnsureSpaceForLazyDeopt();
__ bind(instr->done_label()); __ bind(instr->done_label());
deferred_stack_check->SetExit(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 // If the environment were already registered, we would have no way of
// backpatching it with the spill slot operands. // backpatching it with the spill slot operands.
ASSERT(!environment->HasBeenRegistered()); ASSERT(!environment->HasBeenRegistered());
RegisterEnvironmentForDeoptimization(environment); RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
ASSERT(osr_pc_offset_ == -1); ASSERT(osr_pc_offset_ == -1);
osr_pc_offset_ = masm()->pc_offset(); osr_pc_offset_ = masm()->pc_offset();
} }

30
deps/v8/src/arm/lithium-codegen-arm.h

@ -58,6 +58,7 @@ class LCodeGen BASE_EMBEDDED {
status_(UNUSED), status_(UNUSED),
deferred_(8), deferred_(8),
osr_pc_offset_(-1), osr_pc_offset_(-1),
last_lazy_deopt_pc_(0),
resolver_(this), resolver_(this),
expected_safepoint_kind_(Safepoint::kSimple) { expected_safepoint_kind_(Safepoint::kSimple) {
PopulateDeoptimizationLiteralsWithInlinedFunctions(); PopulateDeoptimizationLiteralsWithInlinedFunctions();
@ -111,8 +112,8 @@ class LCodeGen BASE_EMBEDDED {
void DoDeferredStackCheck(LStackCheck* instr); void DoDeferredStackCheck(LStackCheck* instr);
void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr); void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
void DoDeferredStringCharFromCode(LStringCharFromCode* instr); void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
void DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
Label* map_check); Label* map_check);
// Parallel move support. // Parallel move support.
void DoParallelMove(LParallelMove* move); void DoParallelMove(LParallelMove* move);
@ -148,7 +149,7 @@ class LCodeGen BASE_EMBEDDED {
HGraph* graph() const { return chunk_->graph(); } HGraph* graph() const { return chunk_->graph(); }
Register scratch0() { return r9; } Register scratch0() { return r9; }
DwVfpRegister double_scratch0() { return d15; } DwVfpRegister double_scratch0() { return kScratchDoubleReg; }
int GetNextEmittedBlock(int block); int GetNextEmittedBlock(int block);
LInstruction* GetNextInstruction(); LInstruction* GetNextInstruction();
@ -214,10 +215,11 @@ class LCodeGen BASE_EMBEDDED {
void LoadHeapObject(Register result, Handle<HeapObject> object); void LoadHeapObject(Register result, Handle<HeapObject> object);
void RegisterLazyDeoptimization(LInstruction* instr, void RecordSafepointWithLazyDeopt(LInstruction* instr,
SafepointMode safepoint_mode); SafepointMode safepoint_mode);
void RegisterEnvironmentForDeoptimization(LEnvironment* environment); void RegisterEnvironmentForDeoptimization(LEnvironment* environment,
Safepoint::DeoptMode mode);
void DeoptimizeIf(Condition cc, LEnvironment* environment); void DeoptimizeIf(Condition cc, LEnvironment* environment);
void AddToTranslation(Translation* translation, void AddToTranslation(Translation* translation,
@ -246,19 +248,16 @@ class LCodeGen BASE_EMBEDDED {
void RecordSafepoint(LPointerMap* pointers, void RecordSafepoint(LPointerMap* pointers,
Safepoint::Kind kind, Safepoint::Kind kind,
int arguments, int arguments,
int deoptimization_index); Safepoint::DeoptMode mode);
void RecordSafepoint(LPointerMap* pointers, int deoptimization_index); void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode);
void RecordSafepoint(int deoptimization_index); void RecordSafepoint(Safepoint::DeoptMode mode);
void RecordSafepointWithRegisters(LPointerMap* pointers, void RecordSafepointWithRegisters(LPointerMap* pointers,
int arguments, int arguments,
int deoptimization_index); Safepoint::DeoptMode mode);
void RecordSafepointWithRegistersAndDoubles(LPointerMap* pointers, void RecordSafepointWithRegistersAndDoubles(LPointerMap* pointers,
int arguments, int arguments,
int deoptimization_index); Safepoint::DeoptMode mode);
void RecordPosition(int position); void RecordPosition(int position);
int LastSafepointEnd() {
return static_cast<int>(safepoints_.GetPcAfterGap());
}
static Condition TokenToCondition(Token::Value op, bool is_unsigned); static Condition TokenToCondition(Token::Value op, bool is_unsigned);
void EmitGoto(int block); void EmitGoto(int block);
@ -300,6 +299,8 @@ class LCodeGen BASE_EMBEDDED {
Address address; Address address;
}; };
void EnsureSpaceForLazyDeopt();
LChunk* const chunk_; LChunk* const chunk_;
MacroAssembler* const masm_; MacroAssembler* const masm_;
CompilationInfo* const info_; CompilationInfo* const info_;
@ -316,6 +317,7 @@ class LCodeGen BASE_EMBEDDED {
TranslationBuffer translations_; TranslationBuffer translations_;
ZoneList<LDeferredCode*> deferred_; ZoneList<LDeferredCode*> deferred_;
int osr_pc_offset_; int osr_pc_offset_;
int last_lazy_deopt_pc_;
// Builder that keeps track of safepoints in the code. The table // Builder that keeps track of safepoints in the code. The table
// itself is emitted at the end of the generated code. // itself is emitted at the end of the generated code.

21
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 // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
// met: // met:
@ -34,7 +34,6 @@ namespace v8 {
namespace internal { namespace internal {
static const Register kSavedValueRegister = { 9 }; static const Register kSavedValueRegister = { 9 };
static const DoubleRegister kSavedDoubleValueRegister = { 0 };
LGapResolver::LGapResolver(LCodeGen* owner) LGapResolver::LGapResolver(LCodeGen* owner)
: cgen_(owner), moves_(32), root_index_(0), in_cycle_(false), : cgen_(owner), moves_(32), root_index_(0), in_cycle_(false),
@ -172,9 +171,9 @@ void LGapResolver::BreakCycle(int index) {
} else if (source->IsStackSlot()) { } else if (source->IsStackSlot()) {
__ ldr(kSavedValueRegister, cgen_->ToMemOperand(source)); __ ldr(kSavedValueRegister, cgen_->ToMemOperand(source));
} else if (source->IsDoubleRegister()) { } else if (source->IsDoubleRegister()) {
__ vmov(kSavedDoubleValueRegister, cgen_->ToDoubleRegister(source)); __ vmov(kScratchDoubleReg, cgen_->ToDoubleRegister(source));
} else if (source->IsDoubleStackSlot()) { } else if (source->IsDoubleStackSlot()) {
__ vldr(kSavedDoubleValueRegister, cgen_->ToMemOperand(source)); __ vldr(kScratchDoubleReg, cgen_->ToMemOperand(source));
} else { } else {
UNREACHABLE(); UNREACHABLE();
} }
@ -193,11 +192,9 @@ void LGapResolver::RestoreValue() {
} else if (saved_destination_->IsStackSlot()) { } else if (saved_destination_->IsStackSlot()) {
__ str(kSavedValueRegister, cgen_->ToMemOperand(saved_destination_)); __ str(kSavedValueRegister, cgen_->ToMemOperand(saved_destination_));
} else if (saved_destination_->IsDoubleRegister()) { } else if (saved_destination_->IsDoubleRegister()) {
__ vmov(cgen_->ToDoubleRegister(saved_destination_), __ vmov(cgen_->ToDoubleRegister(saved_destination_), kScratchDoubleReg);
kSavedDoubleValueRegister);
} else if (saved_destination_->IsDoubleStackSlot()) { } else if (saved_destination_->IsDoubleStackSlot()) {
__ vstr(kSavedDoubleValueRegister, __ vstr(kScratchDoubleReg, cgen_->ToMemOperand(saved_destination_));
cgen_->ToMemOperand(saved_destination_));
} else { } else {
UNREACHABLE(); UNREACHABLE();
} }
@ -235,8 +232,8 @@ void LGapResolver::EmitMove(int index) {
// ip is overwritten while saving the value to the destination. // 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 // 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. // destroys ip, since that happens before the value is read.
__ vldr(kSavedDoubleValueRegister.low(), source_operand); __ vldr(kScratchDoubleReg.low(), source_operand);
__ vstr(kSavedDoubleValueRegister.low(), destination_operand); __ vstr(kScratchDoubleReg.low(), destination_operand);
} else { } else {
__ ldr(ip, source_operand); __ ldr(ip, source_operand);
__ str(ip, destination_operand); __ str(ip, destination_operand);
@ -286,8 +283,8 @@ void LGapResolver::EmitMove(int index) {
__ ldr(kSavedValueRegister, source_high_operand); __ ldr(kSavedValueRegister, source_high_operand);
__ str(kSavedValueRegister, destination_high_operand); __ str(kSavedValueRegister, destination_high_operand);
} else { } else {
__ vldr(kSavedDoubleValueRegister, source_operand); __ vldr(kScratchDoubleReg, source_operand);
__ vstr(kSavedDoubleValueRegister, destination_operand); __ vstr(kScratchDoubleReg, destination_operand);
} }
} }
} else { } else {

18
deps/v8/src/deoptimizer.cc

@ -112,25 +112,11 @@ DeoptimizedFrameInfo* Deoptimizer::DebuggerInspectableFrame(
// Get the function and code from the frame. // Get the function and code from the frame.
JSFunction* function = JSFunction::cast(frame->function()); JSFunction* function = JSFunction::cast(frame->function());
Code* code = frame->LookupCode(); 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 // 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. // return address must be at a place in the code with deoptimization support.
int deoptimization_index = Safepoint::kNoDeoptimizationIndex; SafepointEntry safepoint_entry = code->GetSafepointEntry(frame->pc());
// Scope this as the safe point constructor will disallow allocation. int deoptimization_index = safepoint_entry.deoptimization_index();
{
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;
}
}
}
ASSERT(deoptimization_index != Safepoint::kNoDeoptimizationIndex); ASSERT(deoptimization_index != Safepoint::kNoDeoptimizationIndex);
// Always use the actual stack slots when calculating the fp to sp // Always use the actual stack slots when calculating the fp to sp

1
deps/v8/src/hydrogen-instructions.h

@ -4058,6 +4058,7 @@ class HRegExpLiteral: public HMaterializedLiteral<1> {
pattern_(pattern), pattern_(pattern),
flags_(flags) { flags_(flags) {
SetOperandAt(0, context); SetOperandAt(0, context);
SetAllSideEffects();
} }
HValue* context() { return OperandAt(0); } HValue* context() { return OperandAt(0); }

6
deps/v8/src/ia32/code-stubs-ia32.cc

@ -5665,14 +5665,12 @@ void StringHelper::GenerateHashGetHash(MacroAssembler* masm,
__ shl(scratch, 15); __ shl(scratch, 15);
__ add(hash, Operand(scratch)); __ add(hash, Operand(scratch));
uint32_t kHashShiftCutOffMask = (1 << (32 - String::kHashShift)) - 1; __ and_(hash, String::kHashBitMask);
__ and_(hash, kHashShiftCutOffMask);
// if (hash == 0) hash = 27; // if (hash == 0) hash = 27;
Label hash_not_zero; Label hash_not_zero;
__ test(hash, Operand(hash));
__ j(not_zero, &hash_not_zero, Label::kNear); __ j(not_zero, &hash_not_zero, Label::kNear);
__ mov(hash, Immediate(27)); __ mov(hash, Immediate(StringHasher::kZeroHash));
__ bind(&hash_not_zero); __ bind(&hash_not_zero);
} }

116
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> code) { void Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code) {
Isolate* isolate = code->GetIsolate(); Isolate* isolate = code->GetIsolate();
HandleScope scope(isolate); HandleScope scope(isolate);
@ -62,30 +52,23 @@ void Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code) {
// Compute the size of relocation information needed for the code // Compute the size of relocation information needed for the code
// patching in Deoptimizer::DeoptimizeFunction. // patching in Deoptimizer::DeoptimizeFunction.
int min_reloc_size = 0; int min_reloc_size = 0;
Address prev_reloc_address = code->instruction_start(); int prev_pc_offset = 0;
Address code_start_address = code->instruction_start(); DeoptimizationInputData* deopt_data =
SafepointTable table(*code); DeoptimizationInputData::cast(code->deoptimization_data());
for (unsigned i = 0; i < table.length(); ++i) { for (int i = 0; i < deopt_data->DeoptCount(); i++) {
Address curr_reloc_address = code_start_address + table.GetPcOffset(i); int pc_offset = deopt_data->Pc(i)->value();
ASSERT_GE(curr_reloc_address, prev_reloc_address); if (pc_offset == -1) continue;
SafepointEntry safepoint_entry = table.GetEntry(i); ASSERT_GE(pc_offset, prev_pc_offset);
int deoptimization_index = safepoint_entry.deoptimization_index(); int pc_delta = pc_offset - prev_pc_offset;
if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) { // We use RUNTIME_ENTRY reloc info which has a size of 2 bytes
// The gap code is needed to get to the state expected at the // if encodable with small pc delta encoding and up to 6 bytes
// bailout and we need to skip the call opcode to get to the // otherwise.
// address that needs reloc. if (pc_delta <= RelocInfo::kMaxSmallPCDelta) {
curr_reloc_address += safepoint_entry.gap_code_size() + 1; min_reloc_size += 2;
int pc_delta = curr_reloc_address - prev_reloc_address; } else {
// We use RUNTIME_ENTRY reloc info which has a size of 2 bytes min_reloc_size += 6;
// 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;
} }
prev_pc_offset = pc_offset;
} }
// If the relocation information is not big enough we create a new // 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(); Address reloc_end_address = reloc_info->address() + reloc_info->Size();
RelocInfoWriter reloc_info_writer(reloc_end_address, code_start_address); RelocInfoWriter reloc_info_writer(reloc_end_address, code_start_address);
// For each return after a safepoint insert a call to the corresponding // For each LLazyBailout instruction insert a call to the corresponding
// deoptimization entry. Since the call is a relative encoding, write new // 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 // 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). // existing code will not be used again (we zap it in debug builds).
SafepointTable table(code); //
Address prev_address = code_start_address; // Emit call to lazy deoptimization at all lazy deopt points.
for (unsigned i = 0; i < table.length(); ++i) { DeoptimizationInputData* deopt_data =
Address curr_address = code_start_address + table.GetPcOffset(i); DeoptimizationInputData::cast(code->deoptimization_data());
ASSERT_GE(curr_address, prev_address); #ifdef DEBUG
ZapCodeRange(prev_address, curr_address); Address prev_call_address = NULL;
#endif
SafepointEntry safepoint_entry = table.GetEntry(i); for (int i = 0; i < deopt_data->DeoptCount(); i++) {
int deoptimization_index = safepoint_entry.deoptimization_index(); if (deopt_data->Pc(i)->value() == -1) continue;
if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) { // Patch lazy deoptimization entry.
// The gap code is needed to get to the state expected at the bailout. Address call_address = code_start_address + deopt_data->Pc(i)->value();
curr_address += safepoint_entry.gap_code_size(); CodePatcher patcher(call_address, patch_size());
Address deopt_entry = GetDeoptimizationEntry(i, LAZY);
CodePatcher patcher(curr_address, patch_size()); patcher.masm()->call(deopt_entry, RelocInfo::NONE);
Address deopt_entry = GetDeoptimizationEntry(deoptimization_index, LAZY); // We use RUNTIME_ENTRY for deoptimization bailouts.
patcher.masm()->call(deopt_entry, RelocInfo::NONE); RelocInfo rinfo(call_address + 1, // 1 after the call opcode.
RelocInfo::RUNTIME_ENTRY,
// We use RUNTIME_ENTRY for deoptimization bailouts. reinterpret_cast<intptr_t>(deopt_entry));
RelocInfo rinfo(curr_address + 1, // 1 after the call opcode. reloc_info_writer.Write(&rinfo);
RelocInfo::RUNTIME_ENTRY, ASSERT_GE(reloc_info_writer.pos(),
reinterpret_cast<intptr_t>(deopt_entry)); reloc_info->address() + ByteArray::kHeaderSize);
reloc_info_writer.Write(&rinfo); ASSERT(prev_call_address == NULL ||
ASSERT_GE(reloc_info_writer.pos(), call_address >= prev_call_address + patch_size());
reloc_info->address() + ByteArray::kHeaderSize); ASSERT(call_address + patch_size() <= code->instruction_end());
curr_address += patch_size(); #ifdef DEBUG
} prev_call_address = call_address;
prev_address = curr_address; #endif
} }
ZapCodeRange(prev_address,
code_start_address + code->safepoint_table_offset());
// Move the relocation info to the beginning of the byte array. // Move the relocation info to the beginning of the byte array.
int new_reloc_size = reloc_end_address - reloc_info_writer.pos(); int new_reloc_size = reloc_end_address - reloc_info_writer.pos();
@ -212,11 +195,6 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
PrintF("[forced deoptimization: "); PrintF("[forced deoptimization: ");
function->PrintName(); function->PrintName();
PrintF(" / %x]\n", reinterpret_cast<uint32_t>(function)); PrintF(" / %x]\n", reinterpret_cast<uint32_t>(function));
#ifdef DEBUG
if (FLAG_print_code) {
code->PrintLn();
}
#endif
} }
} }

212
deps/v8/src/ia32/lithium-codegen-ia32.cc

@ -44,22 +44,22 @@ class SafepointGenerator : public CallWrapper {
public: public:
SafepointGenerator(LCodeGen* codegen, SafepointGenerator(LCodeGen* codegen,
LPointerMap* pointers, LPointerMap* pointers,
int deoptimization_index) Safepoint::DeoptMode mode)
: codegen_(codegen), : codegen_(codegen),
pointers_(pointers), pointers_(pointers),
deoptimization_index_(deoptimization_index) {} deopt_mode_(mode) {}
virtual ~SafepointGenerator() { } virtual ~SafepointGenerator() { }
virtual void BeforeCall(int call_size) const {} virtual void BeforeCall(int call_size) const {}
virtual void AfterCall() const { virtual void AfterCall() const {
codegen_->RecordSafepoint(pointers_, deoptimization_index_); codegen_->RecordSafepoint(pointers_, deopt_mode_);
} }
private: private:
LCodeGen* codegen_; LCodeGen* codegen_;
LPointerMap* pointers_; LPointerMap* pointers_;
int deoptimization_index_; Safepoint::DeoptMode deopt_mode_;
}; };
@ -187,7 +187,7 @@ bool LCodeGen::GeneratePrologue() {
} else { } else {
__ CallRuntime(Runtime::kNewFunctionContext, 1); __ CallRuntime(Runtime::kNewFunctionContext, 1);
} }
RecordSafepoint(Safepoint::kNoDeoptimizationIndex); RecordSafepoint(Safepoint::kNoLazyDeopt);
// Context is returned in both eax and esi. It replaces the context // 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. // passed to us. It's saved in the stack and kept live in esi.
__ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
@ -241,19 +241,11 @@ bool LCodeGen::GenerateBody() {
instr->CompileToNative(this); instr->CompileToNative(this);
} }
} }
EnsureSpaceForLazyDeopt();
return !is_aborted(); return !is_aborted();
} }
LInstruction* LCodeGen::GetNextInstruction() {
if (current_instruction_ < instructions_->length() - 1) {
return instructions_->at(current_instruction_ + 1);
} else {
return NULL;
}
}
bool LCodeGen::GenerateDeferredCode() { bool LCodeGen::GenerateDeferredCode() {
ASSERT(is_generating()); ASSERT(is_generating());
if (deferred_.length() > 0) { if (deferred_.length() > 0) {
@ -263,13 +255,6 @@ bool LCodeGen::GenerateDeferredCode() {
code->Generate(); code->Generate();
__ jmp(code->exit()); __ 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 // Deferred code is the last part of the instruction sequence. Mark
@ -442,10 +427,8 @@ void LCodeGen::CallCodeGeneric(Handle<Code> code,
ASSERT(instr != NULL); ASSERT(instr != NULL);
LPointerMap* pointers = instr->pointer_map(); LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position()); RecordPosition(pointers->position());
__ call(code, mode); __ call(code, mode);
RecordSafepointWithLazyDeopt(instr, safepoint_mode);
RegisterLazyDeoptimization(instr, safepoint_mode);
// Signal that we don't inline smi code before these stubs in the // Signal that we don't inline smi code before these stubs in the
// optimizing code generator. // optimizing code generator.
@ -473,7 +456,7 @@ void LCodeGen::CallRuntime(const Runtime::Function* fun,
__ CallRuntime(fun, argc); __ 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); __ CallRuntimeSaveDoubles(id);
RecordSafepointWithRegisters( RecordSafepointWithRegisters(
instr->pointer_map(), argc, Safepoint::kNoDeoptimizationIndex); instr->pointer_map(), argc, Safepoint::kNoLazyDeopt);
} }
void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr, void LCodeGen::RegisterEnvironmentForDeoptimization(
SafepointMode safepoint_mode) { LEnvironment* environment, Safepoint::DeoptMode 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) {
if (!environment->HasBeenRegistered()) { if (!environment->HasBeenRegistered()) {
// Physical stack frame layout: // Physical stack frame layout:
// -x ............. -4 0 ..................................... y // -x ............. -4 0 ..................................... y
@ -545,14 +503,17 @@ void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment) {
Translation translation(&translations_, frame_count); Translation translation(&translations_, frame_count);
WriteTranslation(environment, &translation); WriteTranslation(environment, &translation);
int deoptimization_index = deoptimizations_.length(); 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); deoptimizations_.Add(environment);
} }
} }
void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) { void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) {
RegisterEnvironmentForDeoptimization(environment); RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
ASSERT(environment->HasBeenRegistered()); ASSERT(environment->HasBeenRegistered());
int id = environment->deoptimization_index(); int id = environment->deoptimization_index();
Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER); Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER);
@ -632,6 +593,7 @@ void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
data->SetTranslationIndex(i, Smi::FromInt(env->translation_index())); data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
data->SetArgumentsStackHeight(i, data->SetArgumentsStackHeight(i,
Smi::FromInt(env->arguments_stack_height())); Smi::FromInt(env->arguments_stack_height()));
data->SetPc(i, Smi::FromInt(env->pc_offset()));
} }
code->set_deoptimization_data(*data); 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( void LCodeGen::RecordSafepoint(
LPointerMap* pointers, LPointerMap* pointers,
Safepoint::Kind kind, Safepoint::Kind kind,
int arguments, int arguments,
int deoptimization_index) { Safepoint::DeoptMode deopt_mode) {
ASSERT(kind == expected_safepoint_kind_); ASSERT(kind == expected_safepoint_kind_);
const ZoneList<LOperand*>* operands = pointers->operands(); const ZoneList<LOperand*>* operands = pointers->operands();
Safepoint safepoint = safepoints_.DefineSafepoint(masm(), Safepoint safepoint =
kind, arguments, deoptimization_index); safepoints_.DefineSafepoint(masm(), kind, arguments, deopt_mode);
for (int i = 0; i < operands->length(); i++) { for (int i = 0; i < operands->length(); i++) {
LOperand* pointer = operands->at(i); LOperand* pointer = operands->at(i);
if (pointer->IsStackSlot()) { if (pointer->IsStackSlot()) {
@ -684,22 +658,21 @@ void LCodeGen::RecordSafepoint(
void LCodeGen::RecordSafepoint(LPointerMap* pointers, void LCodeGen::RecordSafepoint(LPointerMap* pointers,
int deoptimization_index) { Safepoint::DeoptMode mode) {
RecordSafepoint(pointers, Safepoint::kSimple, 0, deoptimization_index); RecordSafepoint(pointers, Safepoint::kSimple, 0, mode);
} }
void LCodeGen::RecordSafepoint(int deoptimization_index) { void LCodeGen::RecordSafepoint(Safepoint::DeoptMode mode) {
LPointerMap empty_pointers(RelocInfo::kNoPosition); LPointerMap empty_pointers(RelocInfo::kNoPosition);
RecordSafepoint(&empty_pointers, deoptimization_index); RecordSafepoint(&empty_pointers, mode);
} }
void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers, void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
int arguments, int arguments,
int deoptimization_index) { Safepoint::DeoptMode mode) {
RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, mode);
deoptimization_index);
} }
@ -734,12 +707,6 @@ void LCodeGen::DoGap(LGap* gap) {
LParallelMove* move = gap->GetParallelMove(inner_pos); LParallelMove* move = gap->GetParallelMove(inner_pos);
if (move != NULL) DoParallelMove(move); 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) LInstanceOfKnownGlobal* instr)
: LDeferredCode(codegen), instr_(instr) { } : LDeferredCode(codegen), instr_(instr) { }
virtual void Generate() { virtual void Generate() {
codegen()->DoDeferredLInstanceOfKnownGlobal(instr_, &map_check_); codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
} }
Label* map_check() { return &map_check_; } Label* map_check() { return &map_check_; }
@ -1905,8 +1872,8 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
} }
void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
Label* map_check) { Label* map_check) {
PushSafepointRegistersScope scope(this); PushSafepointRegistersScope scope(this);
InstanceofStub::Flags flags = InstanceofStub::kNoFlags; InstanceofStub::Flags flags = InstanceofStub::kNoFlags;
@ -1933,6 +1900,10 @@ void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
RelocInfo::CODE_TARGET, RelocInfo::CODE_TARGET,
instr, instr,
RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); 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. // Put the result value into the eax slot and restore all registers.
__ StoreToSafepointRegisterSlot(eax, eax); __ StoreToSafepointRegisterSlot(eax, eax);
} }
@ -2502,12 +2473,9 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
__ bind(&invoke); __ bind(&invoke);
ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
LPointerMap* pointers = instr->pointer_map(); LPointerMap* pointers = instr->pointer_map();
LEnvironment* env = instr->deoptimization_environment();
RecordPosition(pointers->position()); RecordPosition(pointers->position());
RegisterEnvironmentForDeoptimization(env); SafepointGenerator safepoint_generator(
SafepointGenerator safepoint_generator(this, this, pointers, Safepoint::kLazyDeopt);
pointers,
env->deoptimization_index());
ParameterCount actual(eax); ParameterCount actual(eax);
__ InvokeFunction(function, actual, CALL_FUNCTION, __ InvokeFunction(function, actual, CALL_FUNCTION,
safepoint_generator, CALL_AS_METHOD); safepoint_generator, CALL_AS_METHOD);
@ -2590,8 +2558,7 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
__ call(FieldOperand(edi, JSFunction::kCodeEntryOffset)); __ call(FieldOperand(edi, JSFunction::kCodeEntryOffset));
} }
// Setup deoptimization. RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT);
} }
@ -2966,10 +2933,9 @@ void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
ASSERT(instr->HasPointerMap()); ASSERT(instr->HasPointerMap());
ASSERT(instr->HasDeoptimizationEnvironment()); ASSERT(instr->HasDeoptimizationEnvironment());
LPointerMap* pointers = instr->pointer_map(); LPointerMap* pointers = instr->pointer_map();
LEnvironment* env = instr->deoptimization_environment();
RecordPosition(pointers->position()); RecordPosition(pointers->position());
RegisterEnvironmentForDeoptimization(env); SafepointGenerator generator(
SafepointGenerator generator(this, pointers, env->deoptimization_index()); this, pointers, Safepoint::kLazyDeopt);
ParameterCount count(instr->arity()); ParameterCount count(instr->arity());
__ InvokeFunction(edi, count, CALL_FUNCTION, generator, CALL_AS_METHOD); __ InvokeFunction(edi, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
} }
@ -3463,7 +3429,7 @@ void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) {
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
__ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
RecordSafepointWithRegisters( RecordSafepointWithRegisters(
instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
if (!reg.is(eax)) __ mov(reg, eax); if (!reg.is(eax)) __ mov(reg, eax);
// Done. Put the value in xmm0 into the value of the allocated heap // 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. // not have easy access to the local context.
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
__ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
RecordSafepointWithRegisters(instr->pointer_map(), 0, RecordSafepointWithRegisters(
Safepoint::kNoDeoptimizationIndex); instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
__ StoreToSafepointRegisterSlot(reg, eax); __ 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) { void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
// No code for lazy bailout instruction. Used to capture environment after a EnsureSpaceForLazyDeopt();
// call for populating the safepoint data with deoptimization data. 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()); ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
LPointerMap* pointers = instr->pointer_map(); LPointerMap* pointers = instr->pointer_map();
LEnvironment* env = instr->deoptimization_environment();
RecordPosition(pointers->position()); RecordPosition(pointers->position());
RegisterEnvironmentForDeoptimization(env);
// Create safepoint generator that will also ensure enough space in the // Create safepoint generator that will also ensure enough space in the
// reloc info for patching in deoptimization (since this is invoking a // reloc info for patching in deoptimization (since this is invoking a
// builtin) // builtin)
SafepointGenerator safepoint_generator(this, SafepointGenerator safepoint_generator(
pointers, this, pointers, Safepoint::kLazyDeopt);
env->deoptimization_index());
__ push(Immediate(Smi::FromInt(strict_mode_flag()))); __ push(Immediate(Smi::FromInt(strict_mode_flag())));
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator); __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator);
} }
void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) { void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
{ PushSafepointRegistersScope scope(this);
PushSafepointRegistersScope scope(this); __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
__ CallRuntimeSaveDoubles(Runtime::kStackGuard); RecordSafepointWithLazyDeopt(
RegisterLazyDeoptimization( instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); ASSERT(instr->HasEnvironment());
} LEnvironment* env = instr->environment();
safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
// The gap code includes the restoring of the safepoint registers.
int pc = masm()->pc_offset();
safepoints_.SetPcAfterGap(pc);
} }
@ -4307,6 +4285,10 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) {
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()) { if (instr->hydrogen()->is_function_entry()) {
// Perform stack overflow check. // Perform stack overflow check.
Label done; Label done;
@ -4319,7 +4301,10 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) {
ASSERT(ToRegister(instr->context()).is(esi)); ASSERT(ToRegister(instr->context()).is(esi));
StackCheckStub stub; StackCheckStub stub;
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
EnsureSpaceForLazyDeopt();
__ bind(&done); __ bind(&done);
RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
} else { } else {
ASSERT(instr->hydrogen()->is_backwards_branch()); ASSERT(instr->hydrogen()->is_backwards_branch());
// Perform stack overflow check if this goto needs it before jumping. // 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()); ExternalReference::address_of_stack_limit(isolate());
__ cmp(esp, Operand::StaticVariable(stack_limit)); __ cmp(esp, Operand::StaticVariable(stack_limit));
__ j(below, deferred_stack_check->entry()); __ j(below, deferred_stack_check->entry());
EnsureSpaceForLazyDeopt();
__ bind(instr->done_label()); __ bind(instr->done_label());
deferred_stack_check->SetExit(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 // If the environment were already registered, we would have no way of
// backpatching it with the spill slot operands. // backpatching it with the spill slot operands.
ASSERT(!environment->HasBeenRegistered()); ASSERT(!environment->HasBeenRegistered());
RegisterEnvironmentForDeoptimization(environment); RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
ASSERT(osr_pc_offset_ == -1); ASSERT(osr_pc_offset_ == -1);
osr_pc_offset_ = masm()->pc_offset(); osr_pc_offset_ = masm()->pc_offset();
} }
@ -4367,15 +4357,9 @@ void LCodeGen::DoIn(LIn* instr) {
} }
ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
LPointerMap* pointers = instr->pointer_map(); LPointerMap* pointers = instr->pointer_map();
LEnvironment* env = instr->deoptimization_environment();
RecordPosition(pointers->position()); RecordPosition(pointers->position());
RegisterEnvironmentForDeoptimization(env); SafepointGenerator safepoint_generator(
// Create safepoint generator that will also ensure enough space in the this, pointers, Safepoint::kLazyDeopt);
// reloc info for patching in deoptimization (since this is invoking a
// builtin)
SafepointGenerator safepoint_generator(this,
pointers,
env->deoptimization_index());
__ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator); __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator);
} }

34
deps/v8/src/ia32/lithium-codegen-ia32.h

@ -60,7 +60,7 @@ class LCodeGen BASE_EMBEDDED {
status_(UNUSED), status_(UNUSED),
deferred_(8), deferred_(8),
osr_pc_offset_(-1), osr_pc_offset_(-1),
deoptimization_reloc_size(), last_lazy_deopt_pc_(0),
resolver_(this), resolver_(this),
expected_safepoint_kind_(Safepoint::kSimple) { expected_safepoint_kind_(Safepoint::kSimple) {
PopulateDeoptimizationLiteralsWithInlinedFunctions(); PopulateDeoptimizationLiteralsWithInlinedFunctions();
@ -100,8 +100,8 @@ class LCodeGen BASE_EMBEDDED {
void DoDeferredStackCheck(LStackCheck* instr); void DoDeferredStackCheck(LStackCheck* instr);
void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr); void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
void DoDeferredStringCharFromCode(LStringCharFromCode* instr); void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
void DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
Label* map_check); Label* map_check);
// Parallel move support. // Parallel move support.
void DoParallelMove(LParallelMove* move); void DoParallelMove(LParallelMove* move);
@ -139,7 +139,6 @@ class LCodeGen BASE_EMBEDDED {
HGraph* graph() const { return chunk_->graph(); } HGraph* graph() const { return chunk_->graph(); }
int GetNextEmittedBlock(int block); int GetNextEmittedBlock(int block);
LInstruction* GetNextInstruction();
void EmitClassOfTest(Label* if_true, void EmitClassOfTest(Label* if_true,
Label* if_false, Label* if_false,
@ -205,10 +204,11 @@ class LCodeGen BASE_EMBEDDED {
void LoadHeapObject(Register result, Handle<HeapObject> object); void LoadHeapObject(Register result, Handle<HeapObject> object);
void RegisterLazyDeoptimization(LInstruction* instr, void RecordSafepointWithLazyDeopt(LInstruction* instr,
SafepointMode safepoint_mode); SafepointMode safepoint_mode);
void RegisterEnvironmentForDeoptimization(LEnvironment* environment); void RegisterEnvironmentForDeoptimization(LEnvironment* environment,
Safepoint::DeoptMode mode);
void DeoptimizeIf(Condition cc, LEnvironment* environment); void DeoptimizeIf(Condition cc, LEnvironment* environment);
void AddToTranslation(Translation* translation, void AddToTranslation(Translation* translation,
@ -242,16 +242,13 @@ class LCodeGen BASE_EMBEDDED {
void RecordSafepoint(LPointerMap* pointers, void RecordSafepoint(LPointerMap* pointers,
Safepoint::Kind kind, Safepoint::Kind kind,
int arguments, int arguments,
int deoptimization_index); Safepoint::DeoptMode mode);
void RecordSafepoint(LPointerMap* pointers, int deoptimization_index); void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode);
void RecordSafepoint(int deoptimization_index); void RecordSafepoint(Safepoint::DeoptMode mode);
void RecordSafepointWithRegisters(LPointerMap* pointers, void RecordSafepointWithRegisters(LPointerMap* pointers,
int arguments, int arguments,
int deoptimization_index); Safepoint::DeoptMode mode);
void RecordPosition(int position); void RecordPosition(int position);
int LastSafepointEnd() {
return static_cast<int>(safepoints_.GetPcAfterGap());
}
static Condition TokenToCondition(Token::Value op, bool is_unsigned); static Condition TokenToCondition(Token::Value op, bool is_unsigned);
void EmitGoto(int block); void EmitGoto(int block);
@ -284,6 +281,7 @@ class LCodeGen BASE_EMBEDDED {
Register object, Register object,
Handle<Map> type, Handle<Map> type,
Handle<String> name); Handle<String> name);
void EnsureSpaceForLazyDeopt();
LChunk* const chunk_; LChunk* const chunk_;
MacroAssembler* const masm_; MacroAssembler* const masm_;
@ -300,13 +298,7 @@ class LCodeGen BASE_EMBEDDED {
TranslationBuffer translations_; TranslationBuffer translations_;
ZoneList<LDeferredCode*> deferred_; ZoneList<LDeferredCode*> deferred_;
int osr_pc_offset_; int osr_pc_offset_;
int last_lazy_deopt_pc_;
struct DeoptimizationRelocSize {
int min_size;
int last_pc_offset;
};
DeoptimizationRelocSize deoptimization_reloc_size;
// Builder that keeps track of safepoints in the code. The table // Builder that keeps track of safepoints in the code. The table
// itself is emitted at the end of the generated code. // itself is emitted at the end of the generated code.

10
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> { class LLazyBailout: public LTemplateInstruction<0, 0, 0> {
public: public:
LLazyBailout() : gap_instructions_size_(0) { }
DECLARE_CONCRETE_INSTRUCTION(LazyBailout, "lazy-bailout") 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_;
}; };

8
deps/v8/src/lithium.h

@ -442,6 +442,7 @@ class LEnvironment: public ZoneObject {
translation_index_(-1), translation_index_(-1),
ast_id_(ast_id), ast_id_(ast_id),
parameter_count_(parameter_count), parameter_count_(parameter_count),
pc_offset_(-1),
values_(value_count), values_(value_count),
representations_(value_count), representations_(value_count),
spilled_registers_(NULL), spilled_registers_(NULL),
@ -455,6 +456,7 @@ class LEnvironment: public ZoneObject {
int translation_index() const { return translation_index_; } int translation_index() const { return translation_index_; }
int ast_id() const { return ast_id_; } int ast_id() const { return ast_id_; }
int parameter_count() const { return parameter_count_; } int parameter_count() const { return parameter_count_; }
int pc_offset() const { return pc_offset_; }
LOperand** spilled_registers() const { return spilled_registers_; } LOperand** spilled_registers() const { return spilled_registers_; }
LOperand** spilled_double_registers() const { LOperand** spilled_double_registers() const {
return spilled_double_registers_; return spilled_double_registers_;
@ -471,10 +473,13 @@ class LEnvironment: public ZoneObject {
return representations_[index].IsTagged(); 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()); ASSERT(!HasBeenRegistered());
deoptimization_index_ = deoptimization_index; deoptimization_index_ = deoptimization_index;
translation_index_ = translation_index; translation_index_ = translation_index;
pc_offset_ = pc_offset;
} }
bool HasBeenRegistered() const { bool HasBeenRegistered() const {
return deoptimization_index_ != Safepoint::kNoDeoptimizationIndex; return deoptimization_index_ != Safepoint::kNoDeoptimizationIndex;
@ -495,6 +500,7 @@ class LEnvironment: public ZoneObject {
int translation_index_; int translation_index_;
int ast_id_; int ast_id_;
int parameter_count_; int parameter_count_;
int pc_offset_;
ZoneList<LOperand*> values_; ZoneList<LOperand*> values_;
ZoneList<Representation> representations_; ZoneList<Representation> representations_;

2
deps/v8/src/mips/code-stubs-mips.cc

@ -5607,7 +5607,7 @@ void StringHelper::GenerateHashAddCharacter(MacroAssembler* masm,
void StringHelper::GenerateHashGetHash(MacroAssembler* masm, void StringHelper::GenerateHashGetHash(MacroAssembler* masm,
Register hash) { Register hash) {
// hash += hash << 3; // hash += hash << 3;
__ sll(at, hash, 3); __ sll(at, hash, 3);
__ addu(hash, hash, at); __ addu(hash, hash, at);

11
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); PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count);
if (0 == deopt_count) return; 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" : ""); FLAG_print_code_verbose ? "commands" : "");
for (int i = 0; i < deopt_count; i++) { for (int i = 0; i < deopt_count; i++) {
PrintF(out, "%6d %6d %6d", PrintF(out, "%6d %6d %6d %6d",
i, AstId(i)->value(), ArgumentsStackHeight(i)->value()); i,
AstId(i)->value(),
ArgumentsStackHeight(i)->value(),
Pc(i)->value());
if (!FLAG_print_code_verbose) { if (!FLAG_print_code_verbose) {
PrintF(out, "\n"); PrintF(out, "\n");
@ -10542,7 +10545,7 @@ class TwoCharHashTableKey : public HashTableKey {
hash += hash << 3; hash += hash << 3;
hash ^= hash >> 11; hash ^= hash >> 11;
hash += hash << 15; hash += hash << 15;
if ((hash & String::kHashBitMask) == 0) hash = 27; if ((hash & String::kHashBitMask) == 0) hash = String::kZeroHash;
#ifdef DEBUG #ifdef DEBUG
StringHasher hasher(2, seed); StringHasher hasher(2, seed);
hasher.AddCharacter(c1); hasher.AddCharacter(c1);

9
deps/v8/src/objects.h

@ -3535,7 +3535,8 @@ class DeoptimizationInputData: public FixedArray {
static const int kAstIdOffset = 0; static const int kAstIdOffset = 0;
static const int kTranslationIndexOffset = 1; static const int kTranslationIndexOffset = 1;
static const int kArgumentsStackHeightOffset = 2; static const int kArgumentsStackHeightOffset = 2;
static const int kDeoptEntrySize = 3; static const int kPcOffset = 3;
static const int kDeoptEntrySize = 4;
// Simple element accessors. // Simple element accessors.
#define DEFINE_ELEMENT_ACCESSORS(name, type) \ #define DEFINE_ELEMENT_ACCESSORS(name, type) \
@ -3571,6 +3572,7 @@ class DeoptimizationInputData: public FixedArray {
DEFINE_ENTRY_ACCESSORS(AstId, Smi) DEFINE_ENTRY_ACCESSORS(AstId, Smi)
DEFINE_ENTRY_ACCESSORS(TranslationIndex, Smi) DEFINE_ENTRY_ACCESSORS(TranslationIndex, Smi)
DEFINE_ENTRY_ACCESSORS(ArgumentsStackHeight, Smi) DEFINE_ENTRY_ACCESSORS(ArgumentsStackHeight, Smi)
DEFINE_ENTRY_ACCESSORS(Pc, Smi)
#undef DEFINE_ENTRY_ACCESSORS #undef DEFINE_ENTRY_ACCESSORS
@ -5832,6 +5834,11 @@ class StringHasher {
// value is represented decimal value. // value is represented decimal value.
static uint32_t MakeArrayIndexHash(uint32_t value, int length); 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: private:
uint32_t array_index() { uint32_t array_index() {
ASSERT(is_array_index()); ASSERT(is_array_index());

60
deps/v8/src/safepoint-table.cc

@ -122,17 +122,20 @@ void Safepoint::DefinePointerRegister(Register reg) {
Safepoint SafepointTableBuilder::DefineSafepoint( Safepoint SafepointTableBuilder::DefineSafepoint(
Assembler* assembler, Safepoint::Kind kind, int arguments, Assembler* assembler,
int deoptimization_index) { Safepoint::Kind kind,
ASSERT(deoptimization_index != -1); int arguments,
Safepoint::DeoptMode deopt_mode) {
ASSERT(arguments >= 0); ASSERT(arguments >= 0);
DeoptimizationInfo pc_and_deoptimization_index; DeoptimizationInfo info;
pc_and_deoptimization_index.pc = assembler->pc_offset(); info.pc = assembler->pc_offset();
pc_and_deoptimization_index.deoptimization_index = deoptimization_index; info.arguments = arguments;
pc_and_deoptimization_index.pc_after_gap = assembler->pc_offset(); info.has_doubles = (kind & Safepoint::kWithDoubles);
pc_and_deoptimization_index.arguments = arguments; deoptimization_info_.Add(info);
pc_and_deoptimization_index.has_doubles = (kind & Safepoint::kWithDoubles); deopt_index_list_.Add(Safepoint::kNoDeoptimizationIndex);
deoptimization_info_.Add(pc_and_deoptimization_index); if (deopt_mode == Safepoint::kNoLazyDeopt) {
last_lazy_safepoint_ = deopt_index_list_.length();
}
indexes_.Add(new ZoneList<int>(8)); indexes_.Add(new ZoneList<int>(8));
registers_.Add((kind & Safepoint::kWithRegisters) registers_.Add((kind & Safepoint::kWithRegisters)
? new ZoneList<int>(4) ? new ZoneList<int>(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 { unsigned SafepointTableBuilder::GetCodeOffset() const {
ASSERT(emitted_); ASSERT(emitted_);
return offset_; return offset_;
@ -173,11 +182,11 @@ void SafepointTableBuilder::Emit(Assembler* assembler, int bits_per_entry) {
assembler->dd(length); assembler->dd(length);
assembler->dd(bytes_per_entry); assembler->dd(bytes_per_entry);
// Emit sorted table of pc offsets together with deoptimization indexes and // Emit sorted table of pc offsets together with deoptimization indexes.
// pc after gap information.
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
assembler->dd(deoptimization_info_[i].pc); 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. // Emit table of bitmaps.
@ -222,35 +231,14 @@ void SafepointTableBuilder::Emit(Assembler* assembler, int bits_per_entry) {
} }
uint32_t SafepointTableBuilder::EncodeExceptPC(const DeoptimizationInfo& info) { uint32_t SafepointTableBuilder::EncodeExceptPC(const DeoptimizationInfo& info,
unsigned index = info.deoptimization_index; unsigned index) {
unsigned gap_size = info.pc_after_gap - info.pc;
uint32_t encoding = SafepointEntry::DeoptimizationIndexField::encode(index); uint32_t encoding = SafepointEntry::DeoptimizationIndexField::encode(index);
encoding |= SafepointEntry::GapCodeSizeField::encode(gap_size);
encoding |= SafepointEntry::ArgumentsField::encode(info.arguments); encoding |= SafepointEntry::ArgumentsField::encode(info.arguments);
encoding |= SafepointEntry::SaveDoublesField::encode(info.has_doubles); encoding |= SafepointEntry::SaveDoublesField::encode(info.has_doubles);
return encoding; 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<int>(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 } } // namespace v8::internal

78
deps/v8/src/safepoint-table.h

@ -62,10 +62,20 @@ class SafepointEntry BASE_EMBEDDED {
return DeoptimizationIndexField::decode(info_); return DeoptimizationIndexField::decode(info_);
} }
int gap_code_size() const { static const int kArgumentsFieldBits = 3;
ASSERT(is_valid()); static const int kSaveDoublesFieldBits = 1;
return GapCodeSizeField::decode(info_); static const int kDeoptIndexBits =
} 32 - kArgumentsFieldBits - kSaveDoublesFieldBits;
class DeoptimizationIndexField:
public BitField<int, 0, kDeoptIndexBits> {}; // NOLINT
class ArgumentsField:
public BitField<unsigned,
kDeoptIndexBits,
kArgumentsFieldBits> {}; // NOLINT
class SaveDoublesField:
public BitField<bool,
kDeoptIndexBits + kArgumentsFieldBits,
kSaveDoublesFieldBits> { }; // NOLINT
int argument_count() const { int argument_count() const {
ASSERT(is_valid()); ASSERT(is_valid());
@ -85,27 +95,6 @@ class SafepointEntry BASE_EMBEDDED {
bool HasRegisters() const; bool HasRegisters() const;
bool HasRegisterAt(int reg_index) 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<unsigned, 0, kGapCodeSizeBits> {};
class DeoptimizationIndexField: public BitField<int,
kGapCodeSizeBits,
kDeoptIndexBits> {}; // NOLINT
class ArgumentsField: public BitField<unsigned,
kGapCodeSizeBits + kDeoptIndexBits,
kArgumentsFieldBits> {}; // NOLINT
class SaveDoublesField: public BitField<bool,
kGapCodeSizeBits + kDeoptIndexBits +
kArgumentsFieldBits,
kSaveDoublesFieldBits> { }; // NOLINT
private: private:
unsigned info_; unsigned info_;
uint8_t* bits_; uint8_t* bits_;
@ -186,6 +175,11 @@ class Safepoint BASE_EMBEDDED {
kWithRegistersAndDoubles = kWithRegisters | kWithDoubles kWithRegistersAndDoubles = kWithRegisters | kWithDoubles
} Kind; } Kind;
enum DeoptMode {
kNoLazyDeopt,
kLazyDeopt
};
static const int kNoDeoptimizationIndex = static const int kNoDeoptimizationIndex =
(1 << (SafepointEntry::kDeoptIndexBits)) - 1; (1 << (SafepointEntry::kDeoptIndexBits)) - 1;
@ -206,9 +200,11 @@ class SafepointTableBuilder BASE_EMBEDDED {
public: public:
SafepointTableBuilder() SafepointTableBuilder()
: deoptimization_info_(32), : deoptimization_info_(32),
deopt_index_list_(32),
indexes_(32), indexes_(32),
registers_(32), registers_(32),
emitted_(false) { } emitted_(false),
last_lazy_safepoint_(0) { }
// Get the offset of the emitted safepoint table in the code. // Get the offset of the emitted safepoint table in the code.
unsigned GetCodeOffset() const; unsigned GetCodeOffset() const;
@ -217,50 +213,34 @@ class SafepointTableBuilder BASE_EMBEDDED {
Safepoint DefineSafepoint(Assembler* assembler, Safepoint DefineSafepoint(Assembler* assembler,
Safepoint::Kind kind, Safepoint::Kind kind,
int arguments, int arguments,
int deoptimization_index); Safepoint::DeoptMode mode);
// 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;
}
// Get the end pc offset of the last safepoint, including the code generated // Record deoptimization index for lazy deoptimization for the last
// until the end of the gap following it. // outstanding safepoints.
unsigned GetPcAfterGap() { void RecordLazyDeoptimizationIndex(int index);
int index = deoptimization_info_.length();
if (index == 0) return 0;
return deoptimization_info_[index - 1].pc_after_gap;
}
// Emit the safepoint table after the body. The number of bits per // Emit the safepoint table after the body. The number of bits per
// entry must be enough to hold all the pointer indexes. // entry must be enough to hold all the pointer indexes.
void Emit(Assembler* assembler, int bits_per_entry); 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: private:
struct DeoptimizationInfo { struct DeoptimizationInfo {
unsigned pc; unsigned pc;
unsigned deoptimization_index;
unsigned pc_after_gap;
unsigned arguments; unsigned arguments;
bool has_doubles; bool has_doubles;
}; };
uint32_t EncodeExceptPC(const DeoptimizationInfo& info); uint32_t EncodeExceptPC(const DeoptimizationInfo& info, unsigned index);
ZoneList<DeoptimizationInfo> deoptimization_info_; ZoneList<DeoptimizationInfo> deoptimization_info_;
ZoneList<unsigned> deopt_index_list_;
ZoneList<ZoneList<int>*> indexes_; ZoneList<ZoneList<int>*> indexes_;
ZoneList<ZoneList<int>*> registers_; ZoneList<ZoneList<int>*> registers_;
unsigned offset_; unsigned offset_;
bool emitted_; bool emitted_;
int last_lazy_safepoint_;
DISALLOW_COPY_AND_ASSIGN(SafepointTableBuilder); DISALLOW_COPY_AND_ASSIGN(SafepointTableBuilder);
}; };

4
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 // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
// met: // met:
@ -35,7 +35,7 @@
#define MAJOR_VERSION 3 #define MAJOR_VERSION 3
#define MINOR_VERSION 6 #define MINOR_VERSION 6
#define BUILD_NUMBER 6 #define BUILD_NUMBER 6
#define PATCH_LEVEL 15 #define PATCH_LEVEL 19
// Use 1 for candidates and 0 otherwise. // Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.) // (Boolean macro values are not supported by all preprocessors.)
#define IS_CANDIDATE_VERSION 0 #define IS_CANDIDATE_VERSION 0

5
deps/v8/src/x64/code-stubs-x64.cc

@ -4654,13 +4654,12 @@ void StringHelper::GenerateHashGetHash(MacroAssembler* masm,
__ shll(scratch, Immediate(15)); __ shll(scratch, Immediate(15));
__ addl(hash, scratch); __ addl(hash, scratch);
uint32_t kHashShiftCutOffMask = (1 << (32 - String::kHashShift)) - 1; __ andl(hash, Immediate(String::kHashBitMask));
__ andl(hash, Immediate(kHashShiftCutOffMask));
// if (hash == 0) hash = 27; // if (hash == 0) hash = 27;
Label hash_not_zero; Label hash_not_zero;
__ j(not_zero, &hash_not_zero); __ j(not_zero, &hash_not_zero);
__ Set(hash, 27); __ Set(hash, StringHasher::kZeroHash);
__ bind(&hash_not_zero); __ bind(&hash_not_zero);
} }

147
deps/v8/src/x64/deoptimizer-x64.cc

@ -42,67 +42,7 @@ const int Deoptimizer::table_entry_size_ = 10;
int Deoptimizer::patch_size() { int Deoptimizer::patch_size() {
return MacroAssembler::kCallInstructionLength; return Assembler::kCallInstructionLength;
}
#ifdef DEBUG
// Overwrites code with int3 instructions.
static void ZapCodeRange(Address from, Address to) {
CHECK(from <= to);
int length = static_cast<int>(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> code) {
// TODO(1276): Implement.
} }
@ -119,84 +59,34 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
// code patching below, and is not needed any more. // code patching below, and is not needed any more.
code->InvalidateRelocation(); 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 // corresponding deoptimization entry, or a short call to an absolute
// jump if space is short. The absolute jumps are put in a table just // 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 // before the safepoint table (space was allocated there when the Code
// object was created, if necessary). // object was created, if necessary).
Address instruction_start = function->code()->instruction_start(); Address instruction_start = function->code()->instruction_start();
Address jump_table_address =
instruction_start + function->code()->safepoint_table_offset();
#ifdef DEBUG #ifdef DEBUG
Address previous_pc = instruction_start; Address prev_call_address = NULL;
#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);
#endif #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. // Position where Call will be patched in.
Address call_address = entry_pc + gap_code_size; Address call_address = instruction_start + deopt_data->Pc(i)->value();
// End of call instruction, if using a direct call to a 64-bit address. // There is room enough to write a long call instruction because we pad
Address call_end_address = // LLazyBailout instructions with nops if necessary.
call_address + MacroAssembler::kCallInstructionLength; CodePatcher patcher(call_address, Assembler::kCallInstructionLength);
patcher.masm()->Call(GetDeoptimizationEntry(i, LAZY), RelocInfo::NONE);
// Find next deoptimization entry, if any. ASSERT(prev_call_address == NULL ||
Address next_pc = NULL; call_address >= prev_call_address + patch_size());
SafepointEntry next_entry = deoptimizations.Next(&next_pc); ASSERT(call_address + patch_size() <= code->instruction_end());
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.
#ifdef DEBUG #ifdef DEBUG
Address short_call_end_address = prev_call_address = call_address;
call_address + MacroAssembler::kShortCallInstructionLength;
#endif #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. // Add the deoptimizing code to the list.
DeoptimizingCodeListNode* node = new DeoptimizingCodeListNode(code); DeoptimizingCodeListNode* node = new DeoptimizingCodeListNode(code);
@ -211,11 +101,6 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
PrintF("[forced deoptimization: "); PrintF("[forced deoptimization: ");
function->PrintName(); function->PrintName();
PrintF(" / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function)); PrintF(" / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
#ifdef DEBUG
if (FLAG_print_code) {
code->PrintLn();
}
#endif
} }
} }

236
deps/v8/src/x64/lithium-codegen-x64.cc

@ -43,35 +43,24 @@ class SafepointGenerator : public CallWrapper {
public: public:
SafepointGenerator(LCodeGen* codegen, SafepointGenerator(LCodeGen* codegen,
LPointerMap* pointers, LPointerMap* pointers,
int deoptimization_index) Safepoint::DeoptMode mode)
: codegen_(codegen), : codegen_(codegen),
pointers_(pointers), pointers_(pointers),
deoptimization_index_(deoptimization_index) { } deopt_mode_(mode) { }
virtual ~SafepointGenerator() { } virtual ~SafepointGenerator() { }
virtual void BeforeCall(int call_size) const { virtual void BeforeCall(int call_size) const {
ASSERT(call_size >= 0); codegen_->EnsureSpaceForLazyDeopt(Deoptimizer::patch_size() - call_size);
// 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);
}
} }
virtual void AfterCall() const { virtual void AfterCall() const {
codegen_->RecordSafepoint(pointers_, deoptimization_index_); codegen_->RecordSafepoint(pointers_, deopt_mode_);
} }
private: private:
static const int kMinSafepointSize =
MacroAssembler::kShortCallInstructionLength;
LCodeGen* codegen_; LCodeGen* codegen_;
LPointerMap* pointers_; LPointerMap* pointers_;
int deoptimization_index_; Safepoint::DeoptMode deopt_mode_;
}; };
@ -94,7 +83,6 @@ void LCodeGen::FinishCode(Handle<Code> code) {
code->set_stack_slots(GetStackSlotCount()); code->set_stack_slots(GetStackSlotCount());
code->set_safepoint_table_offset(safepoints_.GetCodeOffset()); code->set_safepoint_table_offset(safepoints_.GetCodeOffset());
PopulateDeoptimizationData(code); PopulateDeoptimizationData(code);
Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(code);
} }
@ -200,7 +188,7 @@ bool LCodeGen::GeneratePrologue() {
} else { } else {
__ CallRuntime(Runtime::kNewFunctionContext, 1); __ CallRuntime(Runtime::kNewFunctionContext, 1);
} }
RecordSafepoint(Safepoint::kNoDeoptimizationIndex); RecordSafepoint(Safepoint::kNoLazyDeopt);
// Context is returned in both rax and rsi. It replaces the context // 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. // passed to us. It's saved in the stack and kept live in rsi.
__ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi); __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
@ -252,19 +240,11 @@ bool LCodeGen::GenerateBody() {
instr->CompileToNative(this); instr->CompileToNative(this);
} }
} }
EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
return !is_aborted(); return !is_aborted();
} }
LInstruction* LCodeGen::GetNextInstruction() {
if (current_instruction_ < instructions_->length() - 1) {
return instructions_->at(current_instruction_ + 1);
} else {
return NULL;
}
}
bool LCodeGen::GenerateJumpTable() { bool LCodeGen::GenerateJumpTable() {
for (int i = 0; i < jump_table_.length(); i++) { for (int i = 0; i < jump_table_.length(); i++) {
__ bind(&jump_table_[i].label); __ bind(&jump_table_[i].label);
@ -283,18 +263,6 @@ bool LCodeGen::GenerateDeferredCode() {
code->Generate(); code->Generate();
__ jmp(code->exit()); __ 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 // Deferred code is the last part of the instruction sequence. Mark
@ -306,20 +274,6 @@ bool LCodeGen::GenerateDeferredCode() {
bool LCodeGen::GenerateSafepointTable() { bool LCodeGen::GenerateSafepointTable() {
ASSERT(is_done()); 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<unsigned>(MacroAssembler::kJumpInstructionLength));
int byte_count = (short_deopts) * MacroAssembler::kJumpInstructionLength;
while (byte_count-- > 0) {
__ int3();
}
safepoints_.Emit(masm(), GetStackSlotCount()); safepoints_.Emit(masm(), GetStackSlotCount());
return !is_aborted(); return !is_aborted();
} }
@ -475,11 +429,12 @@ void LCodeGen::CallCodeGeneric(Handle<Code> code,
LInstruction* instr, LInstruction* instr,
SafepointMode safepoint_mode, SafepointMode safepoint_mode,
int argc) { int argc) {
EnsureSpaceForLazyDeopt(Deoptimizer::patch_size() - masm()->CallSize(code));
ASSERT(instr != NULL); ASSERT(instr != NULL);
LPointerMap* pointers = instr->pointer_map(); LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position()); RecordPosition(pointers->position());
__ call(code, mode); __ 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 // Signal that we don't inline smi code before these stubs in the
// optimizing code generator. // optimizing code generator.
@ -506,7 +461,7 @@ void LCodeGen::CallRuntime(const Runtime::Function* function,
RecordPosition(pointers->position()); RecordPosition(pointers->position());
__ CallRuntime(function, num_arguments); __ 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)); __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
__ CallRuntimeSaveDoubles(id); __ CallRuntimeSaveDoubles(id);
RecordSafepointWithRegisters( RecordSafepointWithRegisters(
instr->pointer_map(), argc, Safepoint::kNoDeoptimizationIndex); instr->pointer_map(), argc, Safepoint::kNoLazyDeopt);
} }
void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr, void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment,
SafepointMode safepoint_mode, Safepoint::DeoptMode 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) {
if (!environment->HasBeenRegistered()) { if (!environment->HasBeenRegistered()) {
// Physical stack frame layout: // Physical stack frame layout:
// -x ............. -4 0 ..................................... y // -x ............. -4 0 ..................................... y
@ -570,14 +498,17 @@ void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment) {
Translation translation(&translations_, frame_count); Translation translation(&translations_, frame_count);
WriteTranslation(environment, &translation); WriteTranslation(environment, &translation);
int deoptimization_index = deoptimizations_.length(); 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); deoptimizations_.Add(environment);
} }
} }
void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) { void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) {
RegisterEnvironmentForDeoptimization(environment); RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
ASSERT(environment->HasBeenRegistered()); ASSERT(environment->HasBeenRegistered());
int id = environment->deoptimization_index(); int id = environment->deoptimization_index();
Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER); Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER);
@ -629,6 +560,7 @@ void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
data->SetTranslationIndex(i, Smi::FromInt(env->translation_index())); data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
data->SetArgumentsStackHeight(i, data->SetArgumentsStackHeight(i,
Smi::FromInt(env->arguments_stack_height())); Smi::FromInt(env->arguments_stack_height()));
data->SetPc(i, Smi::FromInt(env->pc_offset()));
} }
code->set_deoptimization_data(*data); 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( void LCodeGen::RecordSafepoint(
LPointerMap* pointers, LPointerMap* pointers,
Safepoint::Kind kind, Safepoint::Kind kind,
int arguments, int arguments,
int deoptimization_index) { Safepoint::DeoptMode deopt_mode) {
ASSERT(kind == expected_safepoint_kind_); ASSERT(kind == expected_safepoint_kind_);
const ZoneList<LOperand*>* operands = pointers->operands(); const ZoneList<LOperand*>* operands = pointers->operands();
Safepoint safepoint = safepoints_.DefineSafepoint(masm(), Safepoint safepoint = safepoints_.DefineSafepoint(masm(),
kind, arguments, deoptimization_index); kind, arguments, deopt_mode);
for (int i = 0; i < operands->length(); i++) { for (int i = 0; i < operands->length(); i++) {
LOperand* pointer = operands->at(i); LOperand* pointer = operands->at(i);
if (pointer->IsStackSlot()) { if (pointer->IsStackSlot()) {
@ -687,22 +631,21 @@ void LCodeGen::RecordSafepoint(
void LCodeGen::RecordSafepoint(LPointerMap* pointers, void LCodeGen::RecordSafepoint(LPointerMap* pointers,
int deoptimization_index) { Safepoint::DeoptMode deopt_mode) {
RecordSafepoint(pointers, Safepoint::kSimple, 0, deoptimization_index); 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); LPointerMap empty_pointers(RelocInfo::kNoPosition);
RecordSafepoint(&empty_pointers, deoptimization_index); RecordSafepoint(&empty_pointers, deopt_mode);
} }
void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers, void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
int arguments, int arguments,
int deoptimization_index) { Safepoint::DeoptMode deopt_mode) {
RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, deopt_mode);
deoptimization_index);
} }
@ -737,12 +680,6 @@ void LCodeGen::DoGap(LGap* gap) {
LParallelMove* move = gap->GetParallelMove(inner_pos); LParallelMove* move = gap->GetParallelMove(inner_pos);
if (move != NULL) DoParallelMove(move); 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) LInstanceOfKnownGlobal* instr)
: LDeferredCode(codegen), instr_(instr) { } : LDeferredCode(codegen), instr_(instr) { }
virtual void Generate() { virtual void Generate() {
codegen()->DoDeferredLInstanceOfKnownGlobal(instr_, &map_check_); codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
} }
Label* map_check() { return &map_check_; } Label* map_check() { return &map_check_; }
@ -1910,8 +1847,8 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
} }
void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
Label* map_check) { Label* map_check) {
{ {
PushSafepointRegistersScope scope(this); PushSafepointRegistersScope scope(this);
InstanceofStub::Flags flags = static_cast<InstanceofStub::Flags>( InstanceofStub::Flags flags = static_cast<InstanceofStub::Flags>(
@ -1937,6 +1874,9 @@ void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
RECORD_SAFEPOINT_WITH_REGISTERS, RECORD_SAFEPOINT_WITH_REGISTERS,
2); 2);
ASSERT(delta == masm_->SizeOfCodeGeneratedSince(map_check)); 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 // Move result to a register that survives the end of the
// PushSafepointRegisterScope. // PushSafepointRegisterScope.
__ movq(kScratchRegister, rax); __ movq(kScratchRegister, rax);
@ -2508,12 +2448,9 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
__ bind(&invoke); __ bind(&invoke);
ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
LPointerMap* pointers = instr->pointer_map(); LPointerMap* pointers = instr->pointer_map();
LEnvironment* env = instr->deoptimization_environment();
RecordPosition(pointers->position()); RecordPosition(pointers->position());
RegisterEnvironmentForDeoptimization(env); SafepointGenerator safepoint_generator(
SafepointGenerator safepoint_generator(this, this, pointers, Safepoint::kLazyDeopt);
pointers,
env->deoptimization_index());
v8::internal::ParameterCount actual(rax); v8::internal::ParameterCount actual(rax);
__ InvokeFunction(function, actual, CALL_FUNCTION, __ InvokeFunction(function, actual, CALL_FUNCTION,
safepoint_generator, CALL_AS_METHOD); safepoint_generator, CALL_AS_METHOD);
@ -2591,7 +2528,7 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
} }
// Setup deoptimization. // Setup deoptimization.
RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT, 0); RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT, 0);
// Restore context. // Restore context.
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
@ -2938,10 +2875,8 @@ void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
ASSERT(instr->HasPointerMap()); ASSERT(instr->HasPointerMap());
ASSERT(instr->HasDeoptimizationEnvironment()); ASSERT(instr->HasDeoptimizationEnvironment());
LPointerMap* pointers = instr->pointer_map(); LPointerMap* pointers = instr->pointer_map();
LEnvironment* env = instr->deoptimization_environment();
RecordPosition(pointers->position()); RecordPosition(pointers->position());
RegisterEnvironmentForDeoptimization(env); SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
SafepointGenerator generator(this, pointers, env->deoptimization_index());
ParameterCount count(instr->arity()); ParameterCount count(instr->arity());
__ InvokeFunction(rdi, count, CALL_FUNCTION, generator, CALL_AS_METHOD); __ InvokeFunction(rdi, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); __ 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) { void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
// No code for lazy bailout instruction. Used to capture environment after a EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
// call for populating the safepoint data with deoptimization data. 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); EmitPushTaggedOperand(key);
ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
LPointerMap* pointers = instr->pointer_map(); LPointerMap* pointers = instr->pointer_map();
LEnvironment* env = instr->deoptimization_environment();
RecordPosition(pointers->position()); RecordPosition(pointers->position());
RegisterEnvironmentForDeoptimization(env);
// Create safepoint generator that will also ensure enough space in the // Create safepoint generator that will also ensure enough space in the
// reloc info for patching in deoptimization (since this is invoking a // reloc info for patching in deoptimization (since this is invoking a
// builtin) // builtin)
SafepointGenerator safepoint_generator(this, SafepointGenerator safepoint_generator(
pointers, this, pointers, Safepoint::kLazyDeopt);
env->deoptimization_index());
__ Push(Smi::FromInt(strict_mode_flag())); __ Push(Smi::FromInt(strict_mode_flag()));
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator); __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator);
} }
@ -4076,30 +4027,21 @@ void LCodeGen::DoIn(LIn* instr) {
EmitPushTaggedOperand(obj); EmitPushTaggedOperand(obj);
ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
LPointerMap* pointers = instr->pointer_map(); LPointerMap* pointers = instr->pointer_map();
LEnvironment* env = instr->deoptimization_environment();
RecordPosition(pointers->position()); RecordPosition(pointers->position());
RegisterEnvironmentForDeoptimization(env); SafepointGenerator safepoint_generator(
// Create safepoint generator that will also ensure enough space in the this, pointers, Safepoint::kLazyDeopt);
// reloc info for patching in deoptimization (since this is invoking a
// builtin)
SafepointGenerator safepoint_generator(this,
pointers,
env->deoptimization_index());
__ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator); __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator);
} }
void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) { void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
{ PushSafepointRegistersScope scope(this);
PushSafepointRegistersScope scope(this); __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
__ CallRuntimeSaveDoubles(Runtime::kStackGuard); RecordSafepointWithLazyDeopt(instr, RECORD_SAFEPOINT_WITH_REGISTERS, 0);
RegisterLazyDeoptimization(instr, RECORD_SAFEPOINT_WITH_REGISTERS, 0); ASSERT(instr->HasEnvironment());
} LEnvironment* env = instr->environment();
safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
// The gap code includes the restoring of the safepoint registers.
int pc = masm()->pc_offset();
safepoints_.SetPcAfterGap(pc);
} }
@ -4113,6 +4055,10 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) {
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()) { if (instr->hydrogen()->is_function_entry()) {
// Perform stack overflow check. // Perform stack overflow check.
Label done; Label done;
@ -4120,7 +4066,11 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) {
__ j(above_equal, &done, Label::kNear); __ j(above_equal, &done, Label::kNear);
StackCheckStub stub; StackCheckStub stub;
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
last_lazy_deopt_pc_ = masm()->pc_offset();
__ bind(&done); __ bind(&done);
RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
} else { } else {
ASSERT(instr->hydrogen()->is_backwards_branch()); ASSERT(instr->hydrogen()->is_backwards_branch());
// Perform stack overflow check if this goto needs it before jumping. // Perform stack overflow check if this goto needs it before jumping.
@ -4128,8 +4078,14 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) {
new DeferredStackCheck(this, instr); new DeferredStackCheck(this, instr);
__ CompareRoot(rsp, Heap::kStackLimitRootIndex); __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
__ j(below, deferred_stack_check->entry()); __ j(below, deferred_stack_check->entry());
EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
last_lazy_deopt_pc_ = masm()->pc_offset();
__ bind(instr->done_label()); __ bind(instr->done_label());
deferred_stack_check->SetExit(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 // If the environment were already registered, we would have no way of
// backpatching it with the spill slot operands. // backpatching it with the spill slot operands.
ASSERT(!environment->HasBeenRegistered()); ASSERT(!environment->HasBeenRegistered());
RegisterEnvironmentForDeoptimization(environment); RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
ASSERT(osr_pc_offset_ == -1); ASSERT(osr_pc_offset_ == -1);
osr_pc_offset_ = masm()->pc_offset(); osr_pc_offset_ = masm()->pc_offset();
} }

29
deps/v8/src/x64/lithium-codegen-x64.h

@ -60,6 +60,7 @@ class LCodeGen BASE_EMBEDDED {
status_(UNUSED), status_(UNUSED),
deferred_(8), deferred_(8),
osr_pc_offset_(-1), osr_pc_offset_(-1),
last_lazy_deopt_pc_(0),
resolver_(this), resolver_(this),
expected_safepoint_kind_(Safepoint::kSimple) { expected_safepoint_kind_(Safepoint::kSimple) {
PopulateDeoptimizationLiteralsWithInlinedFunctions(); PopulateDeoptimizationLiteralsWithInlinedFunctions();
@ -97,8 +98,8 @@ class LCodeGen BASE_EMBEDDED {
void DoDeferredStackCheck(LStackCheck* instr); void DoDeferredStackCheck(LStackCheck* instr);
void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr); void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
void DoDeferredStringCharFromCode(LStringCharFromCode* instr); void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
void DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
Label* map_check); Label* map_check);
// Parallel move support. // Parallel move support.
void DoParallelMove(LParallelMove* move); void DoParallelMove(LParallelMove* move);
@ -134,7 +135,6 @@ class LCodeGen BASE_EMBEDDED {
HGraph* graph() const { return chunk_->graph(); } HGraph* graph() const { return chunk_->graph(); }
int GetNextEmittedBlock(int block); int GetNextEmittedBlock(int block);
LInstruction* GetNextInstruction();
void EmitClassOfTest(Label* if_true, void EmitClassOfTest(Label* if_true,
Label* if_false, Label* if_false,
@ -199,10 +199,11 @@ class LCodeGen BASE_EMBEDDED {
void LoadHeapObject(Register result, Handle<HeapObject> object); void LoadHeapObject(Register result, Handle<HeapObject> object);
void RegisterLazyDeoptimization(LInstruction* instr, void RecordSafepointWithLazyDeopt(LInstruction* instr,
SafepointMode safepoint_mode, SafepointMode safepoint_mode,
int argc); int argc);
void RegisterEnvironmentForDeoptimization(LEnvironment* environment); void RegisterEnvironmentForDeoptimization(LEnvironment* environment,
Safepoint::DeoptMode mode);
void DeoptimizeIf(Condition cc, LEnvironment* environment); void DeoptimizeIf(Condition cc, LEnvironment* environment);
void AddToTranslation(Translation* translation, void AddToTranslation(Translation* translation,
@ -236,16 +237,13 @@ class LCodeGen BASE_EMBEDDED {
void RecordSafepoint(LPointerMap* pointers, void RecordSafepoint(LPointerMap* pointers,
Safepoint::Kind kind, Safepoint::Kind kind,
int arguments, int arguments,
int deoptimization_index); Safepoint::DeoptMode mode);
void RecordSafepoint(LPointerMap* pointers, int deoptimization_index); void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode);
void RecordSafepoint(int deoptimization_index); void RecordSafepoint(Safepoint::DeoptMode mode);
void RecordSafepointWithRegisters(LPointerMap* pointers, void RecordSafepointWithRegisters(LPointerMap* pointers,
int arguments, int arguments,
int deoptimization_index); Safepoint::DeoptMode mode);
void RecordPosition(int position); void RecordPosition(int position);
int LastSafepointEnd() {
return static_cast<int>(safepoints_.GetPcAfterGap());
}
static Condition TokenToCondition(Token::Value op, bool is_unsigned); static Condition TokenToCondition(Token::Value op, bool is_unsigned);
void EmitGoto(int block); void EmitGoto(int block);
@ -290,6 +288,8 @@ class LCodeGen BASE_EMBEDDED {
Address address; Address address;
}; };
void EnsureSpaceForLazyDeopt(int space_needed);
LChunk* const chunk_; LChunk* const chunk_;
MacroAssembler* const masm_; MacroAssembler* const masm_;
CompilationInfo* const info_; CompilationInfo* const info_;
@ -306,6 +306,7 @@ class LCodeGen BASE_EMBEDDED {
TranslationBuffer translations_; TranslationBuffer translations_;
ZoneList<LDeferredCode*> deferred_; ZoneList<LDeferredCode*> deferred_;
int osr_pc_offset_; int osr_pc_offset_;
int last_lazy_deopt_pc_;
// Builder that keeps track of safepoints in the code. The table // Builder that keeps track of safepoints in the code. The table
// itself is emitted at the end of the generated code. // itself is emitted at the end of the generated code.

11
deps/v8/test/mjsunit/compiler/regress-funcaller.js

@ -25,6 +25,8 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --allow-natives-syntax
// Test function.caller. // Test function.caller.
function A() {} function A() {}
@ -40,9 +42,10 @@ A.prototype.g = gee;
var o = new A(); var o = new A();
for (var i=0; i<5000000; i++) { for (var i=0; i<5; i++) {
o.g(i); o.g(i);
} }
%OptimizeFunctionOnNextCall(o.g);
assertEquals(gee, o.g(0)); assertEquals(gee, o.g(0));
assertEquals(null, o.g(1)); assertEquals(null, o.g(1));
@ -53,9 +56,10 @@ function hej(x) {
return o.g(x); return o.g(x);
} }
for (var j=0; j<5000000; j++) { for (var j=0; j<5; j++) {
hej(j); hej(j);
} }
%OptimizeFunctionOnNextCall(hej);
assertEquals(gee, hej(0)); assertEquals(gee, hej(0));
assertEquals(hej, hej(1)); assertEquals(hej, hej(1));
@ -66,8 +70,9 @@ function from_eval(x) {
return o.g(x); return o.g(x);
} }
for (var j=0; j<5000000; j++) { for (var j=0; j<5; j++) {
from_eval(j); from_eval(j);
} }
%OptimizeFunctionOnNextCall(from_eval);
assertEquals(gee, from_eval(0)); assertEquals(gee, from_eval(0));
assertEquals(from_eval, from_eval(1)); assertEquals(from_eval, from_eval(1));

48
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));
Loading…
Cancel
Save