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