diff options
author | Ryan Dahl <ry@tinyclouds.org> | 2011-01-19 11:06:13 -0800 |
---|---|---|
committer | Ryan Dahl <ry@tinyclouds.org> | 2011-01-19 11:06:13 -0800 |
commit | b8f006ef72bb518397483d5b43111ddbcff250c8 (patch) | |
tree | 0bd0a7f2ae70606aca210c38596fa8f2f6e52194 /deps/v8/src | |
parent | e6e6e87463d4b1d3d8d5c129e4d008d35a1b5463 (diff) | |
download | node-new-b8f006ef72bb518397483d5b43111ddbcff250c8.tar.gz |
Upgrade V8 to 3.0.9
Diffstat (limited to 'deps/v8/src')
67 files changed, 4501 insertions, 2054 deletions
diff --git a/deps/v8/src/SConscript b/deps/v8/src/SConscript index 79b12040bd..708edeff06 100755 --- a/deps/v8/src/SConscript +++ b/deps/v8/src/SConscript @@ -71,6 +71,7 @@ SOURCES = { frames.cc full-codegen.cc func-name-inferrer.cc + gdb-jit.cc global-handles.cc fast-dtoa.cc fixed-dtoa.cc @@ -81,6 +82,7 @@ SOURCES = { hydrogen.cc hydrogen-instructions.cc ic.cc + inspector.cc interpreter-irregexp.cc jsregexp.cc jump-target.cc @@ -190,6 +192,7 @@ SOURCES = { ia32/ic-ia32.cc ia32/jump-target-ia32.cc ia32/lithium-codegen-ia32.cc + ia32/lithium-gap-resolver-ia32.cc ia32/lithium-ia32.cc ia32/macro-assembler-ia32.cc ia32/regexp-macro-assembler-ia32.cc diff --git a/deps/v8/src/arm/assembler-arm.cc b/deps/v8/src/arm/assembler-arm.cc index a7c1897aed..11a9c3930f 100644 --- a/deps/v8/src/arm/assembler-arm.cc +++ b/deps/v8/src/arm/assembler-arm.cc @@ -2495,6 +2495,10 @@ void Assembler::GrowBuffer() { void Assembler::db(uint8_t data) { + // No relocation info should be pending while using db. db is used + // to write pure data with no pointers and the constant pool should + // be emitted before using db. + ASSERT(num_prinfo_ == 0); CheckBuffer(); *reinterpret_cast<uint8_t*>(pc_) = data; pc_ += sizeof(uint8_t); @@ -2502,6 +2506,10 @@ void Assembler::db(uint8_t data) { void Assembler::dd(uint32_t data) { + // No relocation info should be pending while using dd. dd is used + // to write pure data with no pointers and the constant pool should + // be emitted before using dd. + ASSERT(num_prinfo_ == 0); CheckBuffer(); *reinterpret_cast<uint32_t*>(pc_) = data; pc_ += sizeof(uint32_t); diff --git a/deps/v8/src/arm/assembler-arm.h b/deps/v8/src/arm/assembler-arm.h index e0ea819e99..ad1bdabd01 100644 --- a/deps/v8/src/arm/assembler-arm.h +++ b/deps/v8/src/arm/assembler-arm.h @@ -1240,8 +1240,10 @@ class Assembler : public Malloced { // Use --code-comments to enable. void RecordComment(const char* msg); - // Writes a single byte or word of data in the code stream. Used for - // inline tables, e.g., jump-tables. + // Writes a single byte or word of data in the code stream. Used + // for inline tables, e.g., jump-tables. The constant pool should be + // emitted before any use of db and dd to ensure that constant pools + // are not emitted as part of the tables generated. void db(uint8_t data); void dd(uint32_t data); diff --git a/deps/v8/src/arm/ic-arm.cc b/deps/v8/src/arm/ic-arm.cc index 340bc1ef90..6120bba458 100644 --- a/deps/v8/src/arm/ic-arm.cc +++ b/deps/v8/src/arm/ic-arm.cc @@ -542,8 +542,12 @@ static void GenerateMonomorphicCacheProbe(MacroAssembler* masm, Label number, non_number, non_string, boolean, probe, miss; // Probe the stub cache. - Code::Flags flags = - Code::ComputeFlags(kind, NOT_IN_LOOP, MONOMORPHIC, NORMAL, argc); + Code::Flags flags = Code::ComputeFlags(kind, + NOT_IN_LOOP, + MONOMORPHIC, + Code::kNoExtraICState, + NORMAL, + argc); StubCache::GenerateProbe(masm, flags, r1, r2, r3, r4, r5); // If the stub cache probing failed, the receiver might be a value. diff --git a/deps/v8/src/arm/lithium-arm.cc b/deps/v8/src/arm/lithium-arm.cc index df890ab55b..b51633e706 100644 --- a/deps/v8/src/arm/lithium-arm.cc +++ b/deps/v8/src/arm/lithium-arm.cc @@ -576,6 +576,13 @@ LOperand* LChunkBuilder::UseRegisterOrConstantAtStart(HValue* value) { } +LOperand* LChunkBuilder::UseAny(HValue* value) { + return value->IsConstant() + ? chunk_->DefineConstantOperand(HConstant::cast(value)) + : Use(value, new LUnallocated(LUnallocated::ANY)); +} + + LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) { if (value->EmitAtUses()) { HInstruction* instr = HInstruction::cast(value); @@ -907,11 +914,7 @@ LEnvironment* LChunkBuilder::CreateEnvironment(HEnvironment* hydrogen_env) { } else if (value->IsPushArgument()) { op = new LArgument(argument_index++); } else { - op = UseOrConstant(value); - if (op->IsUnallocated()) { - LUnallocated* unalloc = LUnallocated::cast(op); - unalloc->set_policy(LUnallocated::ANY); - } + op = UseAny(value); } result->AddValue(op, value->representation()); } diff --git a/deps/v8/src/arm/lithium-arm.h b/deps/v8/src/arm/lithium-arm.h index c6b89a5046..aab408111c 100644 --- a/deps/v8/src/arm/lithium-arm.h +++ b/deps/v8/src/arm/lithium-arm.h @@ -1887,15 +1887,25 @@ class LChunkBuilder BASE_EMBEDDED { LOperand* UseRegister(HValue* value); LOperand* UseRegisterAtStart(HValue* value); - // A value in a register that may be trashed. + // An input operand in a register that may be trashed. LOperand* UseTempRegister(HValue* value); + + // An input operand in a register or stack slot. LOperand* Use(HValue* value); LOperand* UseAtStart(HValue* value); + + // An input operand in a register, stack slot or a constant operand. LOperand* UseOrConstant(HValue* value); LOperand* UseOrConstantAtStart(HValue* value); + + // An input operand in a register or a constant operand. LOperand* UseRegisterOrConstant(HValue* value); LOperand* UseRegisterOrConstantAtStart(HValue* value); + // An input operand in register, stack slot or a constant operand. + // Will not be moved to a register even if one is freely available. + LOperand* UseAny(HValue* value); + // Methods for setting up define-use relationships. // Return the same instruction that they are passed. LInstruction* Define(LInstruction* instr, LUnallocated* result); diff --git a/deps/v8/src/arm/lithium-codegen-arm.cc b/deps/v8/src/arm/lithium-codegen-arm.cc index dca95f2361..55df8b4cb8 100644 --- a/deps/v8/src/arm/lithium-codegen-arm.cc +++ b/deps/v8/src/arm/lithium-codegen-arm.cc @@ -172,13 +172,13 @@ bool LGapResolver::CanReach(LGapNode* a, LGapNode* b) { void LGapResolver::RegisterMove(LMoveOperands move) { - if (move.from()->IsConstantOperand()) { + if (move.source()->IsConstantOperand()) { // Constant moves should be last in the machine code. Therefore add them // first to the result set. - AddResultMove(move.from(), move.to()); + AddResultMove(move.source(), move.destination()); } else { - LGapNode* from = LookupNode(move.from()); - LGapNode* to = LookupNode(move.to()); + LGapNode* from = LookupNode(move.source()); + LGapNode* to = LookupNode(move.destination()); if (to->IsAssigned() && to->assigned_from() == from) { move.Eliminate(); return; @@ -341,6 +341,11 @@ bool LCodeGen::GenerateDeferredCode() { __ jmp(code->exit()); } + // Force constant pool emission at the end of deferred code to make + // sure that no constant pools are emitted after the official end of + // the instruction sequence. + masm()->CheckConstPool(true, false); + // Deferred code is the last part of the instruction sequence. Mark // the generated code as done unless we bailed out. if (!is_aborted()) status_ = DONE; @@ -816,8 +821,8 @@ void LCodeGen::DoParallelMove(LParallelMove* move) { resolver_.Resolve(move->move_operands(), &marker_operand); for (int i = moves->length() - 1; i >= 0; --i) { LMoveOperands move = moves->at(i); - LOperand* from = move.from(); - LOperand* to = move.to(); + LOperand* from = move.source(); + LOperand* to = move.destination(); ASSERT(!from->IsDoubleRegister() || !ToDoubleRegister(from).is(dbl_scratch)); ASSERT(!to->IsDoubleRegister() || !ToDoubleRegister(to).is(dbl_scratch)); @@ -999,7 +1004,6 @@ void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { void LCodeGen::DoModI(LModI* instr) { - Abort("ModI not implemented"); class DeferredModI: public LDeferredCode { public: DeferredModI(LCodeGen* codegen, LModI* instr) @@ -1055,7 +1059,6 @@ void LCodeGen::DoModI(LModI* instr) { void LCodeGen::DoDivI(LDivI* instr) { - Abort("DivI not implemented"); class DeferredDivI: public LDeferredCode { public: DeferredDivI(LCodeGen* codegen, LDivI* instr) @@ -1293,7 +1296,10 @@ void LCodeGen::DoConstantI(LConstantI* instr) { void LCodeGen::DoConstantD(LConstantD* instr) { - Abort("DoConstantD unimplemented."); + ASSERT(instr->result()->IsDoubleRegister()); + DwVfpRegister result = ToDoubleRegister(instr->result()); + double v = instr->value(); + __ vmov(result, v); } @@ -2336,6 +2342,15 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) { // Move the result back to general purpose register r0. __ vmov(result, single_scratch); + + // Test for -0. + Label done; + __ cmp(result, Operand(0)); + __ b(ne, &done); + __ vmov(scratch, input.high()); + __ tst(scratch, Operand(HeapNumber::kSignMask)); + DeoptimizeIf(ne, instr->environment()); + __ bind(&done); } diff --git a/deps/v8/src/arm/stub-cache-arm.cc b/deps/v8/src/arm/stub-cache-arm.cc index 20e2801826..b7ec5d245a 100644 --- a/deps/v8/src/arm/stub-cache-arm.cc +++ b/deps/v8/src/arm/stub-cache-arm.cc @@ -1332,11 +1332,10 @@ void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell, MaybeObject* CallStubCompiler::GenerateMissBranch() { + MaybeObject* maybe_obj = StubCache::ComputeCallMiss(arguments().immediate(), + kind_); Object* obj; - { MaybeObject* maybe_obj = - StubCache::ComputeCallMiss(arguments().immediate(), kind_); - if (!maybe_obj->ToObject(&obj)) return maybe_obj; - } + if (!maybe_obj->ToObject(&obj)) return maybe_obj; __ Jump(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET); return obj; } @@ -1646,8 +1645,15 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall( const int argc = arguments().immediate(); Label miss; + Label name_miss; Label index_out_of_range; - GenerateNameCheck(name, &miss); + Label* index_out_of_range_label = &index_out_of_range; + + if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) { + index_out_of_range_label = &miss; + } + + GenerateNameCheck(name, &name_miss); // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype(masm(), @@ -1675,7 +1681,7 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall( result, &miss, // When not a string. &miss, // When not a number. - &index_out_of_range, + index_out_of_range_label, STRING_INDEX_IS_NUMBER); char_code_at_generator.GenerateFast(masm()); __ Drop(argc + 1); @@ -1684,12 +1690,17 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall( StubRuntimeCallHelper call_helper; char_code_at_generator.GenerateSlow(masm(), call_helper); - __ bind(&index_out_of_range); - __ LoadRoot(r0, Heap::kNanValueRootIndex); - __ Drop(argc + 1); - __ Ret(); + if (index_out_of_range.is_linked()) { + __ bind(&index_out_of_range); + __ LoadRoot(r0, Heap::kNanValueRootIndex); + __ Drop(argc + 1); + __ Ret(); + } __ bind(&miss); + // Restore function name in r2. + __ Move(r2, Handle<String>(name)); + __ bind(&name_miss); Object* obj; { MaybeObject* maybe_obj = GenerateMissBranch(); if (!maybe_obj->ToObject(&obj)) return maybe_obj; @@ -1720,9 +1731,15 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall( const int argc = arguments().immediate(); Label miss; + Label name_miss; Label index_out_of_range; + Label* index_out_of_range_label = &index_out_of_range; - GenerateNameCheck(name, &miss); + if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) { + index_out_of_range_label = &miss; + } + + GenerateNameCheck(name, &name_miss); // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype(masm(), @@ -1752,7 +1769,7 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall( result, &miss, // When not a string. &miss, // When not a number. - &index_out_of_range, + index_out_of_range_label, STRING_INDEX_IS_NUMBER); char_at_generator.GenerateFast(masm()); __ Drop(argc + 1); @@ -1761,12 +1778,17 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall( StubRuntimeCallHelper call_helper; char_at_generator.GenerateSlow(masm(), call_helper); - __ bind(&index_out_of_range); - __ LoadRoot(r0, Heap::kEmptyStringRootIndex); - __ Drop(argc + 1); - __ Ret(); + if (index_out_of_range.is_linked()) { + __ bind(&index_out_of_range); + __ LoadRoot(r0, Heap::kEmptyStringRootIndex); + __ Drop(argc + 1); + __ Ret(); + } __ bind(&miss); + // Restore function name in r2. + __ Move(r2, Handle<String>(name)); + __ bind(&name_miss); Object* obj; { MaybeObject* maybe_obj = GenerateMissBranch(); if (!maybe_obj->ToObject(&obj)) return maybe_obj; diff --git a/deps/v8/src/assembler.cc b/deps/v8/src/assembler.cc index cdcf481891..fb9a4af14e 100644 --- a/deps/v8/src/assembler.cc +++ b/deps/v8/src/assembler.cc @@ -917,6 +917,11 @@ void PositionsRecorder::RecordPosition(int pos) { ASSERT(pos != RelocInfo::kNoPosition); ASSERT(pos >= 0); state_.current_position = pos; +#ifdef ENABLE_GDB_JIT_INTERFACE + if (gdbjit_lineinfo_ != NULL) { + gdbjit_lineinfo_->SetPosition(assembler_->pc_offset(), pos, false); + } +#endif } @@ -924,6 +929,11 @@ void PositionsRecorder::RecordStatementPosition(int pos) { ASSERT(pos != RelocInfo::kNoPosition); ASSERT(pos >= 0); state_.current_statement_position = pos; +#ifdef ENABLE_GDB_JIT_INTERFACE + if (gdbjit_lineinfo_ != NULL) { + gdbjit_lineinfo_->SetPosition(assembler_->pc_offset(), pos, true); + } +#endif } diff --git a/deps/v8/src/assembler.h b/deps/v8/src/assembler.h index 5817a15b45..4ef61e4b14 100644 --- a/deps/v8/src/assembler.h +++ b/deps/v8/src/assembler.h @@ -35,6 +35,7 @@ #ifndef V8_ASSEMBLER_H_ #define V8_ASSEMBLER_H_ +#include "gdb-jit.h" #include "runtime.h" #include "top.h" #include "token.h" @@ -637,7 +638,29 @@ struct PositionState { class PositionsRecorder BASE_EMBEDDED { public: explicit PositionsRecorder(Assembler* assembler) - : assembler_(assembler) {} + : assembler_(assembler) { +#ifdef ENABLE_GDB_JIT_INTERFACE + gdbjit_lineinfo_ = NULL; +#endif + } + +#ifdef ENABLE_GDB_JIT_INTERFACE + ~PositionsRecorder() { + delete gdbjit_lineinfo_; + } + + void StartGDBJITLineInfoRecording() { + if (FLAG_gdbjit) { + gdbjit_lineinfo_ = new GDBJITLineInfo(); + } + } + + GDBJITLineInfo* DetachGDBJITLineInfo() { + GDBJITLineInfo* lineinfo = gdbjit_lineinfo_; + gdbjit_lineinfo_ = NULL; // To prevent deallocation in destructor. + return lineinfo; + } +#endif // Set current position to pos. void RecordPosition(int pos); @@ -657,6 +680,9 @@ class PositionsRecorder BASE_EMBEDDED { private: Assembler* assembler_; PositionState state_; +#ifdef ENABLE_GDB_JIT_INTERFACE + GDBJITLineInfo* gdbjit_lineinfo_; +#endif friend class PreservePositionScope; diff --git a/deps/v8/src/builtins.cc b/deps/v8/src/builtins.cc index a659c461c0..c4c9fc11c8 100644 --- a/deps/v8/src/builtins.cc +++ b/deps/v8/src/builtins.cc @@ -31,6 +31,7 @@ #include "arguments.h" #include "bootstrapper.h" #include "builtins.h" +#include "gdb-jit.h" #include "ic-inl.h" #include "vm-state-inl.h" @@ -1550,7 +1551,7 @@ void Builtins::Setup(bool create_heap_objects) { CodeDesc desc; masm.GetCode(&desc); Code::Flags flags = functions[i].flags; - Object* code = 0; + Object* code = NULL; { // During startup it's OK to always allocate and defer GC to later. // This simplifies things because we don't need to retry. @@ -1564,7 +1565,11 @@ void Builtins::Setup(bool create_heap_objects) { } // Log the event and add the code to the builtins array. PROFILE(CodeCreateEvent(Logger::BUILTIN_TAG, - Code::cast(code), functions[i].s_name)); + Code::cast(code), + functions[i].s_name)); + GDBJIT(AddCode(GDBJITInterface::BUILTIN, + functions[i].s_name, + Code::cast(code))); builtins_[i] = code; #ifdef ENABLE_DISASSEMBLER if (FLAG_print_builtin_code) { diff --git a/deps/v8/src/code-stubs.cc b/deps/v8/src/code-stubs.cc index ba027e9332..69f8477f89 100644 --- a/deps/v8/src/code-stubs.cc +++ b/deps/v8/src/code-stubs.cc @@ -30,6 +30,7 @@ #include "bootstrapper.h" #include "code-stubs.h" #include "factory.h" +#include "gdb-jit.h" #include "macro-assembler.h" #include "oprofile-agent.h" @@ -66,6 +67,7 @@ void CodeStub::RecordCodeGeneration(Code* code, MacroAssembler* masm) { code->instruction_start(), code->instruction_size())); PROFILE(CodeCreateEvent(Logger::STUB_TAG, code, GetName())); + GDBJIT(AddCode(GDBJITInterface::STUB, GetName(), code)); Counters::total_stubs_code_size.Increment(code->instruction_size()); #ifdef ENABLE_DISASSEMBLER diff --git a/deps/v8/src/codegen.cc b/deps/v8/src/codegen.cc index da479e8fc1..c7e6f1c83f 100644 --- a/deps/v8/src/codegen.cc +++ b/deps/v8/src/codegen.cc @@ -248,6 +248,9 @@ bool CodeGenerator::MakeCode(CompilationInfo* info) { // Generate code. const int kInitialBufferSize = 4 * KB; MacroAssembler masm(NULL, kInitialBufferSize); +#ifdef ENABLE_GDB_JIT_INTERFACE + masm.positions_recorder()->StartGDBJITLineInfoRecording(); +#endif CodeGenerator cgen(&masm); CodeGeneratorScope scope(&cgen); cgen.Generate(info); @@ -263,6 +266,14 @@ bool CodeGenerator::MakeCode(CompilationInfo* info) { code->SetNoStackCheckTable(); CodeGenerator::PrintCode(code, info); info->SetCode(code); // May be an empty handle. +#ifdef ENABLE_GDB_JIT_INTERFACE + if (!code.is_null()) { + GDBJITLineInfo* lineinfo = + masm.positions_recorder()->DetachGDBJITLineInfo(); + + GDBJIT(RegisterDetailedLineInfo(*code, lineinfo)); + } +#endif return !code.is_null(); } diff --git a/deps/v8/src/compiler.cc b/deps/v8/src/compiler.cc index 0bd973045a..bbe7f2fc9c 100755 --- a/deps/v8/src/compiler.cc +++ b/deps/v8/src/compiler.cc @@ -35,6 +35,7 @@ #include "data-flow.h" #include "debug.h" #include "full-codegen.h" +#include "gdb-jit.h" #include "hydrogen.h" #include "lithium-allocator.h" #include "liveedit.h" @@ -207,7 +208,8 @@ static bool MakeCrankshaftCode(CompilationInfo* info) { // Limit the number of times we re-compile a functions with // the optimizing compiler. - const int kMaxOptCount = FLAG_deopt_every_n_times == 0 ? 10 : 1000; + const int kMaxOptCount = + FLAG_deopt_every_n_times == 0 ? Compiler::kDefaultMaxOptCount : 1000; if (info->shared_info()->opt_count() > kMaxOptCount) { AbortAndDisable(info); // True indicates the compilation pipeline is still going, not @@ -420,6 +422,9 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) { OPROFILE(CreateNativeCodeRegion(String::cast(script->name()), info->code()->instruction_start(), info->code()->instruction_size())); + GDBJIT(AddCode(Handle<String>(String::cast(script->name())), + script, + info->code())); } else { PROFILE(CodeCreateEvent( info->is_eval() @@ -430,6 +435,7 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) { OPROFILE(CreateNativeCodeRegion(info->is_eval() ? "Eval" : "Script", info->code()->instruction_start(), info->code()->instruction_size())); + GDBJIT(AddCode(Handle<String>(), script, info->code())); } // Allocate function. @@ -793,6 +799,10 @@ void Compiler::RecordFunctionCompilation(Logger::LogEventsAndTags tag, code->instruction_size())); } } + + GDBJIT(AddCode(name, + Handle<Script>(info->script()), + Handle<Code>(info->code()))); } } } // namespace v8::internal diff --git a/deps/v8/src/compiler.h b/deps/v8/src/compiler.h index 68066aa67a..44ac9c85ce 100644 --- a/deps/v8/src/compiler.h +++ b/deps/v8/src/compiler.h @@ -209,9 +209,13 @@ class CompilationInfo BASE_EMBEDDED { class Compiler : public AllStatic { public: - // All routines return a JSFunction. - // If an error occurs an exception is raised and - // the return handle contains NULL. + // Default maximum number of function optimization attempts before we + // give up. + static const int kDefaultMaxOptCount = 10; + + // All routines return a SharedFunctionInfo. + // If an error occurs an exception is raised and the return handle + // contains NULL. // Compile a String source within a context. static Handle<SharedFunctionInfo> Compile(Handle<String> source, diff --git a/deps/v8/src/flag-definitions.h b/deps/v8/src/flag-definitions.h index daadef69fd..fb892d6248 100644 --- a/deps/v8/src/flag-definitions.h +++ b/deps/v8/src/flag-definitions.h @@ -366,6 +366,14 @@ DEFINE_bool(debug_script_collected_events, true, "Enable debugger script collected events") #endif + +// +// GDB JIT integration flags. +// + +DEFINE_bool(gdbjit, false, "enable GDBJIT interface (disables compacting GC)") +DEFINE_bool(gdbjit_full, false, "enable GDBJIT interface for all code objects") + // // Debug only flags // diff --git a/deps/v8/src/frames.cc b/deps/v8/src/frames.cc index 16ffbf5a94..7f28ff175a 100644 --- a/deps/v8/src/frames.cc +++ b/deps/v8/src/frames.cc @@ -554,6 +554,7 @@ void OptimizedFrame::Iterate(ObjectVisitor* v) const { parameters_base += safepoint_entry.argument_count(); } + // Skip saved double registers. if (safepoint_entry.has_doubles()) { parameters_base += DoubleRegister::kNumAllocatableRegisters * kDoubleSize / kPointerSize; diff --git a/deps/v8/src/full-codegen.cc b/deps/v8/src/full-codegen.cc index 58540f07bc..9366e427a1 100644 --- a/deps/v8/src/full-codegen.cc +++ b/deps/v8/src/full-codegen.cc @@ -286,6 +286,9 @@ bool FullCodeGenerator::MakeCode(CompilationInfo* info) { CodeGenerator::MakeCodePrologue(info); const int kInitialBufferSize = 4 * KB; MacroAssembler masm(NULL, kInitialBufferSize); +#ifdef ENABLE_GDB_JIT_INTERFACE + masm.positions_recorder()->StartGDBJITLineInfoRecording(); +#endif FullCodeGenerator cgen(&masm); cgen.Generate(info); @@ -304,6 +307,14 @@ bool FullCodeGenerator::MakeCode(CompilationInfo* info) { code->set_stack_check_table_start(table_offset); CodeGenerator::PrintCode(code, info); info->SetCode(code); // may be an empty handle. +#ifdef ENABLE_GDB_JIT_INTERFACE + if (!code.is_null()) { + GDBJITLineInfo* lineinfo = + masm.positions_recorder()->DetachGDBJITLineInfo(); + + GDBJIT(RegisterDetailedLineInfo(*code, lineinfo)); + } +#endif return !code.is_null(); } diff --git a/deps/v8/src/gdb-jit.cc b/deps/v8/src/gdb-jit.cc new file mode 100644 index 0000000000..b1782cbdd0 --- /dev/null +++ b/deps/v8/src/gdb-jit.cc @@ -0,0 +1,1170 @@ +// Copyright 2010 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. + +#ifdef ENABLE_GDB_JIT_INTERFACE +#include "gdb-jit.h" + +#include "bootstrapper.h" +#include "compiler.h" +#include "global-handles.h" +#include "messages.h" +#include "natives.h" + +namespace v8 { +namespace internal { + +class ELF; + +class Writer BASE_EMBEDDED { + public: + explicit Writer(ELF* elf) + : elf_(elf), + position_(0), + capacity_(1024), + buffer_(reinterpret_cast<byte*>(malloc(capacity_))) { + } + + ~Writer() { + free(buffer_); + } + + uintptr_t position() const { + return position_; + } + + template<typename T> + class Slot { + public: + Slot(Writer* w, uintptr_t offset) : w_(w), offset_(offset) { } + + T* operator-> () { + return w_->RawSlotAt<T>(offset_); + } + + void set(const T& value) { + *w_->RawSlotAt<T>(offset_) = value; + } + + Slot<T> at(int i) { + return Slot<T>(w_, offset_ + sizeof(T) * i); + } + + private: + Writer* w_; + uintptr_t offset_; + }; + + template<typename T> + void Write(const T& val) { + Ensure(position_ + sizeof(T)); + *RawSlotAt<T>(position_) = val; + position_ += sizeof(T); + } + + template<typename T> + Slot<T> SlotAt(uintptr_t offset) { + Ensure(offset + sizeof(T)); + return Slot<T>(this, offset); + } + + template<typename T> + Slot<T> CreateSlotHere() { + return CreateSlotsHere<T>(1); + } + + template<typename T> + Slot<T> CreateSlotsHere(uint32_t count) { + uintptr_t slot_position = position_; + position_ += sizeof(T) * count; + Ensure(position_); + return SlotAt<T>(slot_position); + } + + void Ensure(uintptr_t pos) { + if (capacity_ < pos) { + while (capacity_ < pos) capacity_ *= 2; + buffer_ = reinterpret_cast<byte*>(realloc(buffer_, capacity_)); + } + } + + ELF* elf() { return elf_; } + + byte* buffer() { return buffer_; } + + void Align(uintptr_t align) { + uintptr_t delta = position_ % align; + if (delta == 0) return; + uintptr_t padding = align - delta; + Ensure(position_ += padding); + ASSERT((position_ % align) == 0); + } + + void WriteULEB128(uintptr_t value) { + do { + uint8_t byte = value & 0x7F; + value >>= 7; + if (value != 0) byte |= 0x80; + Write<uint8_t>(byte); + } while (value != 0); + } + + void WriteSLEB128(intptr_t value) { + bool more = true; + while (more) { + int8_t byte = value & 0x7F; + bool byte_sign = byte & 0x40; + value >>= 7; + + if ((value == 0 && !byte_sign) || (value == -1 && byte_sign)) { + more = false; + } else { + byte |= 0x80; + } + + Write<int8_t>(byte); + } + } + + void WriteString(const char* str) { + do { + Write<char>(*str); + } while (*str++); + } + + private: + template<typename T> friend class Slot; + + template<typename T> + T* RawSlotAt(uintptr_t offset) { + ASSERT(offset < capacity_ && offset + sizeof(T) <= capacity_); + return reinterpret_cast<T*>(&buffer_[offset]); + } + + ELF* elf_; + uintptr_t position_; + uintptr_t capacity_; + byte* buffer_; +}; + +class StringTable; + +class ELFSection : public ZoneObject { + public: + struct Header { + uint32_t name; + uint32_t type; + uintptr_t flags; + uintptr_t address; + uintptr_t offset; + uintptr_t size; + uint32_t link; + uint32_t info; + uintptr_t alignment; + uintptr_t entry_size; + }; + + enum Type { + TYPE_NULL = 0, + TYPE_PROGBITS = 1, + TYPE_SYMTAB = 2, + TYPE_STRTAB = 3, + TYPE_RELA = 4, + TYPE_HASH = 5, + TYPE_DYNAMIC = 6, + TYPE_NOTE = 7, + TYPE_NOBITS = 8, + TYPE_REL = 9, + TYPE_SHLIB = 10, + TYPE_DYNSYM = 11, + TYPE_LOPROC = 0x70000000, + TYPE_HIPROC = 0x7fffffff, + TYPE_LOUSER = 0x80000000, + TYPE_HIUSER = 0xffffffff + }; + + enum Flags { + FLAG_WRITE = 1, + FLAG_ALLOC = 2, + FLAG_EXEC = 4 + }; + + enum SpecialIndexes { + INDEX_ABSOLUTE = 0xfff1 + }; + + ELFSection(const char* name, Type type, uintptr_t align) + : name_(name), type_(type), align_(align) { } + + virtual ~ELFSection() { } + + void PopulateHeader(Writer::Slot<Header> header, StringTable* strtab); + + virtual void WriteBody(Writer::Slot<Header> header, Writer* w) { + uintptr_t start = w->position(); + if (WriteBody(w)) { + uintptr_t end = w->position(); + header->offset = start; + header->size = end - start; + } + } + + virtual bool WriteBody(Writer* w) { + return false; + } + + uint16_t index() const { return index_; } + void set_index(uint16_t index) { index_ = index; } + + protected: + virtual void PopulateHeader(Writer::Slot<Header> header) { + header->flags = 0; + header->address = 0; + header->offset = 0; + header->size = 0; + header->link = 0; + header->info = 0; + header->entry_size = 0; + } + + + private: + const char* name_; + Type type_; + uintptr_t align_; + uint16_t index_; +}; + + +class FullHeaderELFSection : public ELFSection { + public: + FullHeaderELFSection(const char* name, + Type type, + uintptr_t align, + uintptr_t addr, + uintptr_t offset, + uintptr_t size, + uintptr_t flags) + : ELFSection(name, type, align), + addr_(addr), + offset_(offset), + size_(size), + flags_(flags) { } + + protected: + virtual void PopulateHeader(Writer::Slot<Header> header) { + ELFSection::PopulateHeader(header); + header->address = addr_; + header->offset = offset_; + header->size = size_; + header->flags = flags_; + } + + private: + uintptr_t addr_; + uintptr_t offset_; + uintptr_t size_; + uintptr_t flags_; +}; + + +class StringTable : public ELFSection { + public: + explicit StringTable(const char* name) + : ELFSection(name, TYPE_STRTAB, 1), writer_(NULL), offset_(0), size_(0) { + } + + uintptr_t Add(const char* str) { + if (*str == '\0') return 0; + + uintptr_t offset = size_; + WriteString(str); + return offset; + } + + void AttachWriter(Writer* w) { + writer_ = w; + offset_ = writer_->position(); + + // First entry in the string table should be an empty string. + WriteString(""); + } + + void DetachWriter() { + writer_ = NULL; + } + + virtual void WriteBody(Writer::Slot<Header> header, Writer* w) { + ASSERT(writer_ == NULL); + header->offset = offset_; + header->size = size_; + } + + private: + void WriteString(const char* str) { + uintptr_t written = 0; + do { + writer_->Write(*str); + written++; + } while (*str++); + size_ += written; + } + + Writer* writer_; + + uintptr_t offset_; + uintptr_t size_; +}; + + +void ELFSection::PopulateHeader(Writer::Slot<ELFSection::Header> header, + StringTable* strtab) { + header->name = strtab->Add(name_); + header->type = type_; + header->alignment = align_; + PopulateHeader(header); +} + + +class ELF BASE_EMBEDDED { + public: + ELF() : sections_(6) { + sections_.Add(new ELFSection("", ELFSection::TYPE_NULL, 0)); + sections_.Add(new StringTable(".shstrtab")); + } + + void Write(Writer* w) { + WriteHeader(w); + WriteSectionTable(w); + WriteSections(w); + } + + ELFSection* SectionAt(uint32_t index) { + return sections_[index]; + } + + uint32_t AddSection(ELFSection* section) { + sections_.Add(section); + section->set_index(sections_.length() - 1); + return sections_.length() - 1; + } + + private: + struct ELFHeader { + uint8_t ident[16]; + uint16_t type; + uint16_t machine; + uint32_t version; + uintptr_t entry; + uintptr_t pht_offset; + uintptr_t sht_offset; + uint32_t flags; + uint16_t header_size; + uint16_t pht_entry_size; + uint16_t pht_entry_num; + uint16_t sht_entry_size; + uint16_t sht_entry_num; + uint16_t sht_strtab_index; + }; + + + void WriteHeader(Writer* w) { + ASSERT(w->position() == 0); + Writer::Slot<ELFHeader> header = w->CreateSlotHere<ELFHeader>(); +#if defined(V8_TARGET_ARCH_IA32) + const uint8_t ident[16] = + { 0x7f, 'E', 'L', 'F', 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +#elif defined(V8_TARGET_ARCH_X64) + const uint8_t ident[16] = + { 0x7f, 'E', 'L', 'F', 2, 1, 1, 0, 0, 0 , 0, 0, 0, 0, 0, 0}; +#else +#error Unsupported target architecture. +#endif + memcpy(header->ident, ident, 16); + header->type = 1; +#if defined(V8_TARGET_ARCH_IA32) + header->machine = 3; +#elif defined(V8_TARGET_ARCH_X64) + // Processor identification value for x64 is 62 as defined in + // System V ABI, AMD64 Supplement + // http://www.x86-64.org/documentation/abi.pdf + header->machine = 62; +#else +#error Unsupported target architecture. +#endif + header->version = 1; + header->entry = 0; + header->pht_offset = 0; + header->sht_offset = sizeof(ELFHeader); // Section table follows header. + header->flags = 0; + header->header_size = sizeof(ELFHeader); + header->pht_entry_size = 0; + header->pht_entry_num = 0; + header->sht_entry_size = sizeof(ELFSection::Header); + header->sht_entry_num = sections_.length(); + header->sht_strtab_index = 1; + } + + void WriteSectionTable(Writer* w) { + // Section headers table immediately follows file header. + ASSERT(w->position() == sizeof(ELFHeader)); + + Writer::Slot<ELFSection::Header> headers = + w->CreateSlotsHere<ELFSection::Header>(sections_.length()); + + // String table for section table is the first section. + StringTable* strtab = static_cast<StringTable*>(SectionAt(1)); + strtab->AttachWriter(w); + for (int i = 0, length = sections_.length(); + i < length; + i++) { + sections_[i]->PopulateHeader(headers.at(i), strtab); + } + strtab->DetachWriter(); + } + + int SectionHeaderPosition(uint32_t section_index) { + return sizeof(ELFHeader) + sizeof(ELFSection::Header) * section_index; + } + + void WriteSections(Writer* w) { + Writer::Slot<ELFSection::Header> headers = + w->SlotAt<ELFSection::Header>(sizeof(ELFHeader)); + + for (int i = 0, length = sections_.length(); + i < length; + i++) { + sections_[i]->WriteBody(headers.at(i), w); + } + } + + ZoneList<ELFSection*> sections_; +}; + + +class ELFSymbol BASE_EMBEDDED { + public: + enum Type { + TYPE_NOTYPE = 0, + TYPE_OBJECT = 1, + TYPE_FUNC = 2, + TYPE_SECTION = 3, + TYPE_FILE = 4, + TYPE_LOPROC = 13, + TYPE_HIPROC = 15 + }; + + enum Binding { + BIND_LOCAL = 0, + BIND_GLOBAL = 1, + BIND_WEAK = 2, + BIND_LOPROC = 13, + BIND_HIPROC = 15 + }; + + ELFSymbol(const char* name, + uintptr_t value, + uintptr_t size, + Binding binding, + Type type, + uint16_t section) + : name(name), + value(value), + size(size), + info((binding << 4) | type), + other(0), + section(section) { + } + + Binding binding() const { + return static_cast<Binding>(info >> 4); + } + +#if defined(V8_TARGET_ARCH_IA32) + struct SerializedLayout { + SerializedLayout(uint32_t name, + uintptr_t value, + uintptr_t size, + Binding binding, + Type type, + uint16_t section) + : name(name), + value(value), + size(size), + info((binding << 4) | type), + other(0), + section(section) { + } + + uint32_t name; + uintptr_t value; + uintptr_t size; + uint8_t info; + uint8_t other; + uint16_t section; + }; +#elif defined(V8_TARGET_ARCH_X64) + struct SerializedLayout { + SerializedLayout(uint32_t name, + uintptr_t value, + uintptr_t size, + Binding binding, + Type type, + uint16_t section) + : name(name), + info((binding << 4) | type), + other(0), + section(section), + value(value), + size(size) { + } + + uint32_t name; + uint8_t info; + uint8_t other; + uint16_t section; + uintptr_t value; + uintptr_t size; + }; +#endif + + void Write(Writer::Slot<SerializedLayout> s, StringTable* t) { + // Convert symbol names from strings to indexes in the string table. + s->name = t->Add(name); + s->value = value; + s->size = size; + s->info = info; + s->other = other; + s->section = section; + } + + private: + const char* name; + uintptr_t value; + uintptr_t size; + uint8_t info; + uint8_t other; + uint16_t section; +}; + + +class ELFSymbolTable : public ELFSection { + public: + explicit ELFSymbolTable(const char* name) + : ELFSection(name, TYPE_SYMTAB, sizeof(uintptr_t)), + locals_(1), + globals_(1) { + } + + virtual void WriteBody(Writer::Slot<Header> header, Writer* w) { + w->Align(header->alignment); + int total_symbols = locals_.length() + globals_.length() + 1; + header->offset = w->position(); + + Writer::Slot<ELFSymbol::SerializedLayout> symbols = + w->CreateSlotsHere<ELFSymbol::SerializedLayout>(total_symbols); + + header->size = w->position() - header->offset; + + // String table for this symbol table should follow it in the section table. + StringTable* strtab = + static_cast<StringTable*>(w->elf()->SectionAt(index() + 1)); + strtab->AttachWriter(w); + symbols.at(0).set(ELFSymbol::SerializedLayout(0, + 0, + 0, + ELFSymbol::BIND_LOCAL, + ELFSymbol::TYPE_NOTYPE, + 0)); + WriteSymbolsList(&locals_, symbols.at(1), strtab); + WriteSymbolsList(&globals_, symbols.at(locals_.length() + 1), strtab); + strtab->DetachWriter(); + } + + void Add(const ELFSymbol& symbol) { + if (symbol.binding() == ELFSymbol::BIND_LOCAL) { + locals_.Add(symbol); + } else { + globals_.Add(symbol); + } + } + + protected: + virtual void PopulateHeader(Writer::Slot<Header> header) { + ELFSection::PopulateHeader(header); + // We are assuming that string table will follow symbol table. + header->link = index() + 1; + header->info = locals_.length() + 1; + header->entry_size = sizeof(ELFSymbol::SerializedLayout); + } + + private: + void WriteSymbolsList(const ZoneList<ELFSymbol>* src, + Writer::Slot<ELFSymbol::SerializedLayout> dst, + StringTable* strtab) { + for (int i = 0, len = src->length(); + i < len; + i++) { + src->at(i).Write(dst.at(i), strtab); + } + } + + ZoneList<ELFSymbol> locals_; + ZoneList<ELFSymbol> globals_; +}; + + +class CodeDescription BASE_EMBEDDED { + public: + CodeDescription(const char* name, + Code* code, + Handle<Script> script, + GDBJITLineInfo* lineinfo) + : name_(name), code_(code), script_(script), lineinfo_(lineinfo) + { } + + const char* code_name() const { + return name_; + } + + uintptr_t code_size() const { + return code_->instruction_end() - code_->instruction_start(); + } + + uintptr_t code_start() const { + return (uintptr_t)code_->instruction_start(); + } + + bool is_line_info_available() { + return !script_.is_null() && + script_->source()->IsString() && + script_->HasValidSource() && + script_->name()->IsString() && + lineinfo_ != NULL; + } + + GDBJITLineInfo* lineinfo() const { return lineinfo_; } + + SmartPointer<char> filename() { + return String::cast(script_->name())->ToCString(); + } + + int GetScriptLineNumber(int pos) { + return GetScriptLineNumberSafe(script_, pos) + 1; + } + + private: + const char* name_; + Code* code_; + Handle<Script> script_; + GDBJITLineInfo* lineinfo_; +}; + + +static void CreateSymbolsTable(CodeDescription* desc, + ELF* elf, + int text_section_index) { + ELFSymbolTable* symtab = new ELFSymbolTable(".symtab"); + StringTable* strtab = new StringTable(".strtab"); + + // Symbol table should be followed by the linked string table. + elf->AddSection(symtab); + elf->AddSection(strtab); + + symtab->Add(ELFSymbol("V8 Code", + 0, + 0, + ELFSymbol::BIND_LOCAL, + ELFSymbol::TYPE_FILE, + ELFSection::INDEX_ABSOLUTE)); + + symtab->Add(ELFSymbol(desc->code_name(), + 0, + desc->code_size(), + ELFSymbol::BIND_GLOBAL, + ELFSymbol::TYPE_FUNC, + text_section_index)); +} + + +class DebugInfoSection : public ELFSection { + public: + explicit DebugInfoSection(CodeDescription* desc) + : ELFSection(".debug_info", TYPE_PROGBITS, 1), desc_(desc) { } + + bool WriteBody(Writer* w) { + Writer::Slot<uint32_t> size = w->CreateSlotHere<uint32_t>(); + uintptr_t start = w->position(); + w->Write<uint16_t>(2); // DWARF version. + w->Write<uint32_t>(0); // Abbreviation table offset. + w->Write<uint8_t>(sizeof(intptr_t)); + + w->WriteULEB128(1); // Abbreviation code. + w->WriteString(*desc_->filename()); + w->Write<intptr_t>(desc_->code_start()); + w->Write<intptr_t>(desc_->code_start() + desc_->code_size()); + w->Write<uint32_t>(0); + size.set(static_cast<uint32_t>(w->position() - start)); + return true; + } + + private: + CodeDescription* desc_; +}; + + +class DebugAbbrevSection : public ELFSection { + public: + DebugAbbrevSection() : ELFSection(".debug_abbrev", TYPE_PROGBITS, 1) { } + + // DWARF2 standard, figure 14. + enum DWARF2Tags { + DW_TAG_COMPILE_UNIT = 0x11 + }; + + // DWARF2 standard, figure 16. + enum DWARF2ChildrenDetermination { + DW_CHILDREN_NO = 0, + DW_CHILDREN_YES = 1 + }; + + // DWARF standard, figure 17. + enum DWARF2Attribute { + DW_AT_NAME = 0x3, + DW_AT_STMT_LIST = 0x10, + DW_AT_LOW_PC = 0x11, + DW_AT_HIGH_PC = 0x12 + }; + + // DWARF2 standard, figure 19. + enum DWARF2AttributeForm { + DW_FORM_ADDR = 0x1, + DW_FORM_STRING = 0x8, + DW_FORM_DATA4 = 0x6 + }; + + bool WriteBody(Writer* w) { + w->WriteULEB128(1); + w->WriteULEB128(DW_TAG_COMPILE_UNIT); + w->Write<uint8_t>(DW_CHILDREN_NO); + w->WriteULEB128(DW_AT_NAME); + w->WriteULEB128(DW_FORM_STRING); + w->WriteULEB128(DW_AT_LOW_PC); + w->WriteULEB128(DW_FORM_ADDR); + w->WriteULEB128(DW_AT_HIGH_PC); + w->WriteULEB128(DW_FORM_ADDR); + w->WriteULEB128(DW_AT_STMT_LIST); + w->WriteULEB128(DW_FORM_DATA4); + w->WriteULEB128(0); + w->WriteULEB128(0); + w->WriteULEB128(0); + return true; + } +}; + + +class DebugLineSection : public ELFSection { + public: + explicit DebugLineSection(CodeDescription* desc) + : ELFSection(".debug_line", TYPE_PROGBITS, 1), + desc_(desc) { } + + // DWARF2 standard, figure 34. + enum DWARF2Opcodes { + DW_LNS_COPY = 1, + DW_LNS_ADVANCE_PC = 2, + DW_LNS_ADVANCE_LINE = 3, + DW_LNS_SET_FILE = 4, + DW_LNS_SET_COLUMN = 5, + DW_LNS_NEGATE_STMT = 6 + }; + + // DWARF2 standard, figure 35. + enum DWARF2ExtendedOpcode { + DW_LNE_END_SEQUENCE = 1, + DW_LNE_SET_ADDRESS = 2, + DW_LNE_DEFINE_FILE = 3 + }; + + bool WriteBody(Writer* w) { + // Write prologue. + Writer::Slot<uint32_t> total_length = w->CreateSlotHere<uint32_t>(); + uintptr_t start = w->position(); + + w->Write<uint16_t>(2); // Field version. + Writer::Slot<uint32_t> prologue_length = w->CreateSlotHere<uint32_t>(); + uintptr_t prologue_start = w->position(); + w->Write<uint8_t>(1); // Field minimum_instruction_length. + w->Write<uint8_t>(1); // Field default_is_stmt. + w->Write<int8_t>(0); // Field line_base. + w->Write<uint8_t>(2); // Field line_range. + w->Write<uint8_t>(DW_LNS_NEGATE_STMT + 1); // Field opcode_base. + w->Write<uint8_t>(0); // DW_LNS_COPY operands count. + w->Write<uint8_t>(1); // DW_LNS_ADVANCE_PC operands count. + w->Write<uint8_t>(1); // DW_LNS_ADVANCE_LINE operands count. + w->Write<uint8_t>(1); // DW_LNS_SET_FILE operands count. + w->Write<uint8_t>(1); // DW_LNS_SET_COLUMN operands count. + w->Write<uint8_t>(0); // DW_LNS_NEGATE_STMT operands count. + w->Write<uint8_t>(0); // Empty include_directories sequence. + w->WriteString(*desc_->filename()); // File name. + w->WriteULEB128(0); // Current directory. + w->WriteULEB128(0); // Unknown modification time. + w->WriteULEB128(0); // Unknown file size. + w->Write<uint8_t>(0); + prologue_length.set(static_cast<uint32_t>(w->position() - prologue_start)); + + WriteExtendedOpcode(w, DW_LNE_SET_ADDRESS, sizeof(intptr_t)); + w->Write<intptr_t>(desc_->code_start()); + + intptr_t pc = 0; + intptr_t line = 1; + bool is_statement = true; + + List<GDBJITLineInfo::PCInfo>* pc_info = desc_->lineinfo()->pc_info(); + pc_info->Sort(&ComparePCInfo); + for (int i = 0; i < pc_info->length(); i++) { + GDBJITLineInfo::PCInfo* info = &pc_info->at(i); + uintptr_t pc_diff = info->pc_ - pc; + ASSERT(info->pc_ >= pc); + if (pc_diff != 0) { + w->Write<uint8_t>(DW_LNS_ADVANCE_PC); + w->WriteSLEB128(pc_diff); + pc += pc_diff; + } + intptr_t line_diff = desc_->GetScriptLineNumber(info->pos_) - line; + if (line_diff != 0) { + w->Write<uint8_t>(DW_LNS_ADVANCE_LINE); + w->WriteSLEB128(line_diff); + line += line_diff; + } + if (is_statement != info->is_statement_) { + w->Write<uint8_t>(DW_LNS_NEGATE_STMT); + is_statement = !is_statement; + } + if (pc_diff != 0 || i == 0) { + w->Write<uint8_t>(DW_LNS_COPY); + } + } + WriteExtendedOpcode(w, DW_LNE_END_SEQUENCE, 0); + total_length.set(static_cast<uint32_t>(w->position() - start)); + return true; + } + + private: + void WriteExtendedOpcode(Writer* w, + DWARF2ExtendedOpcode op, + size_t operands_size) { + w->Write<uint8_t>(0); + w->WriteULEB128(operands_size + 1); + w->Write<uint8_t>(op); + } + + static int ComparePCInfo(const GDBJITLineInfo::PCInfo* a, + const GDBJITLineInfo::PCInfo* b) { + if (a->pc_ == b->pc_) { + if (a->is_statement_ != b->is_statement_) { + return b->is_statement_ ? +1 : -1; + } + return 0; + } else if (a->pc_ > b->pc_) { + return +1; + } else { + return -1; + } + } + + CodeDescription* desc_; +}; + + +static void CreateDWARFSections(CodeDescription* desc, ELF* elf) { + if (desc->is_line_info_available()) { + elf->AddSection(new DebugInfoSection(desc)); + elf->AddSection(new DebugAbbrevSection); + elf->AddSection(new DebugLineSection(desc)); + } +} + + +// ------------------------------------------------------------------- +// Binary GDB JIT Interface as described in +// http://sourceware.org/gdb/onlinedocs/gdb/Declarations.html +extern "C" { + typedef enum { + JIT_NOACTION = 0, + JIT_REGISTER_FN, + JIT_UNREGISTER_FN + } JITAction; + + struct JITCodeEntry { + JITCodeEntry* next_; + JITCodeEntry* prev_; + Address symfile_addr_; + uint64_t symfile_size_; + }; + + struct JITDescriptor { + uint32_t version_; + uint32_t action_flag_; + JITCodeEntry *relevant_entry_; + JITCodeEntry *first_entry_; + }; + + // GDB will place breakpoint into this function. + // To prevent GCC from inlining or removing it we place noinline attribute + // and inline assembler statement inside. + void __attribute__((noinline)) __jit_debug_register_code() { + __asm__(""); + } + + // GDB will inspect contents of this descriptor. + // Static initialization is necessary to prevent GDB from seeing + // uninitialized descriptor. + JITDescriptor __jit_debug_descriptor = { 1, 0, 0, 0 }; +} + + +static JITCodeEntry* CreateCodeEntry(Address symfile_addr, + uintptr_t symfile_size) { + JITCodeEntry* entry = static_cast<JITCodeEntry*>( + malloc(sizeof(JITCodeEntry) + symfile_size)); + + entry->symfile_addr_ = reinterpret_cast<Address>(entry + 1); + entry->symfile_size_ = symfile_size; + memcpy(entry->symfile_addr_, symfile_addr, symfile_size); + + entry->prev_ = entry->next_ = NULL; + + return entry; +} + + +static void DestroyCodeEntry(JITCodeEntry* entry) { + free(entry); +} + + +static void RegisterCodeEntry(JITCodeEntry* entry) { + entry->next_ = __jit_debug_descriptor.first_entry_; + if (entry->next_ != NULL) entry->next_->prev_ = entry; + __jit_debug_descriptor.first_entry_ = + __jit_debug_descriptor.relevant_entry_ = entry; + + __jit_debug_descriptor.action_flag_ = JIT_REGISTER_FN; + __jit_debug_register_code(); +} + + +static void UnregisterCodeEntry(JITCodeEntry* entry) { + if (entry->prev_ != NULL) { + entry->prev_->next_ = entry->next_; + } else { + __jit_debug_descriptor.first_entry_ = entry->next_; + } + + if (entry->next_ != NULL) { + entry->next_->prev_ = entry->prev_; + } + + __jit_debug_descriptor.relevant_entry_ = entry; + __jit_debug_descriptor.action_flag_ = JIT_UNREGISTER_FN; + __jit_debug_register_code(); +} + + +static JITCodeEntry* CreateELFObject(CodeDescription* desc) { + ZoneScope zone_scope(DELETE_ON_EXIT); + + ELF elf; + Writer w(&elf); + + int text_section_index = elf.AddSection( + new FullHeaderELFSection(".text", + ELFSection::TYPE_NOBITS, + kCodeAlignment, + desc->code_start(), + 0, + desc->code_size(), + ELFSection::FLAG_ALLOC | ELFSection::FLAG_EXEC)); + + CreateSymbolsTable(desc, &elf, text_section_index); + + CreateDWARFSections(desc, &elf); + + elf.Write(&w); + + return CreateCodeEntry(w.buffer(), w.position()); +} + + +static bool SameCodeObjects(void* key1, void* key2) { + return key1 == key2; +} + + +static HashMap entries(&SameCodeObjects); + + +static uint32_t HashForCodeObject(Code* code) { + static const uintptr_t kGoldenRatio = 2654435761u; + uintptr_t hash = reinterpret_cast<uintptr_t>(code->address()); + return static_cast<uint32_t>((hash >> kCodeAlignmentBits) * kGoldenRatio); +} + + +static const intptr_t kLineInfoTag = 0x1; + + +static bool IsLineInfoTagged(void* ptr) { + return 0 != (reinterpret_cast<intptr_t>(ptr) & kLineInfoTag); +} + + +static void* TagLineInfo(GDBJITLineInfo* ptr) { + return reinterpret_cast<void*>( + reinterpret_cast<intptr_t>(ptr) | kLineInfoTag); +} + + +static GDBJITLineInfo* UntagLineInfo(void* ptr) { + return reinterpret_cast<GDBJITLineInfo*>( + reinterpret_cast<intptr_t>(ptr) & ~kLineInfoTag); +} + + +void GDBJITInterface::AddCode(Handle<String> name, + Handle<Script> script, + Handle<Code> code) { + if (!FLAG_gdbjit) return; + + // Force initialization of line_ends array. + GetScriptLineNumber(script, 0); + + if (!name.is_null()) { + SmartPointer<char> name_cstring = name->ToCString(DISALLOW_NULLS); + AddCode(*name_cstring, *code, *script); + } else { + AddCode("", *code, *script); + } +} + + +void GDBJITInterface::AddCode(const char* name, + Code* code, + Script* script) { + if (!FLAG_gdbjit) return; + AssertNoAllocation no_gc; + + HashMap::Entry* e = entries.Lookup(code, HashForCodeObject(code), true); + if (e->value != NULL && !IsLineInfoTagged(e->value)) return; + + GDBJITLineInfo* lineinfo = UntagLineInfo(e->value); + CodeDescription code_desc(name, + code, + script != NULL ? Handle<Script>(script) + : Handle<Script>(), + lineinfo); + + if (!FLAG_gdbjit_full && !code_desc.is_line_info_available()) { + delete lineinfo; + entries.Remove(code, HashForCodeObject(code)); + return; + } + + JITCodeEntry* entry = CreateELFObject(&code_desc); + ASSERT(!IsLineInfoTagged(entry)); + + delete lineinfo; + e->value = entry; + + RegisterCodeEntry(entry); +} + + +void GDBJITInterface::AddCode(GDBJITInterface::CodeTag tag, + const char* name, + Code* code) { + if (!FLAG_gdbjit) return; + + EmbeddedVector<char, 256> buffer; + StringBuilder builder(buffer.start(), buffer.length()); + + builder.AddString(Tag2String(tag)); + if ((name != NULL) && (*name != '\0')) { + builder.AddString(": "); + builder.AddString(name); + } else { + builder.AddFormatted(": code object %p", static_cast<void*>(code)); + } + + AddCode(builder.Finalize(), code); +} + + +void GDBJITInterface::AddCode(GDBJITInterface::CodeTag tag, + String* name, + Code* code) { + if (!FLAG_gdbjit) return; + AddCode(tag, name != NULL ? *name->ToCString(DISALLOW_NULLS) : NULL, code); +} + + +void GDBJITInterface::AddCode(GDBJITInterface::CodeTag tag, Code* code) { + if (!FLAG_gdbjit) return; + + AddCode(tag, "", code); +} + + +void GDBJITInterface::RemoveCode(Code* code) { + if (!FLAG_gdbjit) return; + + HashMap::Entry* e = entries.Lookup(code, HashForCodeObject(code), false); + if (e == NULL) return; + + if (IsLineInfoTagged(e->value)) { + delete UntagLineInfo(e->value); + } else { + JITCodeEntry* entry = static_cast<JITCodeEntry*>(e->value); + UnregisterCodeEntry(entry); + DestroyCodeEntry(entry); + } + e->value = NULL; + entries.Remove(code, HashForCodeObject(code)); +} + + +void GDBJITInterface::RegisterDetailedLineInfo(Code* code, + GDBJITLineInfo* line_info) { + ASSERT(!IsLineInfoTagged(line_info)); + HashMap::Entry* e = entries.Lookup(code, HashForCodeObject(code), true); + ASSERT(e->value == NULL); + e->value = TagLineInfo(line_info); +} + + +} } // namespace v8::internal +#endif diff --git a/deps/v8/src/gdb-jit.h b/deps/v8/src/gdb-jit.h new file mode 100644 index 0000000000..5d348b69a1 --- /dev/null +++ b/deps/v8/src/gdb-jit.h @@ -0,0 +1,136 @@ +// Copyright 2010 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. + +#ifndef V8_GDB_JIT_H_ +#define V8_GDB_JIT_H_ + +// +// Basic implementation of GDB JIT Interface client. +// GBD JIT Interface is supported in GDB 7.0 and above. +// Currently on x64 and ia32 architectures and Linux OS are supported. +// + +#ifdef ENABLE_GDB_JIT_INTERFACE +#include "v8.h" +#include "factory.h" + +namespace v8 { +namespace internal { + +#define CODE_TAGS_LIST(V) \ + V(LOAD_IC) \ + V(KEYED_LOAD_IC) \ + V(STORE_IC) \ + V(KEYED_STORE_IC) \ + V(CALL_IC) \ + V(CALL_INITIALIZE) \ + V(CALL_PRE_MONOMORPHIC) \ + V(CALL_NORMAL) \ + V(CALL_MEGAMORPHIC) \ + V(CALL_MISS) \ + V(STUB) \ + V(BUILTIN) \ + V(SCRIPT) \ + V(EVAL) + +class GDBJITLineInfo : public Malloced { + public: + GDBJITLineInfo() + : pc_info_(10) { } + + void SetPosition(intptr_t pc, int pos, bool is_statement) { + AddPCInfo(PCInfo(pc, pos, is_statement)); + } + + struct PCInfo { + PCInfo(intptr_t pc, int pos, bool is_statement) + : pc_(pc), pos_(pos), is_statement_(is_statement) { } + + intptr_t pc_; + int pos_; + bool is_statement_; + }; + + List<PCInfo>* pc_info() { + return &pc_info_; + } + + private: + void AddPCInfo(const PCInfo& pc_info) { + pc_info_.Add(pc_info); + } + + List<PCInfo> pc_info_; +}; + + +class GDBJITInterface: public AllStatic { + public: + enum CodeTag { +#define V(x) x, + CODE_TAGS_LIST(V) +#undef V + TAG_COUNT + }; + + static const char* Tag2String(CodeTag tag) { + switch (tag) { +#define V(x) case x: return #x; + CODE_TAGS_LIST(V) +#undef V + default: + return NULL; + } + } + + static void AddCode(const char* name, + Code* code, + Script* script = NULL); + + static void AddCode(Handle<String> name, + Handle<Script> script, + Handle<Code> code); + + static void AddCode(CodeTag tag, String* name, Code* code); + + static void AddCode(CodeTag tag, const char* name, Code* code); + + static void AddCode(CodeTag tag, Code* code); + + static void RemoveCode(Code* code); + + static void RegisterDetailedLineInfo(Code* code, GDBJITLineInfo* line_info); +}; + +#define GDBJIT(action) GDBJITInterface::action + +} } // namespace v8::internal +#else +#define GDBJIT(action) ((void) 0) +#endif + +#endif diff --git a/deps/v8/src/hydrogen-instructions.cc b/deps/v8/src/hydrogen-instructions.cc index 89478f5e33..b13bb0c4d8 100644 --- a/deps/v8/src/hydrogen-instructions.cc +++ b/deps/v8/src/hydrogen-instructions.cc @@ -996,7 +996,8 @@ HConstant::HConstant(Handle<Object> handle, Representation r) SetFlag(kUseGVN); if (handle_->IsNumber()) { double n = handle_->Number(); - has_int32_value_ = static_cast<double>(static_cast<int32_t>(n)) == n; + double roundtrip_value = static_cast<double>(static_cast<int32_t>(n)); + has_int32_value_ = BitCast<int64_t>(roundtrip_value) == BitCast<int64_t>(n); if (has_int32_value_) int32_value_ = static_cast<int32_t>(n); double_value_ = n; has_double_value_ = true; diff --git a/deps/v8/src/hydrogen-instructions.h b/deps/v8/src/hydrogen-instructions.h index 4a23f2a327..eebec5a9e2 100644 --- a/deps/v8/src/hydrogen-instructions.h +++ b/deps/v8/src/hydrogen-instructions.h @@ -773,6 +773,10 @@ class HInstruction: public HValue { virtual void Verify() const; #endif + // Returns whether this is some kind of deoptimizing check + // instruction. + virtual bool IsCheckInstruction() const { return false; } + DECLARE_INSTRUCTION(Instruction) protected: @@ -1504,6 +1508,8 @@ class HCheckMap: public HUnaryOperation { SetFlag(kDependsOnMaps); } + virtual bool IsCheckInstruction() const { return true; } + virtual Representation RequiredInputRepresentation(int index) const { return Representation::Tagged(); } @@ -1537,6 +1543,8 @@ class HCheckFunction: public HUnaryOperation { SetFlag(kUseGVN); } + virtual bool IsCheckInstruction() const { return true; } + virtual Representation RequiredInputRepresentation(int index) const { return Representation::Tagged(); } @@ -1573,6 +1581,8 @@ class HCheckInstanceType: public HUnaryOperation { SetFlag(kUseGVN); } + virtual bool IsCheckInstruction() const { return true; } + virtual Representation RequiredInputRepresentation(int index) const { return Representation::Tagged(); } @@ -1610,6 +1620,8 @@ class HCheckNonSmi: public HUnaryOperation { SetFlag(kUseGVN); } + virtual bool IsCheckInstruction() const { return true; } + virtual Representation RequiredInputRepresentation(int index) const { return Representation::Tagged(); } @@ -1632,6 +1644,8 @@ class HCheckPrototypeMaps: public HInstruction { SetFlag(kDependsOnMaps); } + virtual bool IsCheckInstruction() const { return true; } + #ifdef DEBUG virtual void Verify() const; #endif @@ -1668,6 +1682,8 @@ class HCheckSmi: public HUnaryOperation { SetFlag(kUseGVN); } + virtual bool IsCheckInstruction() const { return true; } + virtual Representation RequiredInputRepresentation(int index) const { return Representation::Tagged(); } @@ -1996,6 +2012,8 @@ class HBoundsCheck: public HBinaryOperation { SetFlag(kUseGVN); } + virtual bool IsCheckInstruction() const { return true; } + virtual Representation RequiredInputRepresentation(int index) const { return Representation::Integer32(); } diff --git a/deps/v8/src/hydrogen.cc b/deps/v8/src/hydrogen.cc index 7aa66fd619..da41ef94dc 100644 --- a/deps/v8/src/hydrogen.cc +++ b/deps/v8/src/hydrogen.cc @@ -687,6 +687,11 @@ HGraph::HGraph(CompilationInfo* info) } +bool HGraph::AllowAggressiveOptimizations() const { + return info()->shared_info()->opt_count() + 1 < Compiler::kDefaultMaxOptCount; +} + + Handle<Code> HGraph::Compile() { int values = GetMaximumValueID(); if (values > LAllocator::max_initial_value_ids()) { @@ -1453,8 +1458,12 @@ void HGlobalValueNumberer::ProcessLoopBlock(HBasicBlock* block, // about code that was never executed. bool HGlobalValueNumberer::ShouldMove(HInstruction* instr, HBasicBlock* loop_header) { - if (!instr->IsChange() && - FLAG_aggressive_loop_invariant_motion) return true; + if (FLAG_aggressive_loop_invariant_motion && + !instr->IsChange() && + (!instr->IsCheckInstruction() || + graph_->AllowAggressiveOptimizations())) { + return true; + } HBasicBlock* block = instr->block(); bool result = true; if (block != loop_header) { diff --git a/deps/v8/src/hydrogen.h b/deps/v8/src/hydrogen.h index 35165ae97a..19f898381f 100644 --- a/deps/v8/src/hydrogen.h +++ b/deps/v8/src/hydrogen.h @@ -296,6 +296,9 @@ class HGraph: public HSubgraph { explicit HGraph(CompilationInfo* info); CompilationInfo* info() const { return info_; } + + bool AllowAggressiveOptimizations() const; + const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; } const ZoneList<HPhi*>* phi_list() const { return phi_list_; } Handle<String> debug_name() const { return info_->function()->debug_name(); } diff --git a/deps/v8/src/ia32/ic-ia32.cc b/deps/v8/src/ia32/ic-ia32.cc index 90bfd4b664..f570fe01e9 100644 --- a/deps/v8/src/ia32/ic-ia32.cc +++ b/deps/v8/src/ia32/ic-ia32.cc @@ -1231,8 +1231,12 @@ static void GenerateMonomorphicCacheProbe(MacroAssembler* masm, Label number, non_number, non_string, boolean, probe, miss; // Probe the stub cache. - Code::Flags flags = - Code::ComputeFlags(kind, NOT_IN_LOOP, MONOMORPHIC, NORMAL, argc); + Code::Flags flags = Code::ComputeFlags(kind, + NOT_IN_LOOP, + MONOMORPHIC, + Code::kNoExtraICState, + NORMAL, + argc); StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, eax); // If the stub cache probing failed, the receiver might be a value. @@ -1325,7 +1329,9 @@ static void GenerateCallNormal(MacroAssembler* masm, int argc) { } -static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) { +static void GenerateCallMiss(MacroAssembler* masm, + int argc, + IC::UtilityId id) { // ----------- S t a t e ------------- // -- ecx : name // -- esp[0] : return address diff --git a/deps/v8/src/ia32/lithium-codegen-ia32.cc b/deps/v8/src/ia32/lithium-codegen-ia32.cc index 24ee1fefdb..2d3eac1480 100644 --- a/deps/v8/src/ia32/lithium-codegen-ia32.cc +++ b/deps/v8/src/ia32/lithium-codegen-ia32.cc @@ -58,157 +58,6 @@ class SafepointGenerator : public PostCallGenerator { }; -class LGapNode: public ZoneObject { - public: - explicit LGapNode(LOperand* operand) - : operand_(operand), resolved_(false), visited_id_(-1) { } - - LOperand* operand() const { return operand_; } - bool IsResolved() const { return !IsAssigned() || resolved_; } - void MarkResolved() { - ASSERT(!IsResolved()); - resolved_ = true; - } - int visited_id() const { return visited_id_; } - void set_visited_id(int id) { - ASSERT(id > visited_id_); - visited_id_ = id; - } - - bool IsAssigned() const { return assigned_from_.is_set(); } - LGapNode* assigned_from() const { return assigned_from_.get(); } - void set_assigned_from(LGapNode* n) { assigned_from_.set(n); } - - private: - LOperand* operand_; - SetOncePointer<LGapNode> assigned_from_; - bool resolved_; - int visited_id_; -}; - - -LGapResolver::LGapResolver() - : nodes_(32), - identified_cycles_(4), - result_(16), - next_visited_id_(0) { -} - - -const ZoneList<LMoveOperands>* LGapResolver::Resolve( - const ZoneList<LMoveOperands>* moves, - LOperand* marker_operand) { - nodes_.Rewind(0); - identified_cycles_.Rewind(0); - result_.Rewind(0); - next_visited_id_ = 0; - - for (int i = 0; i < moves->length(); ++i) { - LMoveOperands move = moves->at(i); - if (!move.IsRedundant()) RegisterMove(move); - } - - for (int i = 0; i < identified_cycles_.length(); ++i) { - ResolveCycle(identified_cycles_[i], marker_operand); - } - - int unresolved_nodes; - do { - unresolved_nodes = 0; - for (int j = 0; j < nodes_.length(); j++) { - LGapNode* node = nodes_[j]; - if (!node->IsResolved() && node->assigned_from()->IsResolved()) { - AddResultMove(node->assigned_from(), node); - node->MarkResolved(); - } - if (!node->IsResolved()) ++unresolved_nodes; - } - } while (unresolved_nodes > 0); - return &result_; -} - - -void LGapResolver::AddResultMove(LGapNode* from, LGapNode* to) { - AddResultMove(from->operand(), to->operand()); -} - - -void LGapResolver::AddResultMove(LOperand* from, LOperand* to) { - result_.Add(LMoveOperands(from, to)); -} - - -void LGapResolver::ResolveCycle(LGapNode* start, LOperand* marker_operand) { - ZoneList<LOperand*> cycle_operands(8); - cycle_operands.Add(marker_operand); - LGapNode* cur = start; - do { - cur->MarkResolved(); - cycle_operands.Add(cur->operand()); - cur = cur->assigned_from(); - } while (cur != start); - cycle_operands.Add(marker_operand); - - for (int i = cycle_operands.length() - 1; i > 0; --i) { - LOperand* from = cycle_operands[i]; - LOperand* to = cycle_operands[i - 1]; - AddResultMove(from, to); - } -} - - -bool LGapResolver::CanReach(LGapNode* a, LGapNode* b, int visited_id) { - ASSERT(a != b); - LGapNode* cur = a; - while (cur != b && cur->visited_id() != visited_id && cur->IsAssigned()) { - cur->set_visited_id(visited_id); - cur = cur->assigned_from(); - } - - return cur == b; -} - - -bool LGapResolver::CanReach(LGapNode* a, LGapNode* b) { - ASSERT(a != b); - return CanReach(a, b, next_visited_id_++); -} - - -void LGapResolver::RegisterMove(LMoveOperands move) { - if (move.from()->IsConstantOperand()) { - // Constant moves should be last in the machine code. Therefore add them - // first to the result set. - AddResultMove(move.from(), move.to()); - } else { - LGapNode* from = LookupNode(move.from()); - LGapNode* to = LookupNode(move.to()); - if (to->IsAssigned() && to->assigned_from() == from) { - move.Eliminate(); - return; - } - ASSERT(!to->IsAssigned()); - if (CanReach(from, to)) { - // This introduces a cycle. Save. - identified_cycles_.Add(from); - } - to->set_assigned_from(from); - } -} - - -LGapNode* LGapResolver::LookupNode(LOperand* operand) { - for (int i = 0; i < nodes_.length(); ++i) { - if (nodes_[i]->operand()->Equals(operand)) return nodes_[i]; - } - - // No node found => create a new one. - LGapNode* result = new LGapNode(operand); - nodes_.Add(result); - return result; -} - - #define __ masm()-> bool LCodeGen::GenerateCode() { @@ -427,6 +276,14 @@ Operand LCodeGen::ToOperand(LOperand* op) const { } +Operand LCodeGen::HighOperand(LOperand* op) { + ASSERT(op->IsDoubleStackSlot()); + int index = op->index(); + int offset = (index >= 0) ? index + 3 : index - 1; + return Operand(ebp, -offset * kPointerSize); +} + + void LCodeGen::WriteTranslation(LEnvironment* environment, Translation* translation) { if (environment == NULL) return; @@ -762,66 +619,7 @@ void LCodeGen::DoLabel(LLabel* label) { void LCodeGen::DoParallelMove(LParallelMove* move) { - // xmm0 must always be a scratch register. - XMMRegister xmm_scratch = xmm0; - LUnallocated marker_operand(LUnallocated::NONE); - - Register cpu_scratch = esi; - bool destroys_cpu_scratch = false; - - const ZoneList<LMoveOperands>* moves = - resolver_.Resolve(move->move_operands(), &marker_operand); - for (int i = moves->length() - 1; i >= 0; --i) { - LMoveOperands move = moves->at(i); - LOperand* from = move.from(); - LOperand* to = move.to(); - ASSERT(!from->IsDoubleRegister() || - !ToDoubleRegister(from).is(xmm_scratch)); - ASSERT(!to->IsDoubleRegister() || !ToDoubleRegister(to).is(xmm_scratch)); - ASSERT(!from->IsRegister() || !ToRegister(from).is(cpu_scratch)); - ASSERT(!to->IsRegister() || !ToRegister(to).is(cpu_scratch)); - if (from->IsConstantOperand()) { - __ mov(ToOperand(to), ToImmediate(from)); - } else if (from == &marker_operand) { - if (to->IsRegister() || to->IsStackSlot()) { - __ mov(ToOperand(to), cpu_scratch); - ASSERT(destroys_cpu_scratch); - } else { - ASSERT(to->IsDoubleRegister() || to->IsDoubleStackSlot()); - __ movdbl(ToOperand(to), xmm_scratch); - } - } else if (to == &marker_operand) { - if (from->IsRegister() || from->IsStackSlot()) { - __ mov(cpu_scratch, ToOperand(from)); - destroys_cpu_scratch = true; - } else { - ASSERT(from->IsDoubleRegister() || from->IsDoubleStackSlot()); - __ movdbl(xmm_scratch, ToOperand(from)); - } - } else if (from->IsRegister()) { - __ mov(ToOperand(to), ToRegister(from)); - } else if (to->IsRegister()) { - __ mov(ToRegister(to), ToOperand(from)); - } else if (from->IsStackSlot()) { - ASSERT(to->IsStackSlot()); - __ push(eax); - __ mov(eax, ToOperand(from)); - __ mov(ToOperand(to), eax); - __ pop(eax); - } else if (from->IsDoubleRegister()) { - __ movdbl(ToOperand(to), ToDoubleRegister(from)); - } else if (to->IsDoubleRegister()) { - __ movdbl(ToDoubleRegister(to), ToOperand(from)); - } else { - ASSERT(to->IsDoubleStackSlot() && from->IsDoubleStackSlot()); - __ movdbl(xmm_scratch, ToOperand(from)); - __ movdbl(ToOperand(to), xmm_scratch); - } - } - - if (destroys_cpu_scratch) { - __ mov(cpu_scratch, Operand(ebp, -kPointerSize)); - } + resolver_.Resolve(move); } @@ -908,11 +706,11 @@ void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { void LCodeGen::DoModI(LModI* instr) { - LOperand* right = instr->right(); + LOperand* right = instr->InputAt(1); ASSERT(ToRegister(instr->result()).is(edx)); - ASSERT(ToRegister(instr->left()).is(eax)); - ASSERT(!ToRegister(instr->right()).is(eax)); - ASSERT(!ToRegister(instr->right()).is(edx)); + ASSERT(ToRegister(instr->InputAt(0)).is(eax)); + ASSERT(!ToRegister(instr->InputAt(1)).is(eax)); + ASSERT(!ToRegister(instr->InputAt(1)).is(edx)); Register right_reg = ToRegister(right); @@ -948,11 +746,11 @@ void LCodeGen::DoModI(LModI* instr) { void LCodeGen::DoDivI(LDivI* instr) { - LOperand* right = instr->right(); + LOperand* right = instr->InputAt(1); ASSERT(ToRegister(instr->result()).is(eax)); - ASSERT(ToRegister(instr->left()).is(eax)); - ASSERT(!ToRegister(instr->right()).is(eax)); - ASSERT(!ToRegister(instr->right()).is(edx)); + ASSERT(ToRegister(instr->InputAt(0)).is(eax)); + ASSERT(!ToRegister(instr->InputAt(1)).is(eax)); + ASSERT(!ToRegister(instr->InputAt(1)).is(edx)); Register left_reg = eax; @@ -994,11 +792,11 @@ void LCodeGen::DoDivI(LDivI* instr) { void LCodeGen::DoMulI(LMulI* instr) { - Register left = ToRegister(instr->left()); - LOperand* right = instr->right(); + Register left = ToRegister(instr->InputAt(0)); + LOperand* right = instr->InputAt(1); if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { - __ mov(ToRegister(instr->temp()), left); + __ mov(ToRegister(instr->TempAt(0)), left); } if (right->IsConstantOperand()) { @@ -1022,7 +820,7 @@ void LCodeGen::DoMulI(LMulI* instr) { } } else { // Test the non-zero operand for negative sign. - __ or_(ToRegister(instr->temp()), ToOperand(right)); + __ or_(ToRegister(instr->TempAt(0)), ToOperand(right)); DeoptimizeIf(sign, instr->environment()); } __ bind(&done); @@ -1031,8 +829,8 @@ void LCodeGen::DoMulI(LMulI* instr) { void LCodeGen::DoBitI(LBitI* instr) { - LOperand* left = instr->left(); - LOperand* right = instr->right(); + LOperand* left = instr->InputAt(0); + LOperand* right = instr->InputAt(1); ASSERT(left->Equals(instr->result())); ASSERT(left->IsRegister()); @@ -1072,8 +870,8 @@ void LCodeGen::DoBitI(LBitI* instr) { void LCodeGen::DoShiftI(LShiftI* instr) { - LOperand* left = instr->left(); - LOperand* right = instr->right(); + LOperand* left = instr->InputAt(0); + LOperand* right = instr->InputAt(1); ASSERT(left->Equals(instr->result())); ASSERT(left->IsRegister()); if (right->IsRegister()) { @@ -1128,8 +926,8 @@ void LCodeGen::DoShiftI(LShiftI* instr) { void LCodeGen::DoSubI(LSubI* instr) { - LOperand* left = instr->left(); - LOperand* right = instr->right(); + LOperand* left = instr->InputAt(0); + LOperand* right = instr->InputAt(1); ASSERT(left->Equals(instr->result())); if (right->IsConstantOperand()) { @@ -1184,22 +982,22 @@ void LCodeGen::DoConstantT(LConstantT* instr) { void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) { Register result = ToRegister(instr->result()); - Register array = ToRegister(instr->input()); + Register array = ToRegister(instr->InputAt(0)); __ mov(result, FieldOperand(array, JSArray::kLengthOffset)); } void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) { Register result = ToRegister(instr->result()); - Register array = ToRegister(instr->input()); + Register array = ToRegister(instr->InputAt(0)); __ mov(result, FieldOperand(array, FixedArray::kLengthOffset)); } void LCodeGen::DoValueOf(LValueOf* instr) { - Register input = ToRegister(instr->input()); + Register input = ToRegister(instr->InputAt(0)); Register result = ToRegister(instr->result()); - Register map = ToRegister(instr->temporary()); + Register map = ToRegister(instr->TempAt(0)); ASSERT(input.is(result)); NearLabel done; // If the object is a smi return the object. @@ -1216,14 +1014,14 @@ void LCodeGen::DoValueOf(LValueOf* instr) { void LCodeGen::DoBitNotI(LBitNotI* instr) { - LOperand* input = instr->input(); + LOperand* input = instr->InputAt(0); ASSERT(input->Equals(instr->result())); __ not_(ToRegister(input)); } void LCodeGen::DoThrow(LThrow* instr) { - __ push(ToOperand(instr->input())); + __ push(ToOperand(instr->InputAt(0))); CallRuntime(Runtime::kThrow, 1, instr); if (FLAG_debug_code) { @@ -1234,8 +1032,8 @@ void LCodeGen::DoThrow(LThrow* instr) { void LCodeGen::DoAddI(LAddI* instr) { - LOperand* left = instr->left(); - LOperand* right = instr->right(); + LOperand* left = instr->InputAt(0); + LOperand* right = instr->InputAt(1); ASSERT(left->Equals(instr->result())); if (right->IsConstantOperand()) { @@ -1251,8 +1049,8 @@ void LCodeGen::DoAddI(LAddI* instr) { void LCodeGen::DoArithmeticD(LArithmeticD* instr) { - LOperand* left = instr->left(); - LOperand* right = instr->right(); + LOperand* left = instr->InputAt(0); + LOperand* right = instr->InputAt(1); // Modulo uses a fixed result register. ASSERT(instr->op() == Token::MOD || left->Equals(instr->result())); switch (instr->op()) { @@ -1291,8 +1089,8 @@ void LCodeGen::DoArithmeticD(LArithmeticD* instr) { void LCodeGen::DoArithmeticT(LArithmeticT* instr) { - ASSERT(ToRegister(instr->left()).is(edx)); - ASSERT(ToRegister(instr->right()).is(eax)); + ASSERT(ToRegister(instr->InputAt(0)).is(edx)); + ASSERT(ToRegister(instr->InputAt(1)).is(eax)); ASSERT(ToRegister(instr->result()).is(eax)); TypeRecordingBinaryOpStub stub(instr->op(), NO_OVERWRITE); @@ -1333,17 +1131,17 @@ void LCodeGen::DoBranch(LBranch* instr) { Representation r = instr->hydrogen()->representation(); if (r.IsInteger32()) { - Register reg = ToRegister(instr->input()); + Register reg = ToRegister(instr->InputAt(0)); __ test(reg, Operand(reg)); EmitBranch(true_block, false_block, not_zero); } else if (r.IsDouble()) { - XMMRegister reg = ToDoubleRegister(instr->input()); + XMMRegister reg = ToDoubleRegister(instr->InputAt(0)); __ xorpd(xmm0, xmm0); __ ucomisd(reg, xmm0); EmitBranch(true_block, false_block, not_equal); } else { ASSERT(r.IsTagged()); - Register reg = ToRegister(instr->input()); + Register reg = ToRegister(instr->InputAt(0)); if (instr->hydrogen()->type().IsBoolean()) { __ cmp(reg, Factory::true_value()); EmitBranch(true_block, false_block, equal); @@ -1471,8 +1269,8 @@ void LCodeGen::EmitCmpI(LOperand* left, LOperand* right) { void LCodeGen::DoCmpID(LCmpID* instr) { - LOperand* left = instr->left(); - LOperand* right = instr->right(); + LOperand* left = instr->InputAt(0); + LOperand* right = instr->InputAt(1); LOperand* result = instr->result(); NearLabel unordered; @@ -1497,8 +1295,8 @@ void LCodeGen::DoCmpID(LCmpID* instr) { void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { - LOperand* left = instr->left(); - LOperand* right = instr->right(); + LOperand* left = instr->InputAt(0); + LOperand* right = instr->InputAt(1); int false_block = chunk_->LookupDestination(instr->false_block_id()); int true_block = chunk_->LookupDestination(instr->true_block_id()); @@ -1517,8 +1315,8 @@ void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { void LCodeGen::DoCmpJSObjectEq(LCmpJSObjectEq* instr) { - Register left = ToRegister(instr->left()); - Register right = ToRegister(instr->right()); + Register left = ToRegister(instr->InputAt(0)); + Register right = ToRegister(instr->InputAt(1)); Register result = ToRegister(instr->result()); __ cmp(left, Operand(right)); @@ -1531,8 +1329,8 @@ void LCodeGen::DoCmpJSObjectEq(LCmpJSObjectEq* instr) { void LCodeGen::DoCmpJSObjectEqAndBranch(LCmpJSObjectEqAndBranch* instr) { - Register left = ToRegister(instr->left()); - Register right = ToRegister(instr->right()); + Register left = ToRegister(instr->InputAt(0)); + Register right = ToRegister(instr->InputAt(1)); int false_block = chunk_->LookupDestination(instr->false_block_id()); int true_block = chunk_->LookupDestination(instr->true_block_id()); @@ -1542,7 +1340,7 @@ void LCodeGen::DoCmpJSObjectEqAndBranch(LCmpJSObjectEqAndBranch* instr) { void LCodeGen::DoIsNull(LIsNull* instr) { - Register reg = ToRegister(instr->input()); + Register reg = ToRegister(instr->InputAt(0)); Register result = ToRegister(instr->result()); // TODO(fsc): If the expression is known to be a smi, then it's @@ -1580,7 +1378,7 @@ void LCodeGen::DoIsNull(LIsNull* instr) { void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) { - Register reg = ToRegister(instr->input()); + Register reg = ToRegister(instr->InputAt(0)); // TODO(fsc): If the expression is known to be a smi, then it's // definitely not null. Jump to the false block. @@ -1601,7 +1399,7 @@ void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) { __ j(zero, false_label); // Check for undetectable objects by looking in the bit field in // the map. The object has already been smi checked. - Register scratch = ToRegister(instr->temp()); + Register scratch = ToRegister(instr->TempAt(0)); __ mov(scratch, FieldOperand(reg, HeapObject::kMapOffset)); __ movzx_b(scratch, FieldOperand(scratch, Map::kBitFieldOffset)); __ test(scratch, Immediate(1 << Map::kIsUndetectable)); @@ -1640,9 +1438,9 @@ Condition LCodeGen::EmitIsObject(Register input, void LCodeGen::DoIsObject(LIsObject* instr) { - Register reg = ToRegister(instr->input()); + Register reg = ToRegister(instr->InputAt(0)); Register result = ToRegister(instr->result()); - Register temp = ToRegister(instr->temp()); + Register temp = ToRegister(instr->TempAt(0)); Label is_false, is_true, done; Condition true_cond = EmitIsObject(reg, result, temp, &is_false, &is_true); @@ -1660,9 +1458,9 @@ void LCodeGen::DoIsObject(LIsObject* instr) { void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) { - Register reg = ToRegister(instr->input()); - Register temp = ToRegister(instr->temp()); - Register temp2 = ToRegister(instr->temp2()); + Register reg = ToRegister(instr->InputAt(0)); + Register temp = ToRegister(instr->TempAt(0)); + Register temp2 = ToRegister(instr->TempAt(1)); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); @@ -1676,7 +1474,7 @@ void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) { void LCodeGen::DoIsSmi(LIsSmi* instr) { - Operand input = ToOperand(instr->input()); + Operand input = ToOperand(instr->InputAt(0)); Register result = ToRegister(instr->result()); ASSERT(instr->hydrogen()->value()->representation().IsTagged()); @@ -1690,7 +1488,7 @@ void LCodeGen::DoIsSmi(LIsSmi* instr) { void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { - Operand input = ToOperand(instr->input()); + Operand input = ToOperand(instr->InputAt(0)); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); @@ -1700,9 +1498,9 @@ void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { } -InstanceType LHasInstanceType::TestType() { - InstanceType from = hydrogen()->from(); - InstanceType to = hydrogen()->to(); +static InstanceType TestType(HHasInstanceType* instr) { + InstanceType from = instr->from(); + InstanceType to = instr->to(); if (from == FIRST_TYPE) return to; ASSERT(from == to || to == LAST_TYPE); return from; @@ -1710,9 +1508,9 @@ InstanceType LHasInstanceType::TestType() { -Condition LHasInstanceType::BranchCondition() { - InstanceType from = hydrogen()->from(); - InstanceType to = hydrogen()->to(); +static Condition BranchCondition(HHasInstanceType* instr) { + InstanceType from = instr->from(); + InstanceType to = instr->to(); if (from == to) return equal; if (to == LAST_TYPE) return above_equal; if (from == FIRST_TYPE) return below_equal; @@ -1722,15 +1520,15 @@ Condition LHasInstanceType::BranchCondition() { void LCodeGen::DoHasInstanceType(LHasInstanceType* instr) { - Register input = ToRegister(instr->input()); + Register input = ToRegister(instr->InputAt(0)); Register result = ToRegister(instr->result()); ASSERT(instr->hydrogen()->value()->representation().IsTagged()); __ test(input, Immediate(kSmiTagMask)); NearLabel done, is_false; __ j(zero, &is_false); - __ CmpObjectType(input, instr->TestType(), result); - __ j(NegateCondition(instr->BranchCondition()), &is_false); + __ CmpObjectType(input, TestType(instr->hydrogen()), result); + __ j(NegateCondition(BranchCondition(instr->hydrogen())), &is_false); __ mov(result, Handle<Object>(Heap::true_value())); __ jmp(&done); __ bind(&is_false); @@ -1740,8 +1538,8 @@ void LCodeGen::DoHasInstanceType(LHasInstanceType* instr) { void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { - Register input = ToRegister(instr->input()); - Register temp = ToRegister(instr->temp()); + Register input = ToRegister(instr->InputAt(0)); + Register temp = ToRegister(instr->TempAt(0)); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); @@ -1751,13 +1549,13 @@ void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { __ test(input, Immediate(kSmiTagMask)); __ j(zero, false_label); - __ CmpObjectType(input, instr->TestType(), temp); - EmitBranch(true_block, false_block, instr->BranchCondition()); + __ CmpObjectType(input, TestType(instr->hydrogen()), temp); + EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen())); } void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) { - Register input = ToRegister(instr->input()); + Register input = ToRegister(instr->InputAt(0)); Register result = ToRegister(instr->result()); ASSERT(instr->hydrogen()->value()->representation().IsTagged()); @@ -1773,7 +1571,7 @@ void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) { void LCodeGen::DoHasCachedArrayIndexAndBranch( LHasCachedArrayIndexAndBranch* instr) { - Register input = ToRegister(instr->input()); + Register input = ToRegister(instr->InputAt(0)); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); @@ -1842,10 +1640,10 @@ void LCodeGen::EmitClassOfTest(Label* is_true, void LCodeGen::DoClassOfTest(LClassOfTest* instr) { - Register input = ToRegister(instr->input()); + Register input = ToRegister(instr->InputAt(0)); Register result = ToRegister(instr->result()); ASSERT(input.is(result)); - Register temp = ToRegister(instr->temporary()); + Register temp = ToRegister(instr->TempAt(0)); Handle<String> class_name = instr->hydrogen()->class_name(); NearLabel done; Label is_true, is_false; @@ -1865,9 +1663,9 @@ void LCodeGen::DoClassOfTest(LClassOfTest* instr) { void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { - Register input = ToRegister(instr->input()); - Register temp = ToRegister(instr->temporary()); - Register temp2 = ToRegister(instr->temporary2()); + Register input = ToRegister(instr->InputAt(0)); + Register temp = ToRegister(instr->TempAt(0)); + Register temp2 = ToRegister(instr->TempAt(1)); if (input.is(temp)) { // Swap. Register swapper = temp; @@ -1889,7 +1687,7 @@ void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { - Register reg = ToRegister(instr->input()); + Register reg = ToRegister(instr->InputAt(0)); int true_block = instr->true_block_id(); int false_block = instr->false_block_id(); @@ -1946,8 +1744,8 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { deferred = new DeferredInstanceOfKnownGlobal(this, instr); Label done, false_result; - Register object = ToRegister(instr->input()); - Register temp = ToRegister(instr->temp()); + Register object = ToRegister(instr->InputAt(0)); + Register temp = ToRegister(instr->TempAt(0)); // A Smi is not instance of anything. __ test(object, Immediate(kSmiTagMask)); @@ -1957,7 +1755,7 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { // hole value will be patched to the last map/result pair generated by the // instanceof stub. NearLabel cache_miss; - Register map = ToRegister(instr->temp()); + Register map = ToRegister(instr->TempAt(0)); __ mov(map, FieldOperand(object, HeapObject::kMapOffset)); __ bind(deferred->map_check()); // Label for calculating code patching. __ cmp(map, Factory::the_hole_value()); // Patched to cached map. @@ -2005,7 +1803,7 @@ void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, // Get the temp register reserved by the instruction. This needs to be edi as // its slot of the pushing of safepoint registers is used to communicate the // offset to the location of the map check. - Register temp = ToRegister(instr->temp()); + Register temp = ToRegister(instr->TempAt(0)); ASSERT(temp.is(edi)); __ mov(InstanceofStub::right(), Immediate(instr->function())); static const int kAdditionalDelta = 13; @@ -2110,7 +1908,7 @@ void LCodeGen::DoLoadGlobal(LLoadGlobal* instr) { void LCodeGen::DoStoreGlobal(LStoreGlobal* instr) { - Register value = ToRegister(instr->input()); + Register value = ToRegister(instr->InputAt(0)); __ mov(Operand::Cell(instr->hydrogen()->cell()), value); } @@ -2124,7 +1922,7 @@ void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) { void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { - Register object = ToRegister(instr->input()); + Register object = ToRegister(instr->InputAt(0)); Register result = ToRegister(instr->result()); if (instr->hydrogen()->is_in_object()) { __ mov(result, FieldOperand(object, instr->hydrogen()->offset())); @@ -2147,7 +1945,7 @@ void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) { Register function = ToRegister(instr->function()); - Register temp = ToRegister(instr->temporary()); + Register temp = ToRegister(instr->TempAt(0)); Register result = ToRegister(instr->result()); // Check that the function really is a function. @@ -2188,8 +1986,8 @@ void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) { void LCodeGen::DoLoadElements(LLoadElements* instr) { - ASSERT(instr->result()->Equals(instr->input())); - Register reg = ToRegister(instr->input()); + ASSERT(instr->result()->Equals(instr->InputAt(0))); + Register reg = ToRegister(instr->InputAt(0)); __ mov(reg, FieldOperand(reg, JSObject::kElementsOffset)); if (FLAG_debug_code) { NearLabel done; @@ -2269,7 +2067,7 @@ void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) { void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) { - Operand elem = ToOperand(instr->input()); + Operand elem = ToOperand(instr->InputAt(0)); Register result = ToRegister(instr->result()); NearLabel done; @@ -2343,7 +2141,7 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) { void LCodeGen::DoPushArgument(LPushArgument* instr) { - LOperand* argument = instr->input(); + LOperand* argument = instr->InputAt(0); if (argument->IsConstantOperand()) { __ push(ToImmediate(argument)); } else { @@ -2409,7 +2207,7 @@ void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) { void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) { - Register input_reg = ToRegister(instr->input()); + Register input_reg = ToRegister(instr->InputAt(0)); __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset), Factory::heap_number_map()); DeoptimizeIf(not_equal, instr->environment()); @@ -2476,17 +2274,17 @@ void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) { LUnaryMathOperation* instr_; }; - ASSERT(instr->input()->Equals(instr->result())); + ASSERT(instr->InputAt(0)->Equals(instr->result())); Representation r = instr->hydrogen()->value()->representation(); if (r.IsDouble()) { XMMRegister scratch = xmm0; - XMMRegister input_reg = ToDoubleRegister(instr->input()); + XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); __ pxor(scratch, scratch); __ subsd(scratch, input_reg); __ pand(input_reg, scratch); } else if (r.IsInteger32()) { - Register input_reg = ToRegister(instr->input()); + Register input_reg = ToRegister(instr->InputAt(0)); __ test(input_reg, Operand(input_reg)); Label is_positive; __ j(not_sign, &is_positive); @@ -2498,7 +2296,7 @@ void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) { DeferredMathAbsTaggedHeapNumber* deferred = new DeferredMathAbsTaggedHeapNumber(this, instr); Label not_smi; - Register input_reg = ToRegister(instr->input()); + Register input_reg = ToRegister(instr->InputAt(0)); // Smi check. __ test(input_reg, Immediate(kSmiTagMask)); __ j(not_zero, deferred->entry()); @@ -2519,7 +2317,7 @@ void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) { void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) { XMMRegister xmm_scratch = xmm0; Register output_reg = ToRegister(instr->result()); - XMMRegister input_reg = ToDoubleRegister(instr->input()); + XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); __ xorpd(xmm_scratch, xmm_scratch); // Zero the register. __ ucomisd(input_reg, xmm_scratch); @@ -2541,7 +2339,7 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) { void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { XMMRegister xmm_scratch = xmm0; Register output_reg = ToRegister(instr->result()); - XMMRegister input_reg = ToDoubleRegister(instr->input()); + XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); // xmm_scratch = 0.5 ExternalReference one_half = ExternalReference::address_of_one_half(); @@ -2574,7 +2372,7 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) { - XMMRegister input_reg = ToDoubleRegister(instr->input()); + XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); ASSERT(ToDoubleRegister(instr->result()).is(input_reg)); __ sqrtsd(input_reg, input_reg); } @@ -2582,7 +2380,7 @@ void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) { void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) { XMMRegister xmm_scratch = xmm0; - XMMRegister input_reg = ToDoubleRegister(instr->input()); + XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); ASSERT(ToDoubleRegister(instr->result()).is(input_reg)); ExternalReference negative_infinity = ExternalReference::address_of_negative_infinity(); @@ -2594,8 +2392,8 @@ void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) { void LCodeGen::DoPower(LPower* instr) { - LOperand* left = instr->left(); - LOperand* right = instr->right(); + LOperand* left = instr->InputAt(0); + LOperand* right = instr->InputAt(1); DoubleRegister result_reg = ToDoubleRegister(instr->result()); Representation exponent_type = instr->hydrogen()->right()->representation(); if (exponent_type.IsDouble()) { @@ -2708,6 +2506,7 @@ void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) { void LCodeGen::DoCallKeyed(LCallKeyed* instr) { ASSERT(ToRegister(instr->result()).is(eax)); + ASSERT(ToRegister(instr->InputAt(0)).is(ecx)); int arity = instr->arity(); Handle<Code> ic = StubCache::ComputeKeyedCallInitialize(arity, NOT_IN_LOOP); @@ -2757,7 +2556,7 @@ void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) { void LCodeGen::DoCallNew(LCallNew* instr) { - ASSERT(ToRegister(instr->input()).is(edi)); + ASSERT(ToRegister(instr->InputAt(0)).is(edi)); ASSERT(ToRegister(instr->result()).is(eax)); Handle<Code> builtin(Builtins::builtin(Builtins::JSConstructCall)); @@ -2784,12 +2583,12 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { if (instr->is_in_object()) { __ mov(FieldOperand(object, offset), value); if (instr->needs_write_barrier()) { - Register temp = ToRegister(instr->temp()); + Register temp = ToRegister(instr->TempAt(0)); // Update the write barrier for the object for in-object properties. __ RecordWrite(object, offset, value, temp); } } else { - Register temp = ToRegister(instr->temp()); + Register temp = ToRegister(instr->TempAt(0)); __ mov(temp, FieldOperand(object, JSObject::kPropertiesOffset)); __ mov(FieldOperand(temp, offset), value); if (instr->needs_write_barrier()) { @@ -2853,7 +2652,7 @@ void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) { - LOperand* input = instr->input(); + LOperand* input = instr->InputAt(0); ASSERT(input->IsRegister() || input->IsStackSlot()); LOperand* output = instr->result(); ASSERT(output->IsDoubleRegister()); @@ -2871,7 +2670,7 @@ void LCodeGen::DoNumberTagI(LNumberTagI* instr) { LNumberTagI* instr_; }; - LOperand* input = instr->input(); + LOperand* input = instr->InputAt(0); ASSERT(input->IsRegister() && input->Equals(instr->result())); Register reg = ToRegister(input); @@ -2884,7 +2683,7 @@ void LCodeGen::DoNumberTagI(LNumberTagI* instr) { void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) { Label slow; - Register reg = ToRegister(instr->input()); + Register reg = ToRegister(instr->InputAt(0)); Register tmp = reg.is(eax) ? ecx : eax; // Preserve the value of all registers. @@ -2934,9 +2733,9 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) { LNumberTagD* instr_; }; - XMMRegister input_reg = ToDoubleRegister(instr->input()); + XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); Register reg = ToRegister(instr->result()); - Register tmp = ToRegister(instr->temp()); + Register tmp = ToRegister(instr->TempAt(0)); DeferredNumberTagD* deferred = new DeferredNumberTagD(this, instr); if (FLAG_inline_new) { @@ -2966,7 +2765,7 @@ void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) { void LCodeGen::DoSmiTag(LSmiTag* instr) { - LOperand* input = instr->input(); + LOperand* input = instr->InputAt(0); ASSERT(input->IsRegister() && input->Equals(instr->result())); ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow)); __ SmiTag(ToRegister(input)); @@ -2974,7 +2773,7 @@ void LCodeGen::DoSmiTag(LSmiTag* instr) { void LCodeGen::DoSmiUntag(LSmiUntag* instr) { - LOperand* input = instr->input(); + LOperand* input = instr->InputAt(0); ASSERT(input->IsRegister() && input->Equals(instr->result())); if (instr->needs_check()) { __ test(ToRegister(input), Immediate(kSmiTagMask)); @@ -3034,7 +2833,7 @@ class DeferredTaggedToI: public LDeferredCode { void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { NearLabel done, heap_number; - Register input_reg = ToRegister(instr->input()); + Register input_reg = ToRegister(instr->InputAt(0)); // Heap number map check. __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset), @@ -3077,7 +2876,7 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { __ add(Operand(esp), Immediate(kDoubleSize)); } else { NearLabel deopt; - XMMRegister xmm_temp = ToDoubleRegister(instr->temp()); + XMMRegister xmm_temp = ToDoubleRegister(instr->TempAt(0)); __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset)); __ cvttsd2si(input_reg, Operand(xmm0)); __ cmp(input_reg, 0x80000000u); @@ -3094,7 +2893,7 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { // Deoptimize if we don't have a heap number. DeoptimizeIf(not_equal, instr->environment()); - XMMRegister xmm_temp = ToDoubleRegister(instr->temp()); + XMMRegister xmm_temp = ToDoubleRegister(instr->TempAt(0)); __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset)); __ cvttsd2si(input_reg, Operand(xmm0)); __ cvtsi2sd(xmm_temp, Operand(input_reg)); @@ -3114,7 +2913,7 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { void LCodeGen::DoTaggedToI(LTaggedToI* instr) { - LOperand* input = instr->input(); + LOperand* input = instr->InputAt(0); ASSERT(input->IsRegister()); ASSERT(input->Equals(instr->result())); @@ -3134,7 +2933,7 @@ void LCodeGen::DoTaggedToI(LTaggedToI* instr) { void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { - LOperand* input = instr->input(); + LOperand* input = instr->InputAt(0); ASSERT(input->IsRegister()); LOperand* result = instr->result(); ASSERT(result->IsDoubleRegister()); @@ -3147,7 +2946,7 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { void LCodeGen::DoDoubleToI(LDoubleToI* instr) { - LOperand* input = instr->input(); + LOperand* input = instr->InputAt(0); ASSERT(input->IsDoubleRegister()); LOperand* result = instr->result(); ASSERT(result->IsRegister()); @@ -3185,7 +2984,7 @@ void LCodeGen::DoDoubleToI(LDoubleToI* instr) { __ bind(&done); } else { NearLabel done; - Register temp_reg = ToRegister(instr->temporary()); + Register temp_reg = ToRegister(instr->TempAt(0)); XMMRegister xmm_scratch = xmm0; // If cvttsd2si succeeded, we're done. Otherwise, we attempt @@ -3264,7 +3063,7 @@ void LCodeGen::DoDoubleToI(LDoubleToI* instr) { void LCodeGen::DoCheckSmi(LCheckSmi* instr) { - LOperand* input = instr->input(); + LOperand* input = instr->InputAt(0); ASSERT(input->IsRegister()); __ test(ToRegister(input), Immediate(kSmiTagMask)); DeoptimizeIf(instr->condition(), instr->environment()); @@ -3272,8 +3071,8 @@ void LCodeGen::DoCheckSmi(LCheckSmi* instr) { void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { - Register input = ToRegister(instr->input()); - Register temp = ToRegister(instr->temp()); + Register input = ToRegister(instr->InputAt(0)); + Register temp = ToRegister(instr->TempAt(0)); InstanceType first = instr->hydrogen()->first(); InstanceType last = instr->hydrogen()->last(); @@ -3297,15 +3096,15 @@ void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { void LCodeGen::DoCheckFunction(LCheckFunction* instr) { - ASSERT(instr->input()->IsRegister()); - Register reg = ToRegister(instr->input()); + ASSERT(instr->InputAt(0)->IsRegister()); + Register reg = ToRegister(instr->InputAt(0)); __ cmp(reg, instr->hydrogen()->target()); DeoptimizeIf(not_equal, instr->environment()); } void LCodeGen::DoCheckMap(LCheckMap* instr) { - LOperand* input = instr->input(); + LOperand* input = instr->InputAt(0); ASSERT(input->IsRegister()); Register reg = ToRegister(input); __ cmp(FieldOperand(reg, HeapObject::kMapOffset), @@ -3326,7 +3125,7 @@ void LCodeGen::LoadHeapObject(Register result, Handle<HeapObject> object) { void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { - Register reg = ToRegister(instr->temp()); + Register reg = ToRegister(instr->TempAt(0)); Handle<JSObject> holder = instr->holder(); Handle<JSObject> current_prototype = instr->prototype(); @@ -3470,7 +3269,7 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { void LCodeGen::DoTypeof(LTypeof* instr) { - LOperand* input = instr->input(); + LOperand* input = instr->InputAt(0); if (input->IsConstantOperand()) { __ push(ToImmediate(input)); } else { @@ -3481,7 +3280,7 @@ void LCodeGen::DoTypeof(LTypeof* instr) { void LCodeGen::DoTypeofIs(LTypeofIs* instr) { - Register input = ToRegister(instr->input()); + Register input = ToRegister(instr->InputAt(0)); Register result = ToRegister(instr->result()); Label true_label; Label false_label; @@ -3504,7 +3303,7 @@ void LCodeGen::DoTypeofIs(LTypeofIs* instr) { void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { - Register input = ToRegister(instr->input()); + Register input = ToRegister(instr->InputAt(0)); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); Label* true_label = chunk_->GetAssemblyLabel(true_block); diff --git a/deps/v8/src/ia32/lithium-codegen-ia32.h b/deps/v8/src/ia32/lithium-codegen-ia32.h index ef8fb5c493..ab62e6fe92 100644 --- a/deps/v8/src/ia32/lithium-codegen-ia32.h +++ b/deps/v8/src/ia32/lithium-codegen-ia32.h @@ -34,6 +34,7 @@ #include "deoptimizer.h" #include "safepoint-table.h" #include "scopes.h" +#include "ia32/lithium-gap-resolver-ia32.h" namespace v8 { namespace internal { @@ -43,28 +44,6 @@ class LDeferredCode; class LGapNode; class SafepointGenerator; -class LGapResolver BASE_EMBEDDED { - public: - LGapResolver(); - const ZoneList<LMoveOperands>* Resolve(const ZoneList<LMoveOperands>* moves, - LOperand* marker_operand); - - private: - LGapNode* LookupNode(LOperand* operand); - bool CanReach(LGapNode* a, LGapNode* b, int visited_id); - bool CanReach(LGapNode* a, LGapNode* b); - void RegisterMove(LMoveOperands move); - void AddResultMove(LOperand* from, LOperand* to); - void AddResultMove(LGapNode* from, LGapNode* to); - void ResolveCycle(LGapNode* start, LOperand* marker_operand); - - ZoneList<LGapNode*> nodes_; - ZoneList<LGapNode*> identified_cycles_; - ZoneList<LMoveOperands> result_; - int next_visited_id_; -}; - - class LCodeGen BASE_EMBEDDED { public: LCodeGen(LChunk* chunk, MacroAssembler* assembler, CompilationInfo* info) @@ -80,10 +59,24 @@ class LCodeGen BASE_EMBEDDED { scope_(chunk->graph()->info()->scope()), status_(UNUSED), deferred_(8), - osr_pc_offset_(-1) { + osr_pc_offset_(-1), + resolver_(this) { PopulateDeoptimizationLiteralsWithInlinedFunctions(); } + // Simple accessors. + MacroAssembler* masm() const { return masm_; } + + // Support for converting LOperands to assembler types. + Operand ToOperand(LOperand* op) const; + Register ToRegister(LOperand* op) const; + XMMRegister ToDoubleRegister(LOperand* op) const; + Immediate ToImmediate(LOperand* op); + + // The operand denoting the second word (the one with a higher address) of + // a double stack slot. + Operand HighOperand(LOperand* op); + // Try to generate code for the entire chunk, but it may fail if the // chunk contains constructs we cannot handle. Returns true if the // code generation attempt succeeded. @@ -129,7 +122,6 @@ class LCodeGen BASE_EMBEDDED { LChunk* chunk() const { return chunk_; } Scope* scope() const { return scope_; } HGraph* graph() const { return chunk_->graph(); } - MacroAssembler* masm() const { return masm_; } int GetNextEmittedBlock(int block); LInstruction* GetNextInstruction(); @@ -191,11 +183,7 @@ class LCodeGen BASE_EMBEDDED { Register ToRegister(int index) const; XMMRegister ToDoubleRegister(int index) const; - Register ToRegister(LOperand* op) const; - XMMRegister ToDoubleRegister(LOperand* op) const; int ToInteger32(LConstantOperand* op) const; - Operand ToOperand(LOperand* op) const; - Immediate ToImmediate(LOperand* op); // Specific math operations - used from DoUnaryMathOperation. void DoMathAbs(LUnaryMathOperation* instr); diff --git a/deps/v8/src/ia32/lithium-gap-resolver-ia32.cc b/deps/v8/src/ia32/lithium-gap-resolver-ia32.cc new file mode 100644 index 0000000000..88869590e7 --- /dev/null +++ b/deps/v8/src/ia32/lithium-gap-resolver-ia32.cc @@ -0,0 +1,461 @@ +// 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. + +#include "ia32/lithium-gap-resolver-ia32.h" +#include "ia32/lithium-codegen-ia32.h" + +namespace v8 { +namespace internal { + +LGapResolver::LGapResolver(LCodeGen* owner) + : cgen_(owner), moves_(32), spilled_register_(-1) { + for (int i = 0; i < Register::kNumAllocatableRegisters; ++i) { + source_uses_[i] = 0; + destination_uses_[i] = 0; + } +} + + +void LGapResolver::Resolve(LParallelMove* parallel_move) { + ASSERT(HasBeenReset()); + // Build up a worklist of moves. + BuildInitialMoveList(parallel_move); + + for (int i = 0; i < moves_.length(); ++i) { + LMoveOperands move = moves_[i]; + // Skip constants to perform them last. They don't block other moves + // and skipping such moves with register destinations keeps those + // registers free for the whole algorithm. + if (!move.IsEliminated() && !move.source()->IsConstantOperand()) { + PerformMove(i); + } + } + + // Perform the moves with constant sources. + for (int i = 0; i < moves_.length(); ++i) { + if (!moves_[i].IsEliminated()) { + ASSERT(moves_[i].source()->IsConstantOperand()); + EmitMove(i); + } + } + + Finish(); + ASSERT(HasBeenReset()); +} + + +void LGapResolver::BuildInitialMoveList(LParallelMove* parallel_move) { + // Perform a linear sweep of the moves to add them to the initial list of + // moves to perform, ignoring any move that is redundant (the source is + // the same as the destination, the destination is ignored and + // unallocated, or the move was already eliminated). + const ZoneList<LMoveOperands>* moves = parallel_move->move_operands(); + for (int i = 0; i < moves->length(); ++i) { + LMoveOperands move = moves->at(i); + if (!move.IsRedundant()) AddMove(move); + } + Verify(); +} + + +void LGapResolver::PerformMove(int index) { + // Each call to this function performs a move and deletes it from the move + // graph. We first recursively perform any move blocking this one. We + // mark a move as "pending" on entry to PerformMove in order to detect + // cycles in the move graph. We use operand swaps to resolve cycles, + // which means that a call to PerformMove could change any source operand + // in the move graph. + + ASSERT(!moves_[index].IsPending()); + ASSERT(!moves_[index].IsRedundant()); + + // Clear this move's destination to indicate a pending move. The actual + // destination is saved on the side. + ASSERT(moves_[index].source() != NULL); // Or else it will look eliminated. + LOperand* destination = moves_[index].destination(); + moves_[index].set_destination(NULL); + + // Perform a depth-first traversal of the move graph to resolve + // dependencies. Any unperformed, unpending move with a source the same + // as this one's destination blocks this one so recursively perform all + // such moves. + for (int i = 0; i < moves_.length(); ++i) { + LMoveOperands other_move = moves_[i]; + if (other_move.Blocks(destination) && !other_move.IsPending()) { + // Though PerformMove can change any source operand in the move graph, + // this call cannot create a blocking move via a swap (this loop does + // not miss any). Assume there is a non-blocking move with source A + // and this move is blocked on source B and there is a swap of A and + // B. Then A and B must be involved in the same cycle (or they would + // not be swapped). Since this move's destination is B and there is + // only a single incoming edge to an operand, this move must also be + // involved in the same cycle. In that case, the blocking move will + // be created but will be "pending" when we return from PerformMove. + PerformMove(i); + } + } + + // We are about to resolve this move and don't need it marked as + // pending, so restore its destination. + moves_[index].set_destination(destination); + + // This move's source may have changed due to swaps to resolve cycles and + // so it may now be the last move in the cycle. If so remove it. + if (moves_[index].source()->Equals(destination)) { + RemoveMove(index); + return; + } + + // The move may be blocked on a (at most one) pending move, in which case + // we have a cycle. Search for such a blocking move and perform a swap to + // resolve it. + for (int i = 0; i < moves_.length(); ++i) { + LMoveOperands other_move = moves_[i]; + if (other_move.Blocks(destination)) { + ASSERT(other_move.IsPending()); + EmitSwap(index); + return; + } + } + + // This move is not blocked. + EmitMove(index); +} + + +void LGapResolver::AddMove(LMoveOperands move) { + LOperand* source = move.source(); + if (source->IsRegister()) ++source_uses_[source->index()]; + + LOperand* destination = move.destination(); + if (destination->IsRegister()) ++destination_uses_[destination->index()]; + + moves_.Add(move); +} + + +void LGapResolver::RemoveMove(int index) { + LOperand* source = moves_[index].source(); + if (source->IsRegister()) { + --source_uses_[source->index()]; + ASSERT(source_uses_[source->index()] >= 0); + } + + LOperand* destination = moves_[index].destination(); + if (destination->IsRegister()) { + --destination_uses_[destination->index()]; + ASSERT(destination_uses_[destination->index()] >= 0); + } + + moves_[index].Eliminate(); +} + + +int LGapResolver::CountSourceUses(LOperand* operand) { + int count = 0; + for (int i = 0; i < moves_.length(); ++i) { + if (!moves_[i].IsEliminated() && moves_[i].source()->Equals(operand)) { + ++count; + } + } + return count; +} + + +Register LGapResolver::GetFreeRegisterNot(Register reg) { + int skip_index = reg.is(no_reg) ? -1 : Register::ToAllocationIndex(reg); + for (int i = 0; i < Register::kNumAllocatableRegisters; ++i) { + if (source_uses_[i] == 0 && destination_uses_[i] > 0 && i != skip_index) { + return Register::FromAllocationIndex(i); + } + } + return no_reg; +} + + +bool LGapResolver::HasBeenReset() { + if (!moves_.is_empty()) return false; + if (spilled_register_ >= 0) return false; + + for (int i = 0; i < Register::kNumAllocatableRegisters; ++i) { + if (source_uses_[i] != 0) return false; + if (destination_uses_[i] != 0) return false; + } + return true; +} + + +void LGapResolver::Verify() { +#ifdef ENABLE_SLOW_ASSERTS + // No operand should be the destination for more than one move. + for (int i = 0; i < moves_.length(); ++i) { + LOperand* destination = moves_[i].destination(); + for (int j = i + 1; j < moves_.length(); ++j) { + SLOW_ASSERT(!destination->Equals(moves_[j].destination())); + } + } +#endif +} + + +#define __ ACCESS_MASM(cgen_->masm()) + +void LGapResolver::Finish() { + if (spilled_register_ >= 0) { + __ pop(Register::FromAllocationIndex(spilled_register_)); + spilled_register_ = -1; + } + moves_.Rewind(0); +} + + +void LGapResolver::EnsureRestored(LOperand* operand) { + if (operand->IsRegister() && operand->index() == spilled_register_) { + __ pop(Register::FromAllocationIndex(spilled_register_)); + spilled_register_ = -1; + } +} + + +Register LGapResolver::EnsureTempRegister() { + // 1. We may have already spilled to create a temp register. + if (spilled_register_ >= 0) { + return Register::FromAllocationIndex(spilled_register_); + } + + // 2. We may have a free register that we can use without spilling. + Register free = GetFreeRegisterNot(no_reg); + if (!free.is(no_reg)) return free; + + // 3. Prefer to spill a register that is not used in any remaining move + // because it will not need to be restored until the end. + for (int i = 0; i < Register::kNumAllocatableRegisters; ++i) { + if (source_uses_[i] == 0 && destination_uses_[i] == 0) { + Register scratch = Register::FromAllocationIndex(i); + __ push(scratch); + spilled_register_ = i; + return scratch; + } + } + + // 4. Use an arbitrary register. Register 0 is as arbitrary as any other. + Register scratch = Register::FromAllocationIndex(0); + __ push(scratch); + spilled_register_ = 0; + return scratch; +} + + +void LGapResolver::EmitMove(int index) { + LOperand* source = moves_[index].source(); + LOperand* destination = moves_[index].destination(); + EnsureRestored(source); + EnsureRestored(destination); + + // Dispatch on the source and destination operand kinds. Not all + // combinations are possible. + if (source->IsRegister()) { + ASSERT(destination->IsRegister() || destination->IsStackSlot()); + Register src = cgen_->ToRegister(source); + Operand dst = cgen_->ToOperand(destination); + __ mov(dst, src); + + } else if (source->IsStackSlot()) { + ASSERT(destination->IsRegister() || destination->IsStackSlot()); + Operand src = cgen_->ToOperand(source); + if (destination->IsRegister()) { + Register dst = cgen_->ToRegister(destination); + __ mov(dst, src); + } else { + // Spill on demand to use a temporary register for memory-to-memory + // moves. + Register tmp = EnsureTempRegister(); + Operand dst = cgen_->ToOperand(destination); + __ mov(tmp, src); + __ mov(dst, tmp); + } + + } else if (source->IsConstantOperand()) { + ASSERT(destination->IsRegister() || destination->IsStackSlot()); + Immediate src = cgen_->ToImmediate(source); + Operand dst = cgen_->ToOperand(destination); + __ mov(dst, src); + + } else if (source->IsDoubleRegister()) { + ASSERT(destination->IsDoubleRegister() || + destination->IsDoubleStackSlot()); + XMMRegister src = cgen_->ToDoubleRegister(source); + Operand dst = cgen_->ToOperand(destination); + __ movdbl(dst, src); + + } else if (source->IsDoubleStackSlot()) { + ASSERT(destination->IsDoubleRegister() || + destination->IsDoubleStackSlot()); + Operand src = cgen_->ToOperand(source); + if (destination->IsDoubleRegister()) { + XMMRegister dst = cgen_->ToDoubleRegister(destination); + __ movdbl(dst, src); + } else { + // We rely on having xmm0 available as a fixed scratch register. + Operand dst = cgen_->ToOperand(destination); + __ movdbl(xmm0, src); + __ movdbl(dst, xmm0); + } + + } else { + UNREACHABLE(); + } + + RemoveMove(index); +} + + +void LGapResolver::EmitSwap(int index) { + LOperand* source = moves_[index].source(); + LOperand* destination = moves_[index].destination(); + EnsureRestored(source); + EnsureRestored(destination); + + // Dispatch on the source and destination operand kinds. Not all + // combinations are possible. + if (source->IsRegister() && destination->IsRegister()) { + // Register-register. + Register src = cgen_->ToRegister(source); + Register dst = cgen_->ToRegister(destination); + __ xchg(dst, src); + + } else if ((source->IsRegister() && destination->IsStackSlot()) || + (source->IsStackSlot() && destination->IsRegister())) { + // Register-memory. Use a free register as a temp if possible. Do not + // spill on demand because the simple spill implementation cannot avoid + // spilling src at this point. + Register tmp = GetFreeRegisterNot(no_reg); + Register reg = + cgen_->ToRegister(source->IsRegister() ? source : destination); + Operand mem = + cgen_->ToOperand(source->IsRegister() ? destination : source); + if (tmp.is(no_reg)) { + __ xor_(reg, mem); + __ xor_(mem, reg); + __ xor_(reg, mem); + } else { + __ mov(tmp, mem); + __ mov(mem, reg); + __ mov(reg, tmp); + } + + } else if (source->IsStackSlot() && destination->IsStackSlot()) { + // Memory-memory. Spill on demand to use a temporary. If there is a + // free register after that, use it as a second temporary. + Register tmp0 = EnsureTempRegister(); + Register tmp1 = GetFreeRegisterNot(tmp0); + Operand src = cgen_->ToOperand(source); + Operand dst = cgen_->ToOperand(destination); + if (tmp1.is(no_reg)) { + // Only one temp register available to us. + __ mov(tmp0, dst); + __ xor_(tmp0, src); + __ xor_(src, tmp0); + __ xor_(tmp0, src); + __ mov(dst, tmp0); + } else { + __ mov(tmp0, dst); + __ mov(tmp1, src); + __ mov(dst, tmp1); + __ mov(src, tmp0); + } + + } else if (source->IsDoubleRegister() || destination->IsDoubleRegister()) { + // XMM register-register or register-memory. We rely on having xmm0 + // available as a fixed scratch register. + ASSERT(source->IsDoubleRegister() || source->IsDoubleStackSlot()); + ASSERT(destination->IsDoubleRegister() || + destination->IsDoubleStackSlot()); + XMMRegister reg = cgen_->ToDoubleRegister(source->IsDoubleRegister() + ? source + : destination); + Operand other = + cgen_->ToOperand(source->IsDoubleRegister() ? destination : source); + __ movdbl(xmm0, other); + __ movdbl(other, reg); + __ movdbl(reg, Operand(xmm0)); + + } else if (source->IsDoubleStackSlot() && destination->IsDoubleStackSlot()) { + // Double-width memory-to-memory. Spill on demand to use a general + // purpose temporary register and also rely on having xmm0 available as + // a fixed scratch register. + Register tmp = EnsureTempRegister(); + Operand src0 = cgen_->ToOperand(source); + Operand src1 = cgen_->HighOperand(source); + Operand dst0 = cgen_->ToOperand(destination); + Operand dst1 = cgen_->HighOperand(destination); + __ movdbl(xmm0, dst0); // Save destination in xmm0. + __ mov(tmp, src0); // Then use tmp to copy source to destination. + __ mov(dst0, tmp); + __ mov(tmp, src1); + __ mov(dst1, tmp); + __ movdbl(src0, xmm0); + + } else { + // No other combinations are possible. + UNREACHABLE(); + } + + // The swap of source and destination has executed a move from source to + // destination. + RemoveMove(index); + + // Any unperformed (including pending) move with a source of either + // this move's source or destination needs to have their source + // changed to reflect the state of affairs after the swap. + for (int i = 0; i < moves_.length(); ++i) { + LMoveOperands other_move = moves_[i]; + if (other_move.Blocks(source)) { + moves_[i].set_source(destination); + } else if (other_move.Blocks(destination)) { + moves_[i].set_source(source); + } + } + + // In addition to swapping the actual uses as sources, we need to update + // the use counts. + if (source->IsRegister() && destination->IsRegister()) { + int temp = source_uses_[source->index()]; + source_uses_[source->index()] = source_uses_[destination->index()]; + source_uses_[destination->index()] = temp; + } else if (source->IsRegister()) { + // We don't have use counts for non-register operands like destination. + // Compute those counts now. + source_uses_[source->index()] = CountSourceUses(source); + } else if (destination->IsRegister()) { + source_uses_[destination->index()] = CountSourceUses(destination); + } +} + +#undef __ + +} } // namespace v8::internal diff --git a/deps/v8/src/ia32/lithium-gap-resolver-ia32.h b/deps/v8/src/ia32/lithium-gap-resolver-ia32.h new file mode 100644 index 0000000000..f0bd260aad --- /dev/null +++ b/deps/v8/src/ia32/lithium-gap-resolver-ia32.h @@ -0,0 +1,110 @@ +// 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. + +#ifndef V8_IA32_LITHIUM_GAP_RESOLVER_IA32_H_ +#define V8_IA32_LITHIUM_GAP_RESOLVER_IA32_H_ + +#include "v8.h" + +#include "lithium-allocator.h" + +namespace v8 { +namespace internal { + +class LCodeGen; +class LGapResolver; + +class LGapResolver BASE_EMBEDDED { + public: + explicit LGapResolver(LCodeGen* owner); + + // Resolve a set of parallel moves, emitting assembler instructions. + void Resolve(LParallelMove* parallel_move); + + private: + // Build the initial list of moves. + void BuildInitialMoveList(LParallelMove* parallel_move); + + // Perform the move at the moves_ index in question (possibly requiring + // other moves to satisfy dependencies). + void PerformMove(int index); + + // Emit any code necessary at the end of a gap move. + void Finish(); + + // Add or delete a move from the move graph without emitting any code. + // Used to build up the graph and remove trivial moves. + void AddMove(LMoveOperands move); + void RemoveMove(int index); + + // Report the count of uses of operand as a source in a not-yet-performed + // move. Used to rebuild use counts. + int CountSourceUses(LOperand* operand); + + // Emit a move and remove it from the move graph. + void EmitMove(int index); + + // Execute a move by emitting a swap of two operands. The move from + // source to destination is removed from the move graph. + void EmitSwap(int index); + + // Ensure that the given operand is not spilled. + void EnsureRestored(LOperand* operand); + + // Return a register that can be used as a temp register, spilling + // something if necessary. + Register EnsureTempRegister(); + + // Return a known free register different from the given one (which could + // be no_reg---returning any free register), or no_reg if there is no such + // register. + Register GetFreeRegisterNot(Register reg); + + // Verify that the state is the initial one, ready to resolve a single + // parallel move. + bool HasBeenReset(); + + // Verify the move list before performing moves. + void Verify(); + + LCodeGen* cgen_; + + // List of moves not yet resolved. + ZoneList<LMoveOperands> moves_; + + // Source and destination use counts for the general purpose registers. + int source_uses_[Register::kNumAllocatableRegisters]; + int destination_uses_[Register::kNumAllocatableRegisters]; + + // If we had to spill on demand, the currently spilled register's + // allocation index. + int spilled_register_; +}; + +} } // namespace v8::internal + +#endif // V8_IA32_LITHIUM_GAP_RESOLVER_IA32_H_ diff --git a/deps/v8/src/ia32/lithium-ia32.cc b/deps/v8/src/ia32/lithium-ia32.cc index 254a47af78..cca07c8c8b 100644 --- a/deps/v8/src/ia32/lithium-ia32.cc +++ b/deps/v8/src/ia32/lithium-ia32.cc @@ -90,18 +90,22 @@ void LInstruction::PrintTo(StringStream* stream) { template<int R, int I, int T> void LTemplateInstruction<R, I, T>::PrintDataTo(StringStream* stream) { - for (int i = 0; i < I; i++) { - stream->Add(i == 0 ? "= " : " "); - inputs_.at(i)->PrintTo(stream); - } + stream->Add("= "); + inputs_.PrintOperandsTo(stream); } template<int R, int I, int T> void LTemplateInstruction<R, I, T>::PrintOutputOperandTo(StringStream* stream) { - if (this->HasResult()) { - this->result()->PrintTo(stream); - stream->Add(" "); + results_.PrintOperandsTo(stream); +} + + +template<typename T, int N> +void OperandContainer<T, N>::PrintOperandsTo(StringStream* stream) { + for (int i = 0; i < N; i++) { + if (i > 0) stream->Add(" "); + elems_[i]->PrintTo(stream); } } @@ -172,22 +176,22 @@ void LGoto::PrintDataTo(StringStream* stream) { void LBranch::PrintDataTo(StringStream* stream) { stream->Add("B%d | B%d on ", true_block_id(), false_block_id()); - input()->PrintTo(stream); + InputAt(0)->PrintTo(stream); } void LCmpIDAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if "); - left()->PrintTo(stream); + InputAt(0)->PrintTo(stream); stream->Add(" %s ", Token::String(op())); - right()->PrintTo(stream); + InputAt(1)->PrintTo(stream); stream->Add(" then B%d else B%d", true_block_id(), false_block_id()); } void LIsNullAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if "); - input()->PrintTo(stream); + InputAt(0)->PrintTo(stream); stream->Add(is_strict() ? " === null" : " == null"); stream->Add(" then B%d else B%d", true_block_id(), false_block_id()); } @@ -195,35 +199,35 @@ void LIsNullAndBranch::PrintDataTo(StringStream* stream) { void LIsObjectAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if is_object("); - input()->PrintTo(stream); + InputAt(0)->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LIsSmiAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if is_smi("); - input()->PrintTo(stream); + InputAt(0)->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if has_instance_type("); - input()->PrintTo(stream); + InputAt(0)->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if has_cached_array_index("); - input()->PrintTo(stream); + InputAt(0)->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if class_of_test("); - input()->PrintTo(stream); + InputAt(0)->PrintTo(stream); stream->Add(", \"%o\") then B%d else B%d", *hydrogen()->class_name(), true_block_id(), @@ -232,14 +236,14 @@ void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) { void LTypeofIs::PrintDataTo(StringStream* stream) { - input()->PrintTo(stream); + InputAt(0)->PrintTo(stream); stream->Add(" == \"%s\"", *hydrogen()->type_literal()->ToCString()); } void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if typeof "); - input()->PrintTo(stream); + InputAt(0)->PrintTo(stream); stream->Add(" == \"%s\" then B%d else B%d", *hydrogen()->type_literal()->ToCString(), true_block_id(), false_block_id()); @@ -253,7 +257,7 @@ void LCallConstantFunction::PrintDataTo(StringStream* stream) { void LUnaryMathOperation::PrintDataTo(StringStream* stream) { stream->Add("/%s ", hydrogen()->OpName()); - input()->PrintTo(stream); + InputAt(0)->PrintTo(stream); } @@ -286,14 +290,14 @@ void LCallKnownGlobal::PrintDataTo(StringStream* stream) { void LCallNew::PrintDataTo(StringStream* stream) { stream->Add("= "); - input()->PrintTo(stream); + InputAt(0)->PrintTo(stream); stream->Add(" #%d / ", arity()); } void LClassOfTest::PrintDataTo(StringStream* stream) { stream->Add("= class_of_test("); - input()->PrintTo(stream); + InputAt(0)->PrintTo(stream); stream->Add(", \"%o\")", *hydrogen()->class_name()); } @@ -316,7 +320,7 @@ int LChunk::GetNextSpillIndex(bool is_double) { } -LOperand* LChunk::GetNextSpillSlot(bool is_double) { +LOperand* LChunk::GetNextSpillSlot(bool is_double) { int index = GetNextSpillIndex(is_double); if (is_double) { return LDoubleStackSlot::Create(index); @@ -570,6 +574,13 @@ LOperand* LChunkBuilder::UseRegisterOrConstantAtStart(HValue* value) { } +LOperand* LChunkBuilder::UseAny(HValue* value) { + return value->IsConstant() + ? chunk_->DefineConstantOperand(HConstant::cast(value)) + : Use(value, new LUnallocated(LUnallocated::ANY)); +} + + LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) { if (value->EmitAtUses()) { HInstruction* instr = HInstruction::cast(value); @@ -883,8 +894,17 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) { if (FLAG_stress_environments && !instr->HasEnvironment()) { instr = AssignEnvironment(instr); } - if (current->IsBranch()) { - instr->set_hydrogen_value(HBranch::cast(current)->value()); + if (current->IsBranch() && !instr->IsGoto()) { + // TODO(fschneider): Handle branch instructions uniformly like + // other instructions. This requires us to generate the right + // branch instruction already at the HIR level. + ASSERT(instr->IsControl()); + HBranch* branch = HBranch::cast(current); + instr->set_hydrogen_value(branch->value()); + HBasicBlock* first = branch->FirstSuccessor(); + HBasicBlock* second = branch->SecondSuccessor(); + ASSERT(first != NULL && second != NULL); + instr->SetBranchTargets(first->block_id(), second->block_id()); } else { instr->set_hydrogen_value(current); } @@ -921,11 +941,7 @@ LEnvironment* LChunkBuilder::CreateEnvironment(HEnvironment* hydrogen_env) { } else if (value->IsPushArgument()) { op = new LArgument(argument_index++); } else { - op = UseOrConstant(value); - if (op->IsUnallocated()) { - LUnallocated* unalloc = LUnallocated::cast(op); - unalloc->set_policy(LUnallocated::ANY); - } + op = UseAny(value); } result->AddValue(op, value->representation()); } @@ -945,12 +961,6 @@ LInstruction* LChunkBuilder::DoGoto(HGoto* instr) { LInstruction* LChunkBuilder::DoBranch(HBranch* instr) { HValue* v = instr->value(); - HBasicBlock* first = instr->FirstSuccessor(); - HBasicBlock* second = instr->SecondSuccessor(); - ASSERT(first != NULL && second != NULL); - int first_id = first->block_id(); - int second_id = second->block_id(); - if (v->EmitAtUses()) { if (v->IsClassOfTest()) { HClassOfTest* compare = HClassOfTest::cast(v); @@ -958,9 +968,7 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) { return new LClassOfTestAndBranch(UseTempRegister(compare->value()), TempRegister(), - TempRegister(), - first_id, - second_id); + TempRegister()); } else if (v->IsCompare()) { HCompare* compare = HCompare::cast(v); Token::Value op = compare->token(); @@ -972,17 +980,13 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) { ASSERT(right->representation().IsInteger32()); return new LCmpIDAndBranch(UseRegisterAtStart(left), - UseOrConstantAtStart(right), - first_id, - second_id); + UseOrConstantAtStart(right)); } else if (r.IsDouble()) { ASSERT(left->representation().IsDouble()); ASSERT(right->representation().IsDouble()); return new LCmpIDAndBranch(UseRegisterAtStart(left), - UseRegisterAtStart(right), - first_id, - second_id); + UseRegisterAtStart(right)); } else { ASSERT(left->representation().IsTagged()); ASSERT(right->representation().IsTagged()); @@ -990,32 +994,26 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) { LOperand* left_operand = UseFixed(left, reversed ? eax : edx); LOperand* right_operand = UseFixed(right, reversed ? edx : eax); LCmpTAndBranch* result = new LCmpTAndBranch(left_operand, - right_operand, - first_id, - second_id); + right_operand); return MarkAsCall(result, instr); } } else if (v->IsIsSmi()) { HIsSmi* compare = HIsSmi::cast(v); ASSERT(compare->value()->representation().IsTagged()); - return new LIsSmiAndBranch(Use(compare->value()), - first_id, - second_id); + return new LIsSmiAndBranch(Use(compare->value())); } else if (v->IsHasInstanceType()) { HHasInstanceType* compare = HHasInstanceType::cast(v); ASSERT(compare->value()->representation().IsTagged()); return new LHasInstanceTypeAndBranch(UseRegisterAtStart(compare->value()), - TempRegister(), - first_id, - second_id); + TempRegister()); } else if (v->IsHasCachedArrayIndex()) { HHasCachedArrayIndex* compare = HHasCachedArrayIndex::cast(v); ASSERT(compare->value()->representation().IsTagged()); return new LHasCachedArrayIndexAndBranch( - UseRegisterAtStart(compare->value()), first_id, second_id); + UseRegisterAtStart(compare->value())); } else if (v->IsIsNull()) { HIsNull* compare = HIsNull::cast(v); ASSERT(compare->value()->representation().IsTagged()); @@ -1023,9 +1021,7 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) { // We only need a temp register for non-strict compare. LOperand* temp = compare->is_strict() ? NULL : TempRegister(); return new LIsNullAndBranch(UseRegisterAtStart(compare->value()), - temp, - first_id, - second_id); + temp); } else if (v->IsIsObject()) { HIsObject* compare = HIsObject::cast(v); ASSERT(compare->value()->representation().IsTagged()); @@ -1034,42 +1030,34 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) { LOperand* temp2 = TempRegister(); return new LIsObjectAndBranch(UseRegisterAtStart(compare->value()), temp1, - temp2, - first_id, - second_id); + temp2); } else if (v->IsCompareJSObjectEq()) { HCompareJSObjectEq* compare = HCompareJSObjectEq::cast(v); return new LCmpJSObjectEqAndBranch(UseRegisterAtStart(compare->left()), - UseRegisterAtStart(compare->right()), - first_id, - second_id); + UseRegisterAtStart(compare->right())); } else if (v->IsInstanceOf()) { HInstanceOf* instance_of = HInstanceOf::cast(v); LInstanceOfAndBranch* result = new LInstanceOfAndBranch( UseFixed(instance_of->left(), InstanceofStub::left()), - UseFixed(instance_of->right(), InstanceofStub::right()), - first_id, - second_id); + UseFixed(instance_of->right(), InstanceofStub::right())); return MarkAsCall(result, instr); } else if (v->IsTypeofIs()) { HTypeofIs* typeof_is = HTypeofIs::cast(v); - return new LTypeofIsAndBranch(UseTempRegister(typeof_is->value()), - first_id, - second_id); + return new LTypeofIsAndBranch(UseTempRegister(typeof_is->value())); } else { if (v->IsConstant()) { if (HConstant::cast(v)->handle()->IsTrue()) { - return new LGoto(first_id); + return new LGoto(instr->FirstSuccessor()->block_id()); } else if (HConstant::cast(v)->handle()->IsFalse()) { - return new LGoto(second_id); + return new LGoto(instr->SecondSuccessor()->block_id()); } } Abort("Undefined compare before branch"); return NULL; } } - return new LBranch(UseRegisterAtStart(v), first_id, second_id); + return new LBranch(UseRegisterAtStart(v)); } @@ -1178,8 +1166,8 @@ LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) { LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) { ASSERT(instr->key()->representation().IsTagged()); argument_count_ -= instr->argument_count(); - UseFixed(instr->key(), ecx); - return MarkAsCall(DefineFixed(new LCallKeyed, eax), instr); + LOperand* key = UseFixed(instr->key(), ecx); + return MarkAsCall(DefineFixed(new LCallKeyed(key), eax), instr); } @@ -1266,10 +1254,11 @@ LInstruction* LChunkBuilder::DoDiv(HDiv* instr) { } else if (instr->representation().IsInteger32()) { // The temporary operand is necessary to ensure that right is not allocated // into edx. - FixedTemp(edx); + LOperand* temp = FixedTemp(edx); LOperand* value = UseFixed(instr->left(), eax); LOperand* divisor = UseRegister(instr->right()); - return AssignEnvironment(DefineFixed(new LDivI(value, divisor), eax)); + LDivI* result = new LDivI(value, divisor, temp); + return AssignEnvironment(DefineFixed(result, eax)); } else { ASSERT(instr->representation().IsTagged()); return DoArithmeticT(Token::DIV, instr); @@ -1283,10 +1272,10 @@ LInstruction* LChunkBuilder::DoMod(HMod* instr) { ASSERT(instr->right()->representation().IsInteger32()); // The temporary operand is necessary to ensure that right is not allocated // into edx. - FixedTemp(edx); + LOperand* temp = FixedTemp(edx); LOperand* value = UseFixed(instr->left(), eax); LOperand* divisor = UseRegister(instr->right()); - LModI* mod = new LModI(value, divisor); + LModI* mod = new LModI(value, divisor, temp); LInstruction* result = DefineFixed(mod, edx); return (instr->CheckFlag(HValue::kBailoutOnMinusZero) || instr->CheckFlag(HValue::kCanBeDivByZero)) diff --git a/deps/v8/src/ia32/lithium-ia32.h b/deps/v8/src/ia32/lithium-ia32.h index 07f0a8d90b..67f87518a9 100644 --- a/deps/v8/src/ia32/lithium-ia32.h +++ b/deps/v8/src/ia32/lithium-ia32.h @@ -43,10 +43,22 @@ class LCodeGen; // Type hierarchy: // // LInstruction -// LAccessArgumentsAt -// LArgumentsElements -// LArgumentsLength -// LBinaryOperation +// LTemplateInstruction +// LControlInstruction +// LBranch +// LClassOfTestAndBranch +// LCmpJSObjectEqAndBranch +// LCmpIDAndBranch +// LHasCachedArrayIndexAndBranch +// LHasInstanceTypeAndBranch +// LInstanceOfAndBranch +// LIsNullAndBranch +// LIsObjectAndBranch +// LIsSmiAndBranch +// LTypeofIsAndBranch +// LAccessArgumentsAt +// LArgumentsElements +// LArgumentsLength // LAddI // LApplyArguments // LArithmeticD @@ -54,13 +66,10 @@ class LCodeGen; // LBitI // LBoundsCheck // LCmpID -// LCmpIDAndBranch // LCmpJSObjectEq -// LCmpJSObjectEqAndBranch // LCmpT // LDivI // LInstanceOf -// LInstanceOfAndBranch // LInstanceOfKnownGlobal // LLoadKeyedFastElement // LLoadKeyedGeneric @@ -69,67 +78,59 @@ class LCodeGen; // LPower // LShiftI // LSubI -// LCallConstantFunction -// LCallFunction -// LCallGlobal -// LCallKeyed -// LCallKnownGlobal -// LCallNamed -// LCallRuntime -// LCallStub -// LCheckPrototypeMaps -// LConstant -// LConstantD -// LConstantI -// LConstantT -// LDeoptimize -// LFunctionLiteral -// LGap -// LLabel -// LGlobalObject -// LGlobalReceiver -// LGoto -// LLazyBailout -// LLoadContextSlot -// LLoadGlobal -// LMaterializedLiteral +// LCallConstantFunction +// LCallFunction +// LCallGlobal +// LCallKeyed +// LCallKnownGlobal +// LCallNamed +// LCallRuntime +// LCallStub +// LConstant +// LConstantD +// LConstantI +// LConstantT +// LDeoptimize +// LFunctionLiteral +// LGap +// LLabel +// LGlobalObject +// LGlobalReceiver +// LGoto +// LLazyBailout +// LLoadGlobal +// LCheckPrototypeMaps +// LLoadContextSlot // LArrayLiteral // LObjectLiteral // LRegExpLiteral -// LOsrEntry -// LParameter -// LRegExpConstructResult -// LStackCheck -// LStoreKeyed -// LStoreKeyedFastElement -// LStoreKeyedGeneric -// LStoreNamed -// LStoreNamedField -// LStoreNamedGeneric -// LUnaryOperation +// LOsrEntry +// LParameter +// LRegExpConstructResult +// LStackCheck +// LStoreKeyed +// LStoreKeyedFastElement +// LStoreKeyedGeneric +// LStoreNamed +// LStoreNamedField +// LStoreNamedGeneric // LBitNotI -// LBranch // LCallNew // LCheckFunction +// LCheckPrototypeMaps // LCheckInstanceType // LCheckMap // LCheckSmi // LClassOfTest -// LClassOfTestAndBranch // LDeleteProperty // LDoubleToI // LFixedArrayLength // LHasCachedArrayIndex -// LHasCachedArrayIndexAndBranch // LHasInstanceType -// LHasInstanceTypeAndBranch // LInteger32ToDouble // LIsNull -// LIsNullAndBranch // LIsObject -// LIsObjectAndBranch // LIsSmi -// LIsSmiAndBranch // LJSArrayLength // LLoadNamedField // LLoadNamedGeneric @@ -144,19 +145,16 @@ class LCodeGen; // LThrow // LTypeof // LTypeofIs -// LTypeofIsAndBranch // LUnaryMathOperation // LValueOf -// LUnknownOSRValue +// LUnknownOSRValue #define LITHIUM_ALL_INSTRUCTION_LIST(V) \ - V(BinaryOperation) \ + V(ControlInstruction) \ V(Constant) \ V(Call) \ - V(MaterializedLiteral) \ V(StoreKeyed) \ V(StoreNamed) \ - V(UnaryOperation) \ LITHIUM_CONCRETE_INSTRUCTION_LIST(V) @@ -302,7 +300,9 @@ class LInstruction: public ZoneObject { #define DECLARE_DO(type) virtual bool Is##type() const { return false; } LITHIUM_ALL_INSTRUCTION_LIST(DECLARE_DO) #undef DECLARE_DO + virtual bool IsControl() const { return false; } + virtual void SetBranchTargets(int true_block_id, int false_block_id) { } void set_environment(LEnvironment* env) { environment_.set(env); } LEnvironment* environment() const { return environment_.get(); } @@ -341,9 +341,13 @@ class OperandContainer { OperandContainer() { for (int i = 0; i < N; i++) elems_[i] = NULL; } - int length() const { return N; } - T at(int i) const { return elems_[i]; } - void set_at(int i, T value) { elems_[i] = value; } + int length() { return N; } + T& operator[](int i) { + ASSERT(i < length()); + return elems_[i]; + } + void PrintOperandsTo(StringStream* stream); + private: T elems_[N]; }; @@ -352,38 +356,31 @@ class OperandContainer { template<typename T> class OperandContainer<T, 0> { public: - int length() const { return 0; } - T at(int i) const { - UNREACHABLE(); - return NULL; - } - void set_at(int i, T value) { - UNREACHABLE(); - } + int length() { return 0; } + void PrintOperandsTo(StringStream* stream) { } }; -template<int R, int I, int T> +template<int R, int I, int T = 0> class LTemplateInstruction: public LInstruction { public: // Allow 0 or 1 output operands. STATIC_ASSERT(R == 0 || R == 1); virtual bool HasResult() const { return R != 0; } - void set_result(LOperand* operand) { outputs_.set_at(0, operand); } - LOperand* result() const { return outputs_.at(0); } + void set_result(LOperand* operand) { results_[0] = operand; } + LOperand* result() { return results_[0]; } - int InputCount() const { return inputs_.length(); } - LOperand* InputAt(int i) const { return inputs_.at(i); } - void SetInputAt(int i, LOperand* operand) { inputs_.set_at(i, operand); } + int InputCount() { return I; } + LOperand* InputAt(int i) { return inputs_[i]; } - int TempCount() const { return temps_.length(); } - LOperand* TempAt(int i) const { return temps_.at(i); } + int TempCount() { return T; } + LOperand* TempAt(int i) { return temps_[i]; } virtual void PrintDataTo(StringStream* stream); virtual void PrintOutputOperandTo(StringStream* stream); - private: - OperandContainer<LOperand*, R> outputs_; + protected: + OperandContainer<LOperand*, R> results_; OperandContainer<LOperand*, I> inputs_; OperandContainer<LOperand*, T> temps_; }; @@ -515,31 +512,22 @@ class LUnknownOSRValue: public LTemplateInstruction<1, 0, 0> { }; -template<int R> -class LUnaryOperation: public LTemplateInstruction<R, 1, 0> { +template<int I, int T = 0> +class LControlInstruction: public LTemplateInstruction<0, I, T> { public: - explicit LUnaryOperation<R>(LOperand* input) { - this->SetInputAt(0, input); - } - - LOperand* input() const { return this->InputAt(0); } - - DECLARE_INSTRUCTION(UnaryOperation) -}; - + DECLARE_INSTRUCTION(ControlInstruction) + virtual bool IsControl() const { return true; } -template<int R> -class LBinaryOperation: public LTemplateInstruction<R, 2, 0> { - public: - LBinaryOperation(LOperand* left, LOperand* right) { - this->SetInputAt(0, left); - this->SetInputAt(1, right); + int true_block_id() const { return true_block_id_; } + int false_block_id() const { return false_block_id_; } + void SetBranchTargets(int true_block_id, int false_block_id) { + true_block_id_ = true_block_id; + false_block_id_ = false_block_id; } - DECLARE_INSTRUCTION(BinaryOperation) - - LOperand* left() const { return this->InputAt(0); } - LOperand* right() const { return this->InputAt(1); } + private: + int true_block_id_; + int false_block_id_; }; @@ -549,43 +537,44 @@ class LApplyArguments: public LTemplateInstruction<1, 4, 0> { LOperand* receiver, LOperand* length, LOperand* elements) { - this->SetInputAt(0, function); - this->SetInputAt(1, receiver); - this->SetInputAt(2, length); - this->SetInputAt(3, elements); + inputs_[0] = function; + inputs_[1] = receiver; + inputs_[2] = length; + inputs_[3] = elements; } DECLARE_CONCRETE_INSTRUCTION(ApplyArguments, "apply-arguments") - LOperand* function() const { return InputAt(0); } - LOperand* receiver() const { return InputAt(1); } - LOperand* length() const { return InputAt(2); } - LOperand* elements() const { return InputAt(3); } + LOperand* function() { return inputs_[0]; } + LOperand* receiver() { return inputs_[1]; } + LOperand* length() { return inputs_[2]; } + LOperand* elements() { return inputs_[3]; } }; class LAccessArgumentsAt: public LTemplateInstruction<1, 3, 0> { public: LAccessArgumentsAt(LOperand* arguments, LOperand* length, LOperand* index) { - this->SetInputAt(0, arguments); - this->SetInputAt(1, length); - this->SetInputAt(2, index); + inputs_[0] = arguments; + inputs_[1] = length; + inputs_[2] = index; } DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt, "access-arguments-at") - LOperand* arguments() const { return this->InputAt(0); } - LOperand* length() const { return this->InputAt(1); } - LOperand* index() const { return this->InputAt(2); } + LOperand* arguments() { return inputs_[0]; } + LOperand* length() { return inputs_[1]; } + LOperand* index() { return inputs_[2]; } virtual void PrintDataTo(StringStream* stream); }; -class LArgumentsLength: public LUnaryOperation<1> { +class LArgumentsLength: public LTemplateInstruction<1, 1> { public: - explicit LArgumentsLength(LOperand* elements) - : LUnaryOperation<1>(elements) {} + explicit LArgumentsLength(LOperand* elements) { + inputs_[0] = elements; + } DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength, "arguments-length") }; @@ -599,82 +588,86 @@ class LArgumentsElements: public LTemplateInstruction<1, 0, 0> { }; -class LModI: public LBinaryOperation<1> { +class LModI: public LTemplateInstruction<1, 2, 1> { public: - LModI(LOperand* left, LOperand* right) : LBinaryOperation<1>(left, right) { } + LModI(LOperand* left, LOperand* right, LOperand* temp) { + inputs_[0] = left; + inputs_[1] = right; + temps_[0] = temp; + } DECLARE_CONCRETE_INSTRUCTION(ModI, "mod-i") DECLARE_HYDROGEN_ACCESSOR(Mod) }; -class LDivI: public LBinaryOperation<1> { +class LDivI: public LTemplateInstruction<1, 2, 1> { public: - LDivI(LOperand* left, LOperand* right) - : LBinaryOperation<1>(left, right) { } + LDivI(LOperand* left, LOperand* right, LOperand* temp) { + inputs_[0] = left; + inputs_[1] = right; + temps_[0] = temp; + } DECLARE_CONCRETE_INSTRUCTION(DivI, "div-i") DECLARE_HYDROGEN_ACCESSOR(Div) }; -class LMulI: public LBinaryOperation<1> { +class LMulI: public LTemplateInstruction<1, 2, 1> { public: - LMulI(LOperand* left, LOperand* right, LOperand* temp) - : LBinaryOperation<1>(left, right), temp_(temp) { } + LMulI(LOperand* left, LOperand* right, LOperand* temp) { + inputs_[0] = left; + inputs_[1] = right; + temps_[0] = temp; + } DECLARE_CONCRETE_INSTRUCTION(MulI, "mul-i") DECLARE_HYDROGEN_ACCESSOR(Mul) - - LOperand* temp() const { return temp_; } - - private: - LOperand* temp_; }; -class LCmpID: public LBinaryOperation<1> { +class LCmpID: public LTemplateInstruction<1, 2> { public: - LCmpID(LOperand* left, LOperand* right) - : LBinaryOperation<1>(left, right) { } + LCmpID(LOperand* left, LOperand* right) { + inputs_[0] = left; + inputs_[1] = right; + } + + DECLARE_CONCRETE_INSTRUCTION(CmpID, "cmp-id") + DECLARE_HYDROGEN_ACCESSOR(Compare) Token::Value op() const { return hydrogen()->token(); } bool is_double() const { return hydrogen()->GetInputRepresentation().IsDouble(); } - - DECLARE_CONCRETE_INSTRUCTION(CmpID, "cmp-id") - DECLARE_HYDROGEN_ACCESSOR(Compare) }; -class LCmpIDAndBranch: public LCmpID { +class LCmpIDAndBranch: public LControlInstruction<2> { public: - LCmpIDAndBranch(LOperand* left, - LOperand* right, - int true_block_id, - int false_block_id) - : LCmpID(left, right), - true_block_id_(true_block_id), - false_block_id_(false_block_id) { } + LCmpIDAndBranch(LOperand* left, LOperand* right) { + inputs_[0] = left; + inputs_[1] = right; + } DECLARE_CONCRETE_INSTRUCTION(CmpIDAndBranch, "cmp-id-and-branch") - virtual void PrintDataTo(StringStream* stream); - virtual bool IsControl() const { return true; } + DECLARE_HYDROGEN_ACCESSOR(Compare) - int true_block_id() const { return true_block_id_; } - int false_block_id() const { return false_block_id_; } + Token::Value op() const { return hydrogen()->token(); } + bool is_double() const { + return hydrogen()->GetInputRepresentation().IsDouble(); + } - private: - int true_block_id_; - int false_block_id_; + virtual void PrintDataTo(StringStream* stream); }; -class LUnaryMathOperation: public LUnaryOperation<1> { +class LUnaryMathOperation: public LTemplateInstruction<1, 1> { public: - explicit LUnaryMathOperation(LOperand* value) - : LUnaryOperation<1>(value) { } + explicit LUnaryMathOperation(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation, "unary-math-operation") DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation) @@ -684,40 +677,34 @@ class LUnaryMathOperation: public LUnaryOperation<1> { }; -class LCmpJSObjectEq: public LBinaryOperation<1> { +class LCmpJSObjectEq: public LTemplateInstruction<1, 2> { public: - LCmpJSObjectEq(LOperand* left, LOperand* right) - : LBinaryOperation<1>(left, right) {} + LCmpJSObjectEq(LOperand* left, LOperand* right) { + inputs_[0] = left; + inputs_[1] = right; + } DECLARE_CONCRETE_INSTRUCTION(CmpJSObjectEq, "cmp-jsobject-eq") }; -class LCmpJSObjectEqAndBranch: public LCmpJSObjectEq { +class LCmpJSObjectEqAndBranch: public LControlInstruction<2> { public: - LCmpJSObjectEqAndBranch(LOperand* left, - LOperand* right, - int true_block_id, - int false_block_id) - : LCmpJSObjectEq(left, right), - true_block_id_(true_block_id), - false_block_id_(false_block_id) { } + LCmpJSObjectEqAndBranch(LOperand* left, LOperand* right) { + inputs_[0] = left; + inputs_[1] = right; + } DECLARE_CONCRETE_INSTRUCTION(CmpJSObjectEqAndBranch, "cmp-jsobject-eq-and-branch") - - int true_block_id() const { return true_block_id_; } - int false_block_id() const { return false_block_id_; } - - private: - int true_block_id_; - int false_block_id_; }; -class LIsNull: public LUnaryOperation<1> { +class LIsNull: public LTemplateInstruction<1, 1> { public: - explicit LIsNull(LOperand* value) : LUnaryOperation<1>(value) { } + explicit LIsNull(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(IsNull, "is-null") DECLARE_HYDROGEN_ACCESSOR(IsNull) @@ -726,227 +713,155 @@ class LIsNull: public LUnaryOperation<1> { }; -class LIsNullAndBranch: public LIsNull { +class LIsNullAndBranch: public LControlInstruction<1, 1> { public: - LIsNullAndBranch(LOperand* value, - LOperand* temp, - int true_block_id, - int false_block_id) - : LIsNull(value), - temp_(temp), - true_block_id_(true_block_id), - false_block_id_(false_block_id) { } + LIsNullAndBranch(LOperand* value, LOperand* temp) { + inputs_[0] = value; + temps_[0] = temp; + } DECLARE_CONCRETE_INSTRUCTION(IsNullAndBranch, "is-null-and-branch") - virtual void PrintDataTo(StringStream* stream); - virtual bool IsControl() const { return true; } - - int true_block_id() const { return true_block_id_; } - int false_block_id() const { return false_block_id_; } + DECLARE_HYDROGEN_ACCESSOR(IsNull) - LOperand* temp() const { return temp_; } + bool is_strict() const { return hydrogen()->is_strict(); } - private: - LOperand* temp_; - int true_block_id_; - int false_block_id_; + virtual void PrintDataTo(StringStream* stream); }; -class LIsObject: public LUnaryOperation<1> { +class LIsObject: public LTemplateInstruction<1, 1, 1> { public: - LIsObject(LOperand* value, LOperand* temp) - : LUnaryOperation<1>(value), temp_(temp) {} + LIsObject(LOperand* value, LOperand* temp) { + inputs_[0] = value; + temps_[0] = temp; + } DECLARE_CONCRETE_INSTRUCTION(IsObject, "is-object") - - LOperand* temp() const { return temp_; } - - private: - LOperand* temp_; }; -class LIsObjectAndBranch: public LIsObject { +class LIsObjectAndBranch: public LControlInstruction<1, 2> { public: - LIsObjectAndBranch(LOperand* value, - LOperand* temp, - LOperand* temp2, - int true_block_id, - int false_block_id) - : LIsObject(value, temp), - temp2_(temp2), - true_block_id_(true_block_id), - false_block_id_(false_block_id) { } + LIsObjectAndBranch(LOperand* value, LOperand* temp, LOperand* temp2) { + inputs_[0] = value; + temps_[0] = temp; + temps_[1] = temp2; + } DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch") - virtual void PrintDataTo(StringStream* stream); - virtual bool IsControl() const { return true; } - - int true_block_id() const { return true_block_id_; } - int false_block_id() const { return false_block_id_; } - LOperand* temp2() const { return temp2_; } - - private: - LOperand* temp2_; - int true_block_id_; - int false_block_id_; + virtual void PrintDataTo(StringStream* stream); }; -class LIsSmi: public LUnaryOperation<1> { +class LIsSmi: public LTemplateInstruction<1, 1> { public: - explicit LIsSmi(LOperand* value) : LUnaryOperation<1>(value) {} + explicit LIsSmi(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(IsSmi, "is-smi") DECLARE_HYDROGEN_ACCESSOR(IsSmi) }; -class LIsSmiAndBranch: public LIsSmi { +class LIsSmiAndBranch: public LControlInstruction<1> { public: - LIsSmiAndBranch(LOperand* value, - int true_block_id, - int false_block_id) - : LIsSmi(value), - true_block_id_(true_block_id), - false_block_id_(false_block_id) { } + explicit LIsSmiAndBranch(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch, "is-smi-and-branch") - virtual void PrintDataTo(StringStream* stream); - virtual bool IsControl() const { return true; } - - int true_block_id() const { return true_block_id_; } - int false_block_id() const { return false_block_id_; } - private: - int true_block_id_; - int false_block_id_; + virtual void PrintDataTo(StringStream* stream); }; -class LHasInstanceType: public LUnaryOperation<1> { +class LHasInstanceType: public LTemplateInstruction<1, 1> { public: - explicit LHasInstanceType(LOperand* value) - : LUnaryOperation<1>(value) { } + explicit LHasInstanceType(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(HasInstanceType, "has-instance-type") DECLARE_HYDROGEN_ACCESSOR(HasInstanceType) - - InstanceType TestType(); // The type to test against when generating code. - Condition BranchCondition(); // The branch condition for 'true'. }; -class LHasInstanceTypeAndBranch: public LHasInstanceType { +class LHasInstanceTypeAndBranch: public LControlInstruction<1, 1> { public: - LHasInstanceTypeAndBranch(LOperand* value, - LOperand* temporary, - int true_block_id, - int false_block_id) - : LHasInstanceType(value), - temp_(temporary), - true_block_id_(true_block_id), - false_block_id_(false_block_id) { } + LHasInstanceTypeAndBranch(LOperand* value, LOperand* temp) { + inputs_[0] = value; + temps_[0] = temp; + } DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch, "has-instance-type-and-branch") - virtual void PrintDataTo(StringStream* stream); - virtual bool IsControl() const { return true; } - - int true_block_id() const { return true_block_id_; } - int false_block_id() const { return false_block_id_; } - - LOperand* temp() { return temp_; } + DECLARE_HYDROGEN_ACCESSOR(HasInstanceType) - private: - LOperand* temp_; - int true_block_id_; - int false_block_id_; + virtual void PrintDataTo(StringStream* stream); }; -class LHasCachedArrayIndex: public LUnaryOperation<1> { +class LHasCachedArrayIndex: public LTemplateInstruction<1, 1> { public: - explicit LHasCachedArrayIndex(LOperand* value) : LUnaryOperation<1>(value) {} + explicit LHasCachedArrayIndex(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndex, "has-cached-array-index") DECLARE_HYDROGEN_ACCESSOR(HasCachedArrayIndex) }; -class LHasCachedArrayIndexAndBranch: public LHasCachedArrayIndex { +class LHasCachedArrayIndexAndBranch: public LControlInstruction<1> { public: - LHasCachedArrayIndexAndBranch(LOperand* value, - int true_block_id, - int false_block_id) - : LHasCachedArrayIndex(value), - true_block_id_(true_block_id), - false_block_id_(false_block_id) { } + explicit LHasCachedArrayIndexAndBranch(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch, "has-cached-array-index-and-branch") virtual void PrintDataTo(StringStream* stream); - virtual bool IsControl() const { return true; } - - int true_block_id() const { return true_block_id_; } - int false_block_id() const { return false_block_id_; } - - private: - int true_block_id_; - int false_block_id_; }; -class LClassOfTest: public LUnaryOperation<1> { +class LClassOfTest: public LTemplateInstruction<1, 1, 1> { public: - LClassOfTest(LOperand* value, LOperand* temp) - : LUnaryOperation<1>(value), temporary_(temp) {} + LClassOfTest(LOperand* value, LOperand* temp) { + inputs_[0] = value; + temps_[0] = temp; + } DECLARE_CONCRETE_INSTRUCTION(ClassOfTest, "class-of-test") DECLARE_HYDROGEN_ACCESSOR(ClassOfTest) virtual void PrintDataTo(StringStream* stream); - - LOperand* temporary() { return temporary_; } - - private: - LOperand* temporary_; }; -class LClassOfTestAndBranch: public LClassOfTest { +class LClassOfTestAndBranch: public LControlInstruction<1, 2> { public: - LClassOfTestAndBranch(LOperand* value, - LOperand* temporary, - LOperand* temporary2, - int true_block_id, - int false_block_id) - : LClassOfTest(value, temporary), - temporary2_(temporary2), - true_block_id_(true_block_id), - false_block_id_(false_block_id) { } + LClassOfTestAndBranch(LOperand* value, LOperand* temp, LOperand* temp2) { + inputs_[0] = value; + temps_[0] = temp; + temps_[1] = temp2; + } DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch, "class-of-test-and-branch") - virtual void PrintDataTo(StringStream* stream); - virtual bool IsControl() const { return true; } - - int true_block_id() const { return true_block_id_; } - int false_block_id() const { return false_block_id_; } - LOperand* temporary2() { return temporary2_; } + DECLARE_HYDROGEN_ACCESSOR(ClassOfTest) - private: - LOperand* temporary2_; - int true_block_id_; - int false_block_id_; + virtual void PrintDataTo(StringStream* stream); }; -class LCmpT: public LBinaryOperation<1> { +class LCmpT: public LTemplateInstruction<1, 2> { public: - LCmpT(LOperand* left, LOperand* right) : LBinaryOperation<1>(left, right) {} + LCmpT(LOperand* left, LOperand* right) { + inputs_[0] = left; + inputs_[1] = right; + } DECLARE_CONCRETE_INSTRUCTION(CmpT, "cmp-t") DECLARE_HYDROGEN_ACCESSOR(Compare) @@ -955,90 +870,78 @@ class LCmpT: public LBinaryOperation<1> { }; -class LCmpTAndBranch: public LCmpT { +class LCmpTAndBranch: public LControlInstruction<2> { public: - LCmpTAndBranch(LOperand* left, - LOperand* right, - int true_block_id, - int false_block_id) - : LCmpT(left, right), - true_block_id_(true_block_id), - false_block_id_(false_block_id) { } + LCmpTAndBranch(LOperand* left, LOperand* right) { + inputs_[0] = left; + inputs_[1] = right; + } DECLARE_CONCRETE_INSTRUCTION(CmpTAndBranch, "cmp-t-and-branch") + DECLARE_HYDROGEN_ACCESSOR(Compare) - int true_block_id() const { return true_block_id_; } - int false_block_id() const { return false_block_id_; } - - private: - int true_block_id_; - int false_block_id_; + Token::Value op() const { return hydrogen()->token(); } }; -class LInstanceOf: public LBinaryOperation<1> { +class LInstanceOf: public LTemplateInstruction<1, 2> { public: - LInstanceOf(LOperand* left, LOperand* right) - : LBinaryOperation<1>(left, right) { } + LInstanceOf(LOperand* left, LOperand* right) { + inputs_[0] = left; + inputs_[1] = right; + } DECLARE_CONCRETE_INSTRUCTION(InstanceOf, "instance-of") }; -class LInstanceOfAndBranch: public LInstanceOf { +class LInstanceOfAndBranch: public LControlInstruction<2> { public: - LInstanceOfAndBranch(LOperand* left, - LOperand* right, - int true_block_id, - int false_block_id) - : LInstanceOf(left, right), - true_block_id_(true_block_id), - false_block_id_(false_block_id) { } + LInstanceOfAndBranch(LOperand* left, LOperand* right) { + inputs_[0] = left; + inputs_[1] = right; + } DECLARE_CONCRETE_INSTRUCTION(InstanceOfAndBranch, "instance-of-and-branch") - - int true_block_id() const { return true_block_id_; } - int false_block_id() const { return false_block_id_; } - - private: - int true_block_id_; - int false_block_id_; }; -class LInstanceOfKnownGlobal: public LUnaryOperation<1> { +class LInstanceOfKnownGlobal: public LTemplateInstruction<1, 1, 1> { public: - LInstanceOfKnownGlobal(LOperand* left, LOperand* temp) - : LUnaryOperation<1>(left), temp_(temp) { } + LInstanceOfKnownGlobal(LOperand* value, LOperand* temp) { + inputs_[0] = value; + temps_[0] = temp; + } DECLARE_CONCRETE_INSTRUCTION(InstanceOfKnownGlobal, "instance-of-known-global") DECLARE_HYDROGEN_ACCESSOR(InstanceOfKnownGlobal) Handle<JSFunction> function() const { return hydrogen()->function(); } - LOperand* temp() const { return temp_; } - - private: - LOperand* temp_; }; -class LBoundsCheck: public LBinaryOperation<0> { +class LBoundsCheck: public LTemplateInstruction<0, 2, 0> { public: - LBoundsCheck(LOperand* index, LOperand* length) - : LBinaryOperation<0>(index, length) { } + LBoundsCheck(LOperand* index, LOperand* length) { + inputs_[0] = index; + inputs_[1] = length; + } - LOperand* index() const { return left(); } - LOperand* length() const { return right(); } + LOperand* index() { return inputs_[0]; } + LOperand* length() { return inputs_[1]; } DECLARE_CONCRETE_INSTRUCTION(BoundsCheck, "bounds-check") }; -class LBitI: public LBinaryOperation<1> { +class LBitI: public LTemplateInstruction<1, 2> { public: LBitI(Token::Value op, LOperand* left, LOperand* right) - : LBinaryOperation<1>(left, right), op_(op) { } + : op_(op) { + inputs_[0] = left; + inputs_[1] = right; + } Token::Value op() const { return op_; } @@ -1049,10 +952,13 @@ class LBitI: public LBinaryOperation<1> { }; -class LShiftI: public LBinaryOperation<1> { +class LShiftI: public LTemplateInstruction<1, 2> { public: LShiftI(Token::Value op, LOperand* left, LOperand* right, bool can_deopt) - : LBinaryOperation<1>(left, right), op_(op), can_deopt_(can_deopt) { } + : op_(op), can_deopt_(can_deopt) { + inputs_[0] = left; + inputs_[1] = right; + } Token::Value op() const { return op_; } @@ -1066,10 +972,12 @@ class LShiftI: public LBinaryOperation<1> { }; -class LSubI: public LBinaryOperation<1> { +class LSubI: public LTemplateInstruction<1, 2> { public: - LSubI(LOperand* left, LOperand* right) - : LBinaryOperation<1>(left, right) { } + LSubI(LOperand* left, LOperand* right) { + inputs_[0] = left; + inputs_[1] = right; + } DECLARE_CONCRETE_INSTRUCTION(SubI, "sub-i") DECLARE_HYDROGEN_ACCESSOR(Sub) @@ -1117,31 +1025,24 @@ class LConstantT: public LConstant { }; -class LBranch: public LUnaryOperation<0> { +class LBranch: public LControlInstruction<1> { public: - LBranch(LOperand* input, int true_block_id, int false_block_id) - : LUnaryOperation<0>(input), - true_block_id_(true_block_id), - false_block_id_(false_block_id) { } + explicit LBranch(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(Branch, "branch") DECLARE_HYDROGEN_ACCESSOR(Value) virtual void PrintDataTo(StringStream* stream); - virtual bool IsControl() const { return true; } - - int true_block_id() const { return true_block_id_; } - int false_block_id() const { return false_block_id_; } - - private: - int true_block_id_; - int false_block_id_; }; -class LCmpMapAndBranch: public LUnaryOperation<0> { +class LCmpMapAndBranch: public LTemplateInstruction<0, 1> { public: - explicit LCmpMapAndBranch(LOperand* value) : LUnaryOperation<0>(value) { } + explicit LCmpMapAndBranch(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(CmpMapAndBranch, "cmp-map-and-branch") DECLARE_HYDROGEN_ACCESSOR(CompareMapAndBranch) @@ -1158,79 +1059,91 @@ class LCmpMapAndBranch: public LUnaryOperation<0> { }; -class LJSArrayLength: public LUnaryOperation<1> { +class LJSArrayLength: public LTemplateInstruction<1, 1> { public: - explicit LJSArrayLength(LOperand* input) : LUnaryOperation<1>(input) { } + explicit LJSArrayLength(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(JSArrayLength, "js-array-length") DECLARE_HYDROGEN_ACCESSOR(JSArrayLength) }; -class LFixedArrayLength: public LUnaryOperation<1> { +class LFixedArrayLength: public LTemplateInstruction<1, 1> { public: - explicit LFixedArrayLength(LOperand* input) : LUnaryOperation<1>(input) { } + explicit LFixedArrayLength(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(FixedArrayLength, "fixed-array-length") DECLARE_HYDROGEN_ACCESSOR(FixedArrayLength) }; -class LValueOf: public LUnaryOperation<1> { +class LValueOf: public LTemplateInstruction<1, 1, 1> { public: - LValueOf(LOperand* input, LOperand* temporary) - : LUnaryOperation<1>(input), temporary_(temporary) { } - - LOperand* temporary() const { return temporary_; } + LValueOf(LOperand* value, LOperand* temp) { + inputs_[0] = value; + temps_[0] = temp; + } DECLARE_CONCRETE_INSTRUCTION(ValueOf, "value-of") DECLARE_HYDROGEN_ACCESSOR(ValueOf) - - private: - LOperand* temporary_; }; -class LThrow: public LUnaryOperation<0> { +class LThrow: public LTemplateInstruction<0, 1> { public: - explicit LThrow(LOperand* value) : LUnaryOperation<0>(value) { } + explicit LThrow(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(Throw, "throw") }; -class LBitNotI: public LUnaryOperation<1> { +class LBitNotI: public LTemplateInstruction<1, 1> { public: - explicit LBitNotI(LOperand* input) : LUnaryOperation<1>(input) { } + explicit LBitNotI(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(BitNotI, "bit-not-i") }; -class LAddI: public LBinaryOperation<1> { +class LAddI: public LTemplateInstruction<1, 2> { public: - LAddI(LOperand* left, LOperand* right) - : LBinaryOperation<1>(left, right) { } + LAddI(LOperand* left, LOperand* right) { + inputs_[0] = left; + inputs_[1] = right; + } DECLARE_CONCRETE_INSTRUCTION(AddI, "add-i") DECLARE_HYDROGEN_ACCESSOR(Add) }; -class LPower: public LBinaryOperation<1> { +class LPower: public LTemplateInstruction<1, 2> { public: - LPower(LOperand* left, LOperand* right) - : LBinaryOperation<1>(left, right) { } + LPower(LOperand* left, LOperand* right) { + inputs_[0] = left; + inputs_[1] = right; + } DECLARE_CONCRETE_INSTRUCTION(Power, "power") DECLARE_HYDROGEN_ACCESSOR(Power) }; -class LArithmeticD: public LBinaryOperation<1> { +class LArithmeticD: public LTemplateInstruction<1, 2> { public: LArithmeticD(Token::Value op, LOperand* left, LOperand* right) - : LBinaryOperation<1>(left, right), op_(op) { } + : op_(op) { + inputs_[0] = left; + inputs_[1] = right; + } Token::Value op() const { return op_; } @@ -1242,10 +1155,13 @@ class LArithmeticD: public LBinaryOperation<1> { }; -class LArithmeticT: public LBinaryOperation<1> { +class LArithmeticT: public LTemplateInstruction<1, 2> { public: LArithmeticT(Token::Value op, LOperand* left, LOperand* right) - : LBinaryOperation<1>(left, right), op_(op) { } + : op_(op) { + inputs_[0] = left; + inputs_[1] = right; + } virtual void CompileToNative(LCodeGen* generator); virtual const char* Mnemonic() const; @@ -1257,81 +1173,91 @@ class LArithmeticT: public LBinaryOperation<1> { }; -class LReturn: public LUnaryOperation<0> { +class LReturn: public LTemplateInstruction<0, 1> { public: - explicit LReturn(LOperand* use) : LUnaryOperation<0>(use) { } + explicit LReturn(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(Return, "return") }; -class LLoadNamedField: public LUnaryOperation<1> { +class LLoadNamedField: public LTemplateInstruction<1, 1> { public: - explicit LLoadNamedField(LOperand* object) : LUnaryOperation<1>(object) { } + explicit LLoadNamedField(LOperand* object) { + inputs_[0] = object; + } DECLARE_CONCRETE_INSTRUCTION(LoadNamedField, "load-named-field") DECLARE_HYDROGEN_ACCESSOR(LoadNamedField) }; -class LLoadNamedGeneric: public LUnaryOperation<1> { +class LLoadNamedGeneric: public LTemplateInstruction<1, 1> { public: - explicit LLoadNamedGeneric(LOperand* object) : LUnaryOperation<1>(object) { } + explicit LLoadNamedGeneric(LOperand* object) { + inputs_[0] = object; + } DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric, "load-named-generic") DECLARE_HYDROGEN_ACCESSOR(LoadNamedGeneric) - LOperand* object() const { return input(); } + LOperand* object() { return inputs_[0]; } Handle<Object> name() const { return hydrogen()->name(); } }; -class LLoadFunctionPrototype: public LUnaryOperation<1> { +class LLoadFunctionPrototype: public LTemplateInstruction<1, 1, 1> { public: - LLoadFunctionPrototype(LOperand* function, LOperand* temporary) - : LUnaryOperation<1>(function), temporary_(temporary) { } + LLoadFunctionPrototype(LOperand* function, LOperand* temp) { + inputs_[0] = function; + temps_[0] = temp; + } DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype, "load-function-prototype") DECLARE_HYDROGEN_ACCESSOR(LoadFunctionPrototype) - LOperand* function() const { return input(); } - LOperand* temporary() const { return temporary_; } - - private: - LOperand* temporary_; + LOperand* function() { return inputs_[0]; } }; -class LLoadElements: public LUnaryOperation<1> { +class LLoadElements: public LTemplateInstruction<1, 1> { public: - explicit LLoadElements(LOperand* obj) : LUnaryOperation<1>(obj) { } + explicit LLoadElements(LOperand* object) { + inputs_[0] = object; + } DECLARE_CONCRETE_INSTRUCTION(LoadElements, "load-elements") }; -class LLoadKeyedFastElement: public LBinaryOperation<1> { +class LLoadKeyedFastElement: public LTemplateInstruction<1, 2> { public: - LLoadKeyedFastElement(LOperand* elements, LOperand* key) - : LBinaryOperation<1>(elements, key) { } + LLoadKeyedFastElement(LOperand* elements, LOperand* key) { + inputs_[0] = elements; + inputs_[1] = key; + } DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastElement, "load-keyed-fast-element") DECLARE_HYDROGEN_ACCESSOR(LoadKeyedFastElement) - LOperand* elements() const { return left(); } - LOperand* key() const { return right(); } + LOperand* elements() { return inputs_[0]; } + LOperand* key() { return inputs_[1]; } }; -class LLoadKeyedGeneric: public LBinaryOperation<1> { +class LLoadKeyedGeneric: public LTemplateInstruction<1, 2> { public: - LLoadKeyedGeneric(LOperand* obj, LOperand* key) - : LBinaryOperation<1>(obj, key) { } + LLoadKeyedGeneric(LOperand* obj, LOperand* key) { + inputs_[0] = obj; + inputs_[1] = key; + } DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric, "load-keyed-generic") - LOperand* object() const { return left(); } - LOperand* key() const { return right(); } + LOperand* object() { return inputs_[0]; } + LOperand* key() { return inputs_[1]; } }; @@ -1342,9 +1268,11 @@ class LLoadGlobal: public LTemplateInstruction<1, 0, 0> { }; -class LStoreGlobal: public LUnaryOperation<0> { +class LStoreGlobal: public LTemplateInstruction<0, 1> { public: - explicit LStoreGlobal(LOperand* value) : LUnaryOperation<0>(value) {} + explicit LStoreGlobal(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(StoreGlobal, "store-global") DECLARE_HYDROGEN_ACCESSOR(StoreGlobal) @@ -1356,18 +1284,18 @@ class LLoadContextSlot: public LTemplateInstruction<1, 0, 0> { DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot, "load-context-slot") DECLARE_HYDROGEN_ACCESSOR(LoadContextSlot) - int context_chain_length() const { - return hydrogen()->context_chain_length(); - } - int slot_index() const { return hydrogen()->slot_index(); } + int context_chain_length() { return hydrogen()->context_chain_length(); } + int slot_index() { return hydrogen()->slot_index(); } virtual void PrintDataTo(StringStream* stream); }; -class LPushArgument: public LUnaryOperation<0> { +class LPushArgument: public LTemplateInstruction<0, 1> { public: - explicit LPushArgument(LOperand* argument) : LUnaryOperation<0>(argument) {} + explicit LPushArgument(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(PushArgument, "push-argument") }; @@ -1397,8 +1325,12 @@ class LCallConstantFunction: public LTemplateInstruction<1, 0, 0> { }; -class LCallKeyed: public LTemplateInstruction<1, 0, 0> { +class LCallKeyed: public LTemplateInstruction<1, 1, 0> { public: + explicit LCallKeyed(LOperand* key) { + inputs_[0] = key; + } + DECLARE_CONCRETE_INSTRUCTION(CallKeyed, "call-keyed") DECLARE_HYDROGEN_ACCESSOR(CallKeyed) @@ -1453,9 +1385,11 @@ class LCallKnownGlobal: public LTemplateInstruction<1, 0, 0> { }; -class LCallNew: public LUnaryOperation<1> { +class LCallNew: public LTemplateInstruction<1, 1> { public: - explicit LCallNew(LOperand* constructor) : LUnaryOperation<1>(constructor) { } + explicit LCallNew(LOperand* constructor) { + inputs_[0] = constructor; + } DECLARE_CONCRETE_INSTRUCTION(CallNew, "call-new") DECLARE_HYDROGEN_ACCESSOR(CallNew) @@ -1476,90 +1410,93 @@ class LCallRuntime: public LTemplateInstruction<1, 0, 0> { }; -class LInteger32ToDouble: public LUnaryOperation<1> { +class LInteger32ToDouble: public LTemplateInstruction<1, 1> { public: - explicit LInteger32ToDouble(LOperand* use) : LUnaryOperation<1>(use) { } + explicit LInteger32ToDouble(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(Integer32ToDouble, "int32-to-double") }; -class LNumberTagI: public LUnaryOperation<1> { +class LNumberTagI: public LTemplateInstruction<1, 1> { public: - explicit LNumberTagI(LOperand* use) : LUnaryOperation<1>(use) { } + explicit LNumberTagI(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(NumberTagI, "number-tag-i") }; -class LNumberTagD: public LUnaryOperation<1> { +class LNumberTagD: public LTemplateInstruction<1, 1, 1> { public: - explicit LNumberTagD(LOperand* value, LOperand* temp) - : LUnaryOperation<1>(value), temp_(temp) { } + explicit LNumberTagD(LOperand* value, LOperand* temp) { + inputs_[0] = value; + temps_[0] = temp; + } DECLARE_CONCRETE_INSTRUCTION(NumberTagD, "number-tag-d") - - LOperand* temp() const { return temp_; } - - private: - LOperand* temp_; }; // Sometimes truncating conversion from a tagged value to an int32. -class LDoubleToI: public LUnaryOperation<1> { +class LDoubleToI: public LTemplateInstruction<1, 1, 1> { public: - LDoubleToI(LOperand* value, LOperand* temporary) - : LUnaryOperation<1>(value), temporary_(temporary) { } + LDoubleToI(LOperand* value, LOperand* temp) { + inputs_[0] = value; + temps_[0] = temp; + } DECLARE_CONCRETE_INSTRUCTION(DoubleToI, "double-to-i") DECLARE_HYDROGEN_ACCESSOR(Change) bool truncating() { return hydrogen()->CanTruncateToInt32(); } - LOperand* temporary() const { return temporary_; } - - private: - LOperand* temporary_; }; // Truncating conversion from a tagged value to an int32. -class LTaggedToI: public LUnaryOperation<1> { +class LTaggedToI: public LTemplateInstruction<1, 1, 1> { public: - LTaggedToI(LOperand* value, LOperand* temp) - : LUnaryOperation<1>(value), temp_(temp) { } + LTaggedToI(LOperand* value, LOperand* temp) { + inputs_[0] = value; + temps_[0] = temp; + } DECLARE_CONCRETE_INSTRUCTION(TaggedToI, "tagged-to-i") DECLARE_HYDROGEN_ACCESSOR(Change) bool truncating() { return hydrogen()->CanTruncateToInt32(); } - LOperand* temp() const { return temp_; } - - private: - LOperand* temp_; }; -class LSmiTag: public LUnaryOperation<1> { +class LSmiTag: public LTemplateInstruction<1, 1> { public: - explicit LSmiTag(LOperand* use) : LUnaryOperation<1>(use) { } + explicit LSmiTag(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(SmiTag, "smi-tag") }; -class LNumberUntagD: public LUnaryOperation<1> { +class LNumberUntagD: public LTemplateInstruction<1, 1> { public: - explicit LNumberUntagD(LOperand* value) : LUnaryOperation<1>(value) { } + explicit LNumberUntagD(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(NumberUntagD, "double-untag") }; -class LSmiUntag: public LUnaryOperation<1> { +class LSmiUntag: public LTemplateInstruction<1, 1> { public: - LSmiUntag(LOperand* use, bool needs_check) - : LUnaryOperation<1>(use), needs_check_(needs_check) { } + LSmiUntag(LOperand* value, bool needs_check) + : needs_check_(needs_check) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(SmiUntag, "smi-untag") @@ -1570,11 +1507,11 @@ class LSmiUntag: public LUnaryOperation<1> { }; -class LStoreNamed: public LTemplateInstruction<0, 2, 0> { +class LStoreNamed: public LTemplateInstruction<0, 2, 1> { public: LStoreNamed(LOperand* obj, LOperand* val) { - this->SetInputAt(0, obj); - this->SetInputAt(1, val); + inputs_[0] = obj; + inputs_[1] = val; } DECLARE_INSTRUCTION(StoreNamed) @@ -1582,8 +1519,8 @@ class LStoreNamed: public LTemplateInstruction<0, 2, 0> { virtual void PrintDataTo(StringStream* stream); - LOperand* object() const { return this->InputAt(0); } - LOperand* value() const { return this->InputAt(1); } + LOperand* object() { return inputs_[0]; } + LOperand* value() { return inputs_[1]; } Handle<Object> name() const { return hydrogen()->name(); } }; @@ -1591,7 +1528,9 @@ class LStoreNamed: public LTemplateInstruction<0, 2, 0> { class LStoreNamedField: public LStoreNamed { public: LStoreNamedField(LOperand* obj, LOperand* val, LOperand* temp) - : LStoreNamed(obj, val), temp_(temp) { } + : LStoreNamed(obj, val) { + temps_[0] = temp; + } DECLARE_CONCRETE_INSTRUCTION(StoreNamedField, "store-named-field") DECLARE_HYDROGEN_ACCESSOR(StoreNamedField) @@ -1600,11 +1539,6 @@ class LStoreNamedField: public LStoreNamed { int offset() { return hydrogen()->offset(); } bool needs_write_barrier() { return hydrogen()->NeedsWriteBarrier(); } Handle<Map> transition() const { return hydrogen()->transition(); } - - LOperand* temp() { return temp_; } - - private: - LOperand* temp_; }; @@ -1621,18 +1555,18 @@ class LStoreNamedGeneric: public LStoreNamed { class LStoreKeyed: public LTemplateInstruction<0, 3, 0> { public: LStoreKeyed(LOperand* obj, LOperand* key, LOperand* val) { - this->SetInputAt(0, obj); - this->SetInputAt(1, key); - this->SetInputAt(2, val); + inputs_[0] = obj; + inputs_[1] = key; + inputs_[2] = val; } DECLARE_INSTRUCTION(StoreKeyed) virtual void PrintDataTo(StringStream* stream); - LOperand* object() const { return this->InputAt(0); } - LOperand* key() const { return this->InputAt(1); } - LOperand* value() const { return this->InputAt(2); } + LOperand* object() { return inputs_[0]; } + LOperand* key() { return inputs_[1]; } + LOperand* value() { return inputs_[2]; } }; @@ -1656,60 +1590,60 @@ class LStoreKeyedGeneric: public LStoreKeyed { }; -class LCheckFunction: public LUnaryOperation<0> { +class LCheckFunction: public LTemplateInstruction<0, 1> { public: - explicit LCheckFunction(LOperand* use) : LUnaryOperation<0>(use) { } + explicit LCheckFunction(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(CheckFunction, "check-function") DECLARE_HYDROGEN_ACCESSOR(CheckFunction) }; -class LCheckInstanceType: public LUnaryOperation<0> { +class LCheckInstanceType: public LTemplateInstruction<0, 1, 1> { public: - LCheckInstanceType(LOperand* use, LOperand* temp) - : LUnaryOperation<0>(use), temp_(temp) { } + LCheckInstanceType(LOperand* value, LOperand* temp) { + inputs_[0] = value; + temps_[0] = temp; + } DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType, "check-instance-type") DECLARE_HYDROGEN_ACCESSOR(CheckInstanceType) - - LOperand* temp() const { return temp_; } - - private: - LOperand* temp_; }; -class LCheckMap: public LUnaryOperation<0> { +class LCheckMap: public LTemplateInstruction<0, 1> { public: - explicit LCheckMap(LOperand* use) : LUnaryOperation<0>(use) { } + explicit LCheckMap(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(CheckMap, "check-map") DECLARE_HYDROGEN_ACCESSOR(CheckMap) }; -class LCheckPrototypeMaps: public LTemplateInstruction<0, 0, 0> { +class LCheckPrototypeMaps: public LTemplateInstruction<0, 0, 1> { public: - explicit LCheckPrototypeMaps(LOperand* temp) : temp_(temp) { } + explicit LCheckPrototypeMaps(LOperand* temp) { + temps_[0] = temp; + } DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps, "check-prototype-maps") DECLARE_HYDROGEN_ACCESSOR(CheckPrototypeMaps) Handle<JSObject> prototype() const { return hydrogen()->prototype(); } Handle<JSObject> holder() const { return hydrogen()->holder(); } - - LOperand* temp() const { return temp_; } - - private: - LOperand* temp_; }; -class LCheckSmi: public LUnaryOperation<0> { +class LCheckSmi: public LTemplateInstruction<0, 1> { public: - LCheckSmi(LOperand* use, Condition condition) - : LUnaryOperation<0>(use), condition_(condition) { } + LCheckSmi(LOperand* value, Condition condition) + : condition_(condition) { + inputs_[0] = value; + } Condition condition() const { return condition_; } @@ -1723,27 +1657,21 @@ class LCheckSmi: public LUnaryOperation<0> { }; -class LMaterializedLiteral: public LTemplateInstruction<1, 0, 0> { - public: - DECLARE_INSTRUCTION(MaterializedLiteral) -}; - - -class LArrayLiteral: public LMaterializedLiteral { +class LArrayLiteral: public LTemplateInstruction<1, 0, 0> { public: DECLARE_CONCRETE_INSTRUCTION(ArrayLiteral, "array-literal") DECLARE_HYDROGEN_ACCESSOR(ArrayLiteral) }; -class LObjectLiteral: public LMaterializedLiteral { +class LObjectLiteral: public LTemplateInstruction<1, 0, 0> { public: DECLARE_CONCRETE_INSTRUCTION(ObjectLiteral, "object-literal") DECLARE_HYDROGEN_ACCESSOR(ObjectLiteral) }; -class LRegExpLiteral: public LMaterializedLiteral { +class LRegExpLiteral: public LTemplateInstruction<1, 0, 0> { public: DECLARE_CONCRETE_INSTRUCTION(RegExpLiteral, "regexp-literal") DECLARE_HYDROGEN_ACCESSOR(RegExpLiteral) @@ -1759,58 +1687,57 @@ class LFunctionLiteral: public LTemplateInstruction<1, 0, 0> { }; -class LTypeof: public LUnaryOperation<1> { +class LTypeof: public LTemplateInstruction<1, 1> { public: - explicit LTypeof(LOperand* input) : LUnaryOperation<1>(input) { } + explicit LTypeof(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(Typeof, "typeof") }; -class LTypeofIs: public LUnaryOperation<1> { +class LTypeofIs: public LTemplateInstruction<1, 1> { public: - explicit LTypeofIs(LOperand* input) : LUnaryOperation<1>(input) { } - virtual void PrintDataTo(StringStream* stream); + explicit LTypeofIs(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(TypeofIs, "typeof-is") DECLARE_HYDROGEN_ACCESSOR(TypeofIs) Handle<String> type_literal() { return hydrogen()->type_literal(); } + + virtual void PrintDataTo(StringStream* stream); }; -class LTypeofIsAndBranch: public LTypeofIs { +class LTypeofIsAndBranch: public LControlInstruction<1> { public: - LTypeofIsAndBranch(LOperand* value, - int true_block_id, - int false_block_id) - : LTypeofIs(value), - true_block_id_(true_block_id), - false_block_id_(false_block_id) { } + explicit LTypeofIsAndBranch(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch, "typeof-is-and-branch") + DECLARE_HYDROGEN_ACCESSOR(TypeofIs) - virtual void PrintDataTo(StringStream* stream); - virtual bool IsControl() const { return true; } - - int true_block_id() const { return true_block_id_; } - int false_block_id() const { return false_block_id_; } + Handle<String> type_literal() { return hydrogen()->type_literal(); } - private: - int true_block_id_; - int false_block_id_; + virtual void PrintDataTo(StringStream* stream); }; -class LDeleteProperty: public LBinaryOperation<1> { +class LDeleteProperty: public LTemplateInstruction<1, 2> { public: - LDeleteProperty(LOperand* obj, LOperand* key) - : LBinaryOperation<1>(obj, key) { } + LDeleteProperty(LOperand* obj, LOperand* key) { + inputs_[0] = obj; + inputs_[1] = key; + } DECLARE_CONCRETE_INSTRUCTION(DeleteProperty, "delete-property") - LOperand* object() const { return left(); } - LOperand* key() const { return right(); } + LOperand* object() { return inputs_[0]; } + LOperand* key() { return inputs_[1]; } }; @@ -1954,9 +1881,10 @@ class LChunkBuilder BASE_EMBEDDED { LUnallocated* ToUnallocated(XMMRegister reg); // Methods for setting up define-use relationships. - LOperand* Use(HValue* value, LUnallocated* operand); - LOperand* UseFixed(HValue* value, Register fixed_register); - LOperand* UseFixedDouble(HValue* value, XMMRegister fixed_register); + MUST_USE_RESULT LOperand* Use(HValue* value, LUnallocated* operand); + MUST_USE_RESULT LOperand* UseFixed(HValue* value, Register fixed_register); + MUST_USE_RESULT LOperand* UseFixedDouble(HValue* value, + XMMRegister fixed_register); // A value that is guaranteed to be allocated to a register. // Operand created by UseRegister is guaranteed to be live until the end of @@ -1966,17 +1894,32 @@ class LChunkBuilder BASE_EMBEDDED { // instruction start. Register allocator is free to assign the same register // to some other operand used inside instruction (i.e. temporary or // output). - LOperand* UseRegister(HValue* value); - LOperand* UseRegisterAtStart(HValue* value); - - // A value in a register that may be trashed. - LOperand* UseTempRegister(HValue* value); - LOperand* Use(HValue* value); - LOperand* UseAtStart(HValue* value); - LOperand* UseOrConstant(HValue* value); - LOperand* UseOrConstantAtStart(HValue* value); - LOperand* UseRegisterOrConstant(HValue* value); - LOperand* UseRegisterOrConstantAtStart(HValue* value); + MUST_USE_RESULT LOperand* UseRegister(HValue* value); + MUST_USE_RESULT LOperand* UseRegisterAtStart(HValue* value); + + // An input operand in a register that may be trashed. + MUST_USE_RESULT LOperand* UseTempRegister(HValue* value); + + // An input operand in a register or stack slot. + MUST_USE_RESULT LOperand* Use(HValue* value); + MUST_USE_RESULT LOperand* UseAtStart(HValue* value); + + // An input operand in a register, stack slot or a constant operand. + MUST_USE_RESULT LOperand* UseOrConstant(HValue* value); + MUST_USE_RESULT LOperand* UseOrConstantAtStart(HValue* value); + + // An input operand in a register or a constant operand. + MUST_USE_RESULT LOperand* UseRegisterOrConstant(HValue* value); + MUST_USE_RESULT LOperand* UseRegisterOrConstantAtStart(HValue* value); + + // An input operand in register, stack slot or a constant operand. + // Will not be moved to a register even if one is freely available. + MUST_USE_RESULT LOperand* UseAny(HValue* value); + + // Temporary operand that must be in a register. + MUST_USE_RESULT LUnallocated* TempRegister(); + MUST_USE_RESULT LOperand* FixedTemp(Register reg); + MUST_USE_RESULT LOperand* FixedTemp(XMMRegister reg); // Methods for setting up define-use relationships. // Return the same instruction that they are passed. @@ -2018,11 +1961,6 @@ class LChunkBuilder BASE_EMBEDDED { LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env); - // Temporary operand that must be in a register. - LUnallocated* TempRegister(); - LOperand* FixedTemp(Register reg); - LOperand* FixedTemp(XMMRegister reg); - void VisitInstruction(HInstruction* current); void DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block); diff --git a/deps/v8/src/ia32/stub-cache-ia32.cc b/deps/v8/src/ia32/stub-cache-ia32.cc index bcb02ed797..45d63c5a0e 100644 --- a/deps/v8/src/ia32/stub-cache-ia32.cc +++ b/deps/v8/src/ia32/stub-cache-ia32.cc @@ -1362,11 +1362,10 @@ void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell, MaybeObject* CallStubCompiler::GenerateMissBranch() { + MaybeObject* maybe_obj = StubCache::ComputeCallMiss(arguments().immediate(), + kind_); Object* obj; - { MaybeObject* maybe_obj = - StubCache::ComputeCallMiss(arguments().immediate(), kind_); - if (!maybe_obj->ToObject(&obj)) return maybe_obj; - } + if (!maybe_obj->ToObject(&obj)) return maybe_obj; __ jmp(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET); return obj; } @@ -1685,9 +1684,15 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall( const int argc = arguments().immediate(); Label miss; + Label name_miss; Label index_out_of_range; + Label* index_out_of_range_label = &index_out_of_range; - GenerateNameCheck(name, &miss); + if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) { + index_out_of_range_label = &miss; + } + + GenerateNameCheck(name, &name_miss); // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype(masm(), @@ -1715,7 +1720,7 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall( result, &miss, // When not a string. &miss, // When not a number. - &index_out_of_range, + index_out_of_range_label, STRING_INDEX_IS_NUMBER); char_code_at_generator.GenerateFast(masm()); __ ret((argc + 1) * kPointerSize); @@ -1723,11 +1728,16 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall( StubRuntimeCallHelper call_helper; char_code_at_generator.GenerateSlow(masm(), call_helper); - __ bind(&index_out_of_range); - __ Set(eax, Immediate(Factory::nan_value())); - __ ret((argc + 1) * kPointerSize); + if (index_out_of_range.is_linked()) { + __ bind(&index_out_of_range); + __ Set(eax, Immediate(Factory::nan_value())); + __ ret((argc + 1) * kPointerSize); + } __ bind(&miss); + // Restore function name in ecx. + __ Set(ecx, Immediate(Handle<String>(name))); + __ bind(&name_miss); Object* obj; { MaybeObject* maybe_obj = GenerateMissBranch(); if (!maybe_obj->ToObject(&obj)) return maybe_obj; @@ -1758,9 +1768,15 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall( const int argc = arguments().immediate(); Label miss; + Label name_miss; Label index_out_of_range; + Label* index_out_of_range_label = &index_out_of_range; - GenerateNameCheck(name, &miss); + if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) { + index_out_of_range_label = &miss; + } + + GenerateNameCheck(name, &name_miss); // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype(masm(), @@ -1790,7 +1806,7 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall( result, &miss, // When not a string. &miss, // When not a number. - &index_out_of_range, + index_out_of_range_label, STRING_INDEX_IS_NUMBER); char_at_generator.GenerateFast(masm()); __ ret((argc + 1) * kPointerSize); @@ -1798,11 +1814,16 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall( StubRuntimeCallHelper call_helper; char_at_generator.GenerateSlow(masm(), call_helper); - __ bind(&index_out_of_range); - __ Set(eax, Immediate(Factory::empty_string())); - __ ret((argc + 1) * kPointerSize); + if (index_out_of_range.is_linked()) { + __ bind(&index_out_of_range); + __ Set(eax, Immediate(Factory::empty_string())); + __ ret((argc + 1) * kPointerSize); + } __ bind(&miss); + // Restore function name in ecx. + __ Set(ecx, Immediate(Handle<String>(name))); + __ bind(&name_miss); Object* obj; { MaybeObject* maybe_obj = GenerateMissBranch(); if (!maybe_obj->ToObject(&obj)) return maybe_obj; diff --git a/deps/v8/src/ic.cc b/deps/v8/src/ic.cc index 645c6fdcf6..afae323536 100644 --- a/deps/v8/src/ic.cc +++ b/deps/v8/src/ic.cc @@ -154,24 +154,20 @@ static bool HasNormalObjectsInPrototypeChain(LookupResult* lookup, } -IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) { - IC::State state = target->ic_state(); - - if (state != MONOMORPHIC || !name->IsString()) return state; - if (receiver->IsUndefined() || receiver->IsNull()) return state; - +static bool TryRemoveInvalidPrototypeDependentStub(Code* target, + Object* receiver, + Object* name) { InlineCacheHolderFlag cache_holder = Code::ExtractCacheHolderFromFlags(target->flags()); - if (cache_holder == OWN_MAP && !receiver->IsJSObject()) { // The stub was generated for JSObject but called for non-JSObject. // IC::GetCodeCacheHolder is not applicable. - return MONOMORPHIC; + return false; } else if (cache_holder == PROTOTYPE_MAP && receiver->GetPrototype()->IsNull()) { // IC::GetCodeCacheHolder is not applicable. - return MONOMORPHIC; + return false; } Map* map = IC::GetCodeCacheHolder(receiver, cache_holder)->map(); @@ -185,20 +181,37 @@ IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) { // to prototype check failure. int index = map->IndexInCodeCache(name, target); if (index >= 0) { - // For keyed load/store/call, the most likely cause of cache failure is - // that the key has changed. We do not distinguish between - // prototype and non-prototype failures for keyed access. - Code::Kind kind = target->kind(); - if (kind == Code::KEYED_LOAD_IC || - kind == Code::KEYED_STORE_IC || - kind == Code::KEYED_CALL_IC) { - return MONOMORPHIC; - } - - // Remove the target from the code cache to avoid hitting the same - // invalid stub again. map->RemoveFromCodeCache(String::cast(name), target, index); + return true; + } + + return false; +} + + +IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) { + IC::State state = target->ic_state(); + + if (state != MONOMORPHIC || !name->IsString()) return state; + if (receiver->IsUndefined() || receiver->IsNull()) return state; + + // For keyed load/store/call, the most likely cause of cache failure is + // that the key has changed. We do not distinguish between + // prototype and non-prototype failures for keyed access. + Code::Kind kind = target->kind(); + if (kind == Code::KEYED_LOAD_IC || + kind == Code::KEYED_STORE_IC || + kind == Code::KEYED_CALL_IC) { + return MONOMORPHIC; + } + // Remove the target from the code cache if it became invalid + // because of changes in the prototype chain to avoid hitting it + // again. + // Call stubs handle this later to allow extra IC state + // transitions. + if (kind != Code::CALL_IC && + TryRemoveInvalidPrototypeDependentStub(target, receiver, name)) { return MONOMORPHIC_PROTOTYPE_FAILURE; } @@ -482,6 +495,7 @@ void CallICBase::ReceiverToObject(Handle<Object> object) { MaybeObject* CallICBase::LoadFunction(State state, + Code::ExtraICState extra_ic_state, Handle<Object> object, Handle<String> name) { // If the object is undefined or null it's illegal to try to get any @@ -527,7 +541,7 @@ MaybeObject* CallICBase::LoadFunction(State state, // Lookup is valid: Update inline cache and stub cache. if (FLAG_use_ic) { - UpdateCaches(&lookup, state, object, name); + UpdateCaches(&lookup, state, extra_ic_state, object, name); } // Get the property. @@ -576,8 +590,142 @@ MaybeObject* CallICBase::LoadFunction(State state, } +bool CallICBase::TryUpdateExtraICState(LookupResult* lookup, + Handle<Object> object, + Code::ExtraICState* extra_ic_state) { + ASSERT(kind_ == Code::CALL_IC); + if (lookup->type() != CONSTANT_FUNCTION) return false; + JSFunction* function = lookup->GetConstantFunction(); + if (!function->shared()->HasBuiltinFunctionId()) return false; + + // Fetch the arguments passed to the called function. + const int argc = target()->arguments_count(); + Address entry = Top::c_entry_fp(Top::GetCurrentThread()); + Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset); + Arguments args(argc + 1, + &Memory::Object_at(fp + + StandardFrameConstants::kCallerSPOffset + + argc * kPointerSize)); + switch (function->shared()->builtin_function_id()) { + case kStringCharCodeAt: + case kStringCharAt: + if (object->IsString()) { + String* string = String::cast(*object); + // Check that there's the right wrapper in the receiver slot. + ASSERT(string == JSValue::cast(args[0])->value()); + // If we're in the default (fastest) state and the index is + // out of bounds, update the state to record this fact. + if (*extra_ic_state == DEFAULT_STRING_STUB && + argc >= 1 && args[1]->IsNumber()) { + double index; + if (args[1]->IsSmi()) { + index = Smi::cast(args[1])->value(); + } else { + ASSERT(args[1]->IsHeapNumber()); + index = DoubleToInteger(HeapNumber::cast(args[1])->value()); + } + if (index < 0 || index >= string->length()) { + *extra_ic_state = STRING_INDEX_OUT_OF_BOUNDS; + return true; + } + } + } + break; + default: + return false; + } + return false; +} + + +MaybeObject* CallICBase::ComputeMonomorphicStub( + LookupResult* lookup, + State state, + Code::ExtraICState extra_ic_state, + Handle<Object> object, + Handle<String> name) { + int argc = target()->arguments_count(); + InLoopFlag in_loop = target()->ic_in_loop(); + MaybeObject* maybe_code = NULL; + switch (lookup->type()) { + case FIELD: { + int index = lookup->GetFieldIndex(); + maybe_code = StubCache::ComputeCallField(argc, + in_loop, + kind_, + *name, + *object, + lookup->holder(), + index); + break; + } + case CONSTANT_FUNCTION: { + // Get the constant function and compute the code stub for this + // call; used for rewriting to monomorphic state and making sure + // that the code stub is in the stub cache. + JSFunction* function = lookup->GetConstantFunction(); + maybe_code = StubCache::ComputeCallConstant(argc, + in_loop, + kind_, + extra_ic_state, + *name, + *object, + lookup->holder(), + function); + break; + } + case NORMAL: { + if (!object->IsJSObject()) return NULL; + Handle<JSObject> receiver = Handle<JSObject>::cast(object); + + if (lookup->holder()->IsGlobalObject()) { + GlobalObject* global = GlobalObject::cast(lookup->holder()); + JSGlobalPropertyCell* cell = + JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); + if (!cell->value()->IsJSFunction()) return NULL; + JSFunction* function = JSFunction::cast(cell->value()); + maybe_code = StubCache::ComputeCallGlobal(argc, + in_loop, + kind_, + *name, + *receiver, + global, + cell, + function); + } else { + // There is only one shared stub for calling normalized + // properties. It does not traverse the prototype chain, so the + // property must be found in the receiver for the stub to be + // applicable. + if (lookup->holder() != *receiver) return NULL; + maybe_code = StubCache::ComputeCallNormal(argc, + in_loop, + kind_, + *name, + *receiver); + } + break; + } + case INTERCEPTOR: { + ASSERT(HasInterceptorGetter(lookup->holder())); + maybe_code = StubCache::ComputeCallInterceptor(argc, + kind_, + *name, + *object, + lookup->holder()); + break; + } + default: + maybe_code = NULL; + break; + } + return maybe_code; +} + + void CallICBase::UpdateCaches(LookupResult* lookup, State state, + Code::ExtraICState extra_ic_state, Handle<Object> object, Handle<String> name) { // Bail out if we didn't find a result. @@ -594,90 +742,44 @@ void CallICBase::UpdateCaches(LookupResult* lookup, int argc = target()->arguments_count(); InLoopFlag in_loop = target()->ic_in_loop(); MaybeObject* maybe_code = NULL; - Object* code; + bool had_proto_failure = false; if (state == UNINITIALIZED) { // This is the first time we execute this inline cache. // Set the target to the pre monomorphic stub to delay // setting the monomorphic state. maybe_code = StubCache::ComputeCallPreMonomorphic(argc, in_loop, kind_); } else if (state == MONOMORPHIC) { - maybe_code = StubCache::ComputeCallMegamorphic(argc, in_loop, kind_); - } else { - // Compute monomorphic stub. - switch (lookup->type()) { - case FIELD: { - int index = lookup->GetFieldIndex(); - maybe_code = StubCache::ComputeCallField(argc, - in_loop, - kind_, - *name, - *object, - lookup->holder(), - index); - break; - } - case CONSTANT_FUNCTION: { - // Get the constant function and compute the code stub for this - // call; used for rewriting to monomorphic state and making sure - // that the code stub is in the stub cache. - JSFunction* function = lookup->GetConstantFunction(); - maybe_code = StubCache::ComputeCallConstant(argc, - in_loop, - kind_, - *name, - *object, - lookup->holder(), - function); - break; - } - case NORMAL: { - if (!object->IsJSObject()) return; - Handle<JSObject> receiver = Handle<JSObject>::cast(object); - - if (lookup->holder()->IsGlobalObject()) { - GlobalObject* global = GlobalObject::cast(lookup->holder()); - JSGlobalPropertyCell* cell = - JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); - if (!cell->value()->IsJSFunction()) return; - JSFunction* function = JSFunction::cast(cell->value()); - maybe_code = StubCache::ComputeCallGlobal(argc, - in_loop, - kind_, - *name, - *receiver, - global, - cell, - function); - } else { - // There is only one shared stub for calling normalized - // properties. It does not traverse the prototype chain, so the - // property must be found in the receiver for the stub to be - // applicable. - if (lookup->holder() != *receiver) return; - maybe_code = StubCache::ComputeCallNormal(argc, - in_loop, - kind_, - *name, - *receiver); - } - break; - } - case INTERCEPTOR: { - ASSERT(HasInterceptorGetter(lookup->holder())); - maybe_code = StubCache::ComputeCallInterceptor(argc, - kind_, - *name, - *object, - lookup->holder()); - break; - } - default: - return; + if (kind_ == Code::CALL_IC && + TryUpdateExtraICState(lookup, object, &extra_ic_state)) { + maybe_code = ComputeMonomorphicStub(lookup, + state, + extra_ic_state, + object, + name); + } else if (kind_ == Code::CALL_IC && + TryRemoveInvalidPrototypeDependentStub(target(), + *object, + *name)) { + had_proto_failure = true; + maybe_code = ComputeMonomorphicStub(lookup, + state, + extra_ic_state, + object, + name); + } else { + maybe_code = StubCache::ComputeCallMegamorphic(argc, in_loop, kind_); } + } else { + maybe_code = ComputeMonomorphicStub(lookup, + state, + extra_ic_state, + object, + name); } // If we're unable to compute the stub (not enough memory left), we // simply avoid updating the caches. + Object* code; if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; // Patch the call site depending on the state of the cache. @@ -696,7 +798,9 @@ void CallICBase::UpdateCaches(LookupResult* lookup, StubCache::Set(*name, map, Code::cast(code)); } + USE(had_proto_failure); #ifdef DEBUG + if (had_proto_failure) state = MONOMORPHIC_PROTOTYPE_FAILURE; TraceIC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC", name, state, target(), in_loop ? " (in-loop)" : ""); #endif @@ -707,7 +811,10 @@ MaybeObject* KeyedCallIC::LoadFunction(State state, Handle<Object> object, Handle<Object> key) { if (key->IsSymbol()) { - return CallICBase::LoadFunction(state, object, Handle<String>::cast(key)); + return CallICBase::LoadFunction(state, + Code::kNoExtraICState, + object, + Handle<String>::cast(key)); } if (object->IsUndefined() || object->IsNull()) { @@ -1641,11 +1748,13 @@ MUST_USE_RESULT MaybeObject* CallIC_Miss(Arguments args) { ASSERT(args.length() == 2); CallIC ic; IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); + Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); + MaybeObject* maybe_result = ic.LoadFunction(state, + extra_ic_state, + args.at<Object>(0), + args.at<String>(1)); Object* result; - { MaybeObject* maybe_result = - ic.LoadFunction(state, args.at<Object>(0), args.at<String>(1)); - if (!maybe_result->ToObject(&result)) return maybe_result; - } + if (!maybe_result->ToObject(&result)) return maybe_result; // The first time the inline cache is updated may be the first time the // function it references gets called. If the function was lazily compiled diff --git a/deps/v8/src/ic.h b/deps/v8/src/ic.h index 8562bcc24a..9996affa74 100644 --- a/deps/v8/src/ic.h +++ b/deps/v8/src/ic.h @@ -193,16 +193,29 @@ class CallICBase: public IC { public: MUST_USE_RESULT MaybeObject* LoadFunction(State state, + Code::ExtraICState extra_ic_state, Handle<Object> object, Handle<String> name); protected: Code::Kind kind_; + bool TryUpdateExtraICState(LookupResult* lookup, + Handle<Object> object, + Code::ExtraICState* extra_ic_state); + + MUST_USE_RESULT MaybeObject* ComputeMonomorphicStub( + LookupResult* lookup, + State state, + Code::ExtraICState extra_ic_state, + Handle<Object> object, + Handle<String> name); + // Update the inline cache and the global stub cache based on the // lookup result. void UpdateCaches(LookupResult* lookup, State state, + Code::ExtraICState extra_ic_state, Handle<Object> object, Handle<String> name); diff --git a/deps/v8/src/inspector.cc b/deps/v8/src/inspector.cc new file mode 100644 index 0000000000..8fb80f1a22 --- /dev/null +++ b/deps/v8/src/inspector.cc @@ -0,0 +1,63 @@ +// 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. + + +#include "v8.h" +#include "inspector.h" + + +namespace v8 { +namespace internal { + +#ifdef INSPECTOR + +//============================================================================ +// The Inspector. + +void Inspector::DumpObjectType(FILE* out, Object *obj, bool print_more) { + // Dump the object pointer. + OS::FPrint(out, "%p:", reinterpret_cast<void*>(obj)); + if (obj->IsHeapObject()) { + HeapObject *hobj = HeapObject::cast(obj); + OS::FPrint(out, " size %d :", hobj->Size()); + } + + // Dump each object classification that matches this object. +#define FOR_EACH_TYPE(type) \ + if (obj->Is##type()) { \ + OS::FPrint(out, " %s", #type); \ + } + OBJECT_TYPE_LIST(FOR_EACH_TYPE) + HEAP_OBJECT_TYPE_LIST(FOR_EACH_TYPE) +#undef FOR_EACH_TYPE +} + + +#endif // INSPECTOR + +} } // namespace v8::internal + diff --git a/deps/v8/src/inspector.h b/deps/v8/src/inspector.h new file mode 100644 index 0000000000..f8b3042861 --- /dev/null +++ b/deps/v8/src/inspector.h @@ -0,0 +1,62 @@ +// 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. + + +#ifndef V8_INSPECTOR_H_ +#define V8_INSPECTOR_H_ + +// Only build this code if we're configured with the INSPECTOR. +#ifdef INSPECTOR + +#include "v8.h" + +#include "objects.h" + +namespace v8 { +namespace internal { + +class Inspector { + public: + + static void DumpObjectType(FILE* out, Object *obj, bool print_more); + static void DumpObjectType(FILE* out, Object *obj) { + DumpObjectType(out, obj, false); + } + static void DumpObjectType(Object *obj, bool print_more) { + DumpObjectType(stdout, obj, print_more); + } + static void DumpObjectType(Object *obj) { + DumpObjectType(stdout, obj, false); + } +}; + +} } // namespace v8::internal + +#endif // INSPECTOR + +#endif // V8_INSPECTOR_H_ + diff --git a/deps/v8/src/lithium-allocator.cc b/deps/v8/src/lithium-allocator.cc index 29662c94a9..2bbc6b6527 100644 --- a/deps/v8/src/lithium-allocator.cc +++ b/deps/v8/src/lithium-allocator.cc @@ -745,10 +745,10 @@ void LAllocator::AddConstraintsGapMove(int index, const ZoneList<LMoveOperands>* move_operands = move->move_operands(); for (int i = 0; i < move_operands->length(); ++i) { LMoveOperands cur = move_operands->at(i); - LOperand* cur_to = cur.to(); + LOperand* cur_to = cur.destination(); if (cur_to->IsUnallocated()) { if (cur_to->VirtualRegister() == from->VirtualRegister()) { - move->AddMove(cur.from(), to); + move->AddMove(cur.source(), to); return; } } @@ -896,8 +896,8 @@ void LAllocator::ProcessInstructions(HBasicBlock* block, BitVector* live) { for (int i = 0; i < move_operands->length(); ++i) { LMoveOperands* cur = &move_operands->at(i); if (cur->IsIgnored()) continue; - LOperand* from = cur->from(); - LOperand* to = cur->to(); + LOperand* from = cur->source(); + LOperand* to = cur->destination(); HPhi* phi = LookupPhi(to); LOperand* hint = to; if (phi != NULL) { @@ -1217,9 +1217,9 @@ void LAllocator::BuildLiveRanges() { LGap* gap = GetLastGap(phi->block()->predecessors()->at(0)); LParallelMove* move = gap->GetOrCreateParallelMove(LGap::START); for (int j = 0; j < move->move_operands()->length(); ++j) { - LOperand* to = move->move_operands()->at(j).to(); + LOperand* to = move->move_operands()->at(j).destination(); if (to->IsUnallocated() && to->VirtualRegister() == phi->id()) { - hint = move->move_operands()->at(j).from(); + hint = move->move_operands()->at(j).source(); phi_operand = to; break; } diff --git a/deps/v8/src/lithium-allocator.h b/deps/v8/src/lithium-allocator.h index dfe1953df6..48c65631df 100644 --- a/deps/v8/src/lithium-allocator.h +++ b/deps/v8/src/lithium-allocator.h @@ -321,27 +321,49 @@ class LUnallocated: public LOperand { class LMoveOperands BASE_EMBEDDED { public: - LMoveOperands(LOperand* from, LOperand* to) : from_(from), to_(to) { } + LMoveOperands(LOperand* source, LOperand* destination) + : source_(source), destination_(destination) { + } + + LOperand* source() const { return source_; } + void set_source(LOperand* operand) { source_ = operand; } + + LOperand* destination() const { return destination_; } + void set_destination(LOperand* operand) { destination_ = operand; } + + // The gap resolver marks moves as "in-progress" by clearing the + // destination (but not the source). + bool IsPending() const { + return destination_ == NULL && source_ != NULL; + } - LOperand* from() const { return from_; } - LOperand* to() const { return to_; } + // True if this move a move into the given destination operand. + bool Blocks(LOperand* operand) const { + return !IsEliminated() && source()->Equals(operand); + } + + // A move is redundant if it's been eliminated, if its source and + // destination are the same, or if its destination is unneeded. bool IsRedundant() const { - return IsEliminated() || from_->Equals(to_) || IsIgnored(); + return IsEliminated() || source_->Equals(destination_) || IsIgnored(); } - bool IsEliminated() const { return from_ == NULL; } + bool IsIgnored() const { - if (to_ != NULL && to_->IsUnallocated() && - LUnallocated::cast(to_)->HasIgnorePolicy()) { - return true; - } - return false; + return destination_ != NULL && + destination_->IsUnallocated() && + LUnallocated::cast(destination_)->HasIgnorePolicy(); } - void Eliminate() { from_ = to_ = NULL; } + // We clear both operands to indicate move that's been eliminated. + void Eliminate() { source_ = destination_ = NULL; } + bool IsEliminated() const { + ASSERT(source_ != NULL || destination_ == NULL); + return source_ == NULL; + } private: - LOperand* from_; - LOperand* to_; + LOperand* source_; + LOperand* destination_; }; diff --git a/deps/v8/src/lithium.cc b/deps/v8/src/lithium.cc index e066e7da93..d6cff25653 100644 --- a/deps/v8/src/lithium.cc +++ b/deps/v8/src/lithium.cc @@ -39,18 +39,21 @@ bool LParallelMove::IsRedundant() const { void LParallelMove::PrintDataTo(StringStream* stream) const { - for (int i = move_operands_.length() - 1; i >= 0; --i) { + bool first = true; + for (int i = 0; i < move_operands_.length(); ++i) { if (!move_operands_[i].IsEliminated()) { - LOperand* from = move_operands_[i].from(); - LOperand* to = move_operands_[i].to(); - if (from->Equals(to)) { - to->PrintTo(stream); + LOperand* source = move_operands_[i].source(); + LOperand* destination = move_operands_[i].destination(); + if (!first) stream->Add(" "); + first = false; + if (source->Equals(destination)) { + destination->PrintTo(stream); } else { - to->PrintTo(stream); + destination->PrintTo(stream); stream->Add(" = "); - from->PrintTo(stream); + source->PrintTo(stream); } - stream->Add("; "); + stream->Add(";"); } } } diff --git a/deps/v8/src/lithium.h b/deps/v8/src/lithium.h index f4ae2aa2c9..5f7c92fce4 100644 --- a/deps/v8/src/lithium.h +++ b/deps/v8/src/lithium.h @@ -35,9 +35,6 @@ namespace v8 { namespace internal { -class LCodeGen; -class Translation; - class LParallelMove : public ZoneObject { public: LParallelMove() : move_operands_(4) { } diff --git a/deps/v8/src/mark-compact.cc b/deps/v8/src/mark-compact.cc index 8ade41cd2a..a946ffa23f 100644 --- a/deps/v8/src/mark-compact.cc +++ b/deps/v8/src/mark-compact.cc @@ -30,6 +30,7 @@ #include "compilation-cache.h" #include "execution.h" #include "heap-profiler.h" +#include "gdb-jit.h" #include "global-handles.h" #include "ic-inl.h" #include "mark-compact.h" @@ -125,6 +126,12 @@ void MarkCompactCollector::Prepare(GCTracer* tracer) { if (!Heap::map_space()->MapPointersEncodable()) compacting_collection_ = false; if (FLAG_collect_maps) CreateBackPointers(); +#ifdef ENABLE_GDB_JIT_INTERFACE + if (FLAG_gdbjit) { + // If GDBJIT interface is active disable compaction. + compacting_collection_ = false; + } +#endif PagedSpaces spaces; for (PagedSpace* space = spaces.next(); @@ -2906,6 +2913,11 @@ int MarkCompactCollector::RelocateNewObject(HeapObject* obj) { void MarkCompactCollector::ReportDeleteIfNeeded(HeapObject* obj) { +#ifdef ENABLE_GDB_JIT_INTERFACE + if (obj->IsCode()) { + GDBJITInterface::RemoveCode(reinterpret_cast<Code*>(obj)); + } +#endif #ifdef ENABLE_LOGGING_AND_PROFILING if (obj->IsCode()) { PROFILE(CodeDeleteEvent(obj->address())); diff --git a/deps/v8/src/objects-debug.cc b/deps/v8/src/objects-debug.cc index 7d50bfb6f6..f9c57e6960 100644 --- a/deps/v8/src/objects-debug.cc +++ b/deps/v8/src/objects-debug.cc @@ -670,16 +670,17 @@ void JSFunctionResultCache::JSFunctionResultCacheVerify() { int finger = Smi::cast(get(kFingerIndex))->value(); ASSERT(kEntriesIndex <= finger); - ASSERT(finger < size || finger == kEntriesIndex); + ASSERT((finger < size) || (finger == kEntriesIndex && finger == size)); ASSERT_EQ(0, finger % kEntrySize); if (FLAG_enable_slow_asserts) { - STATIC_ASSERT(2 == kEntrySize); - for (int i = kEntriesIndex; i < length(); i += kEntrySize) { + for (int i = kEntriesIndex; i < size; i++) { + ASSERT(!get(i)->IsTheHole()); + get(i)->Verify(); + } + for (int i = size; i < length(); i++) { + ASSERT(get(i)->IsTheHole()); get(i)->Verify(); - get(i + 1)->Verify(); - // Key and value must be either both the holes, or not. - ASSERT(get(i)->IsTheHole() == get(i + 1)->IsTheHole()); } } } diff --git a/deps/v8/src/objects-inl.h b/deps/v8/src/objects-inl.h index abfd4436df..df44674a1a 100644 --- a/deps/v8/src/objects-inl.h +++ b/deps/v8/src/objects-inl.h @@ -1978,13 +1978,13 @@ void ExternalTwoByteString::set_resource( void JSFunctionResultCache::MakeZeroSize() { - set(kFingerIndex, Smi::FromInt(kEntriesIndex)); - set(kCacheSizeIndex, Smi::FromInt(kEntriesIndex)); + set_finger_index(kEntriesIndex); + set_size(kEntriesIndex); } void JSFunctionResultCache::Clear() { - int cache_size = Smi::cast(get(kCacheSizeIndex))->value(); + int cache_size = size(); Object** entries_start = RawField(this, OffsetOfElementAt(kEntriesIndex)); MemsetPointer(entries_start, Heap::the_hole_value(), @@ -1993,6 +1993,26 @@ void JSFunctionResultCache::Clear() { } +int JSFunctionResultCache::size() { + return Smi::cast(get(kCacheSizeIndex))->value(); +} + + +void JSFunctionResultCache::set_size(int size) { + set(kCacheSizeIndex, Smi::FromInt(size)); +} + + +int JSFunctionResultCache::finger_index() { + return Smi::cast(get(kFingerIndex))->value(); +} + + +void JSFunctionResultCache::set_finger_index(int finger_index) { + set(kFingerIndex, Smi::FromInt(finger_index)); +} + + byte ByteArray::get(int index) { ASSERT(index >= 0 && index < this->length()); return READ_BYTE_FIELD(this, kHeaderSize + index * kCharSize); @@ -2396,6 +2416,12 @@ InlineCacheState Code::ic_state() { } +Code::ExtraICState Code::extra_ic_state() { + ASSERT(is_inline_cache_stub()); + return ExtractExtraICStateFromFlags(flags()); +} + + PropertyType Code::type() { ASSERT(ic_state() == MONOMORPHIC); return ExtractTypeFromFlags(flags()); @@ -2572,14 +2598,20 @@ bool Code::is_inline_cache_stub() { Code::Flags Code::ComputeFlags(Kind kind, InLoopFlag in_loop, InlineCacheState ic_state, + ExtraICState extra_ic_state, PropertyType type, int argc, InlineCacheHolderFlag holder) { + // Extra IC state is only allowed for monomorphic call IC stubs. + ASSERT(extra_ic_state == kNoExtraICState || + (kind == CALL_IC && (ic_state == MONOMORPHIC || + ic_state == MONOMORPHIC_PROTOTYPE_FAILURE))); // Compute the bit mask. int bits = kind << kFlagsKindShift; if (in_loop) bits |= kFlagsICInLoopMask; bits |= ic_state << kFlagsICStateShift; bits |= type << kFlagsTypeShift; + bits |= extra_ic_state << kFlagsExtraICStateShift; bits |= argc << kFlagsArgumentsCountShift; if (holder == PROTOTYPE_MAP) bits |= kFlagsCacheInPrototypeMapMask; // Cast to flags and validate result before returning it. @@ -2588,6 +2620,7 @@ Code::Flags Code::ComputeFlags(Kind kind, ASSERT(ExtractICStateFromFlags(result) == ic_state); ASSERT(ExtractICInLoopFromFlags(result) == in_loop); ASSERT(ExtractTypeFromFlags(result) == type); + ASSERT(ExtractExtraICStateFromFlags(result) == extra_ic_state); ASSERT(ExtractArgumentsCountFromFlags(result) == argc); return result; } @@ -2595,10 +2628,12 @@ Code::Flags Code::ComputeFlags(Kind kind, Code::Flags Code::ComputeMonomorphicFlags(Kind kind, PropertyType type, + ExtraICState extra_ic_state, InlineCacheHolderFlag holder, InLoopFlag in_loop, int argc) { - return ComputeFlags(kind, in_loop, MONOMORPHIC, type, argc, holder); + return ComputeFlags( + kind, in_loop, MONOMORPHIC, extra_ic_state, type, argc, holder); } @@ -2614,6 +2649,12 @@ InlineCacheState Code::ExtractICStateFromFlags(Flags flags) { } +Code::ExtraICState Code::ExtractExtraICStateFromFlags(Flags flags) { + int bits = (flags & kFlagsExtraICStateMask) >> kFlagsExtraICStateShift; + return static_cast<ExtraICState>(bits); +} + + InLoopFlag Code::ExtractICInLoopFromFlags(Flags flags) { int bits = (flags & kFlagsICInLoopMask); return bits != 0 ? IN_LOOP : NOT_IN_LOOP; diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h index c136dc59b5..f9cab45fb1 100644 --- a/deps/v8/src/objects.h +++ b/deps/v8/src/objects.h @@ -624,6 +624,71 @@ class MaybeObject BASE_EMBEDDED { #endif }; + +#define OBJECT_TYPE_LIST(V) \ + V(Smi) \ + V(HeapObject) \ + V(Number) \ + +#define HEAP_OBJECT_TYPE_LIST(V) \ + V(HeapNumber) \ + V(String) \ + V(Symbol) \ + V(SeqString) \ + V(ExternalString) \ + V(ConsString) \ + V(ExternalTwoByteString) \ + V(ExternalAsciiString) \ + V(SeqTwoByteString) \ + V(SeqAsciiString) \ + \ + V(PixelArray) \ + V(ExternalArray) \ + V(ExternalByteArray) \ + V(ExternalUnsignedByteArray) \ + V(ExternalShortArray) \ + V(ExternalUnsignedShortArray) \ + V(ExternalIntArray) \ + V(ExternalUnsignedIntArray) \ + V(ExternalFloatArray) \ + V(ByteArray) \ + V(JSObject) \ + V(JSContextExtensionObject) \ + V(Map) \ + V(DescriptorArray) \ + V(DeoptimizationInputData) \ + V(DeoptimizationOutputData) \ + V(FixedArray) \ + V(Context) \ + V(CatchContext) \ + V(GlobalContext) \ + V(JSFunction) \ + V(Code) \ + V(Oddball) \ + V(SharedFunctionInfo) \ + V(JSValue) \ + V(StringWrapper) \ + V(Proxy) \ + V(Boolean) \ + V(JSArray) \ + V(JSRegExp) \ + V(HashTable) \ + V(Dictionary) \ + V(SymbolTable) \ + V(JSFunctionResultCache) \ + V(NormalizedMapCache) \ + V(CompilationCacheTable) \ + V(CodeCacheHashTable) \ + V(MapCache) \ + V(Primitive) \ + V(GlobalObject) \ + V(JSGlobalObject) \ + V(JSBuiltinsObject) \ + V(JSGlobalProxy) \ + V(UndetectableObject) \ + V(AccessCheckNeeded) \ + V(JSGlobalPropertyCell) \ + // Object is the abstract superclass for all classes in the // object hierarchy. // Object does not use any virtual functions to avoid the @@ -633,67 +698,10 @@ class MaybeObject BASE_EMBEDDED { class Object : public MaybeObject { public: // Type testing. - inline bool IsSmi(); - inline bool IsHeapObject(); - inline bool IsHeapNumber(); - inline bool IsString(); - inline bool IsSymbol(); - // See objects-inl.h for more details - inline bool IsSeqString(); - inline bool IsExternalString(); - inline bool IsExternalTwoByteString(); - inline bool IsExternalAsciiString(); - inline bool IsSeqTwoByteString(); - inline bool IsSeqAsciiString(); - inline bool IsConsString(); - - inline bool IsNumber(); - inline bool IsByteArray(); - inline bool IsPixelArray(); - inline bool IsExternalArray(); - inline bool IsExternalByteArray(); - inline bool IsExternalUnsignedByteArray(); - inline bool IsExternalShortArray(); - inline bool IsExternalUnsignedShortArray(); - inline bool IsExternalIntArray(); - inline bool IsExternalUnsignedIntArray(); - inline bool IsExternalFloatArray(); - inline bool IsJSObject(); - inline bool IsJSContextExtensionObject(); - inline bool IsMap(); - inline bool IsFixedArray(); - inline bool IsDescriptorArray(); - inline bool IsDeoptimizationInputData(); - inline bool IsDeoptimizationOutputData(); - inline bool IsContext(); - inline bool IsCatchContext(); - inline bool IsGlobalContext(); - inline bool IsJSFunction(); - inline bool IsCode(); - inline bool IsOddball(); - inline bool IsSharedFunctionInfo(); - inline bool IsJSValue(); - inline bool IsStringWrapper(); - inline bool IsProxy(); - inline bool IsBoolean(); - inline bool IsJSArray(); - inline bool IsJSRegExp(); - inline bool IsHashTable(); - inline bool IsDictionary(); - inline bool IsSymbolTable(); - inline bool IsJSFunctionResultCache(); - inline bool IsNormalizedMapCache(); - inline bool IsCompilationCacheTable(); - inline bool IsCodeCacheHashTable(); - inline bool IsMapCache(); - inline bool IsPrimitive(); - inline bool IsGlobalObject(); - inline bool IsJSGlobalObject(); - inline bool IsJSBuiltinsObject(); - inline bool IsJSGlobalProxy(); - inline bool IsUndetectableObject(); - inline bool IsAccessCheckNeeded(); - inline bool IsJSGlobalPropertyCell(); +#define IS_TYPE_FUNCTION_DECL(type_) inline bool Is##type_(); + OBJECT_TYPE_LIST(IS_TYPE_FUNCTION_DECL) + HEAP_OBJECT_TYPE_LIST(IS_TYPE_FUNCTION_DECL) +#undef IS_TYPE_FUNCTION_DECL // Returns true if this object is an instance of the specified // function template. @@ -2613,6 +2621,11 @@ class JSFunctionResultCache: public FixedArray { inline void MakeZeroSize(); inline void Clear(); + inline int size(); + inline void set_size(int size); + inline int finger_index(); + inline void set_finger_index(int finger_index); + // Casting static inline JSFunctionResultCache* cast(Object* obj); @@ -3163,6 +3176,10 @@ class Code: public HeapObject { NUMBER_OF_KINDS = LAST_IC_KIND + 1 }; + typedef int ExtraICState; + + static const ExtraICState kNoExtraICState = 0; + #ifdef ENABLE_DISASSEMBLER // Printing static const char* Kind2String(Kind kind); @@ -3198,6 +3215,7 @@ class Code: public HeapObject { // [flags]: Access to specific code flags. inline Kind kind(); inline InlineCacheState ic_state(); // Only valid for IC stubs. + inline ExtraICState extra_ic_state(); // Only valid for IC stubs. inline InLoopFlag ic_in_loop(); // Only valid for IC stubs. inline PropertyType type(); // Only valid for monomorphic IC stubs. inline int arguments_count(); // Only valid for call IC stubs. @@ -3282,22 +3300,26 @@ class Code: public HeapObject { Map* FindFirstMap(); // Flags operations. - static inline Flags ComputeFlags(Kind kind, - InLoopFlag in_loop = NOT_IN_LOOP, - InlineCacheState ic_state = UNINITIALIZED, - PropertyType type = NORMAL, - int argc = -1, - InlineCacheHolderFlag holder = OWN_MAP); + static inline Flags ComputeFlags( + Kind kind, + InLoopFlag in_loop = NOT_IN_LOOP, + InlineCacheState ic_state = UNINITIALIZED, + ExtraICState extra_ic_state = kNoExtraICState, + PropertyType type = NORMAL, + int argc = -1, + InlineCacheHolderFlag holder = OWN_MAP); static inline Flags ComputeMonomorphicFlags( Kind kind, PropertyType type, + ExtraICState extra_ic_state = kNoExtraICState, InlineCacheHolderFlag holder = OWN_MAP, InLoopFlag in_loop = NOT_IN_LOOP, int argc = -1); static inline Kind ExtractKindFromFlags(Flags flags); static inline InlineCacheState ExtractICStateFromFlags(Flags flags); + static inline ExtraICState ExtractExtraICStateFromFlags(Flags flags); static inline InLoopFlag ExtractICInLoopFromFlags(Flags flags); static inline PropertyType ExtractTypeFromFlags(Flags flags); static inline int ExtractArgumentsCountFromFlags(Flags flags); @@ -3418,14 +3440,16 @@ class Code: public HeapObject { static const int kFlagsTypeShift = 4; static const int kFlagsKindShift = 7; static const int kFlagsICHolderShift = 11; - static const int kFlagsArgumentsCountShift = 12; + static const int kFlagsExtraICStateShift = 12; + static const int kFlagsArgumentsCountShift = 14; static const int kFlagsICStateMask = 0x00000007; // 00000000111 static const int kFlagsICInLoopMask = 0x00000008; // 00000001000 static const int kFlagsTypeMask = 0x00000070; // 00001110000 static const int kFlagsKindMask = 0x00000780; // 11110000000 static const int kFlagsCacheInPrototypeMapMask = 0x00000800; - static const int kFlagsArgumentsCountMask = 0xFFFFF000; + static const int kFlagsExtraICStateMask = 0x00003000; + static const int kFlagsArgumentsCountMask = 0xFFFFC000; static const int kFlagsNotUsedInLookup = (kFlagsICInLoopMask | kFlagsTypeMask | kFlagsCacheInPrototypeMapMask); diff --git a/deps/v8/src/platform-win32.cc b/deps/v8/src/platform-win32.cc index a97785e4c3..bf1737a54b 100644 --- a/deps/v8/src/platform-win32.cc +++ b/deps/v8/src/platform-win32.cc @@ -1474,7 +1474,7 @@ Thread::Thread(const char* name) : ThreadHandle(ThreadHandle::INVALID) { void Thread::set_name(const char* name) { - strncpy_s(name_, sizeof(name_), name, strlen(name)); + OS::StrNCpy(Vector<char>(name_, sizeof(name_)), name, strlen(name)); name_[sizeof(name_) - 1] = '\0'; } diff --git a/deps/v8/src/preparse-data.h b/deps/v8/src/preparse-data.h index cc82bcc62c..bb5707b61d 100644 --- a/deps/v8/src/preparse-data.h +++ b/deps/v8/src/preparse-data.h @@ -39,7 +39,7 @@ class PreparseDataConstants : public AllStatic { public: // Layout and constants of the preparse data exchange format. static const unsigned kMagicNumber = 0xBadDead; - static const unsigned kCurrentVersion = 5; + static const unsigned kCurrentVersion = 6; static const int kMagicOffset = 0; static const int kVersionOffset = 1; diff --git a/deps/v8/src/runtime-profiler.cc b/deps/v8/src/runtime-profiler.cc index 1efc6ef620..d7792aceae 100644 --- a/deps/v8/src/runtime-profiler.cc +++ b/deps/v8/src/runtime-profiler.cc @@ -134,6 +134,7 @@ void PendingListNode::WeakCallback(v8::Persistent<v8::Value>, void* data) { static bool IsOptimizable(JSFunction* function) { + if (Heap::InNewSpace(function)) return false; Code* code = function->code(); return code->kind() == Code::FUNCTION && code->optimizable(); } diff --git a/deps/v8/src/runtime.cc b/deps/v8/src/runtime.cc index 0cde7779a3..2f1f54c696 100644 --- a/deps/v8/src/runtime.cc +++ b/deps/v8/src/runtime.cc @@ -10654,51 +10654,12 @@ static MaybeObject* Runtime_Abort(Arguments args) { } -MUST_USE_RESULT static MaybeObject* CacheMiss(FixedArray* cache_obj, - int index, - Object* key_obj) { - ASSERT(index % 2 == 0); // index of the key - ASSERT(index >= JSFunctionResultCache::kEntriesIndex); - ASSERT(index < cache_obj->length()); - - HandleScope scope; - - Handle<FixedArray> cache(cache_obj); - Handle<Object> key(key_obj); - Handle<JSFunction> factory(JSFunction::cast( - cache->get(JSFunctionResultCache::kFactoryIndex))); - // TODO(antonm): consider passing a receiver when constructing a cache. - Handle<Object> receiver(Top::global_context()->global()); - - Handle<Object> value; - { - // This handle is nor shared, nor used later, so it's safe. - Object** argv[] = { key.location() }; - bool pending_exception = false; - value = Execution::Call(factory, - receiver, - 1, - argv, - &pending_exception); - if (pending_exception) return Failure::Exception(); - } - - cache->set(index, *key); - cache->set(index + 1, *value); - cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(index)); - - return *value; -} - - static MaybeObject* Runtime_GetFromCache(Arguments args) { // This is only called from codegen, so checks might be more lax. - CONVERT_CHECKED(FixedArray, cache, args[0]); + CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]); Object* key = args[1]; - const int finger_index = - Smi::cast(cache->get(JSFunctionResultCache::kFingerIndex))->value(); - + int finger_index = cache->finger_index(); Object* o = cache->get(finger_index); if (o == key) { // The fastest case: hit the same place again. @@ -10710,35 +10671,78 @@ static MaybeObject* Runtime_GetFromCache(Arguments args) { i -= 2) { o = cache->get(i); if (o == key) { - cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(i)); + cache->set_finger_index(i); return cache->get(i + 1); } } - const int size = - Smi::cast(cache->get(JSFunctionResultCache::kCacheSizeIndex))->value(); + int size = cache->size(); ASSERT(size <= cache->length()); for (int i = size - 2; i > finger_index; i -= 2) { o = cache->get(i); if (o == key) { - cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(i)); + cache->set_finger_index(i); return cache->get(i + 1); } } - // Cache miss. If we have spare room, put new data into it, otherwise - // evict post finger entry which must be least recently used. - if (size < cache->length()) { - cache->set(JSFunctionResultCache::kCacheSizeIndex, Smi::FromInt(size + 2)); - return CacheMiss(cache, size, key); + // There is no value in the cache. Invoke the function and cache result. + HandleScope scope; + + Handle<JSFunctionResultCache> cache_handle(cache); + Handle<Object> key_handle(key); + Handle<Object> value; + { + Handle<JSFunction> factory(JSFunction::cast( + cache_handle->get(JSFunctionResultCache::kFactoryIndex))); + // TODO(antonm): consider passing a receiver when constructing a cache. + Handle<Object> receiver(Top::global_context()->global()); + // This handle is nor shared, nor used later, so it's safe. + Object** argv[] = { key_handle.location() }; + bool pending_exception = false; + value = Execution::Call(factory, + receiver, + 1, + argv, + &pending_exception); + if (pending_exception) return Failure::Exception(); + } + +#ifdef DEBUG + cache_handle->JSFunctionResultCacheVerify(); +#endif + + // Function invocation may have cleared the cache. Reread all the data. + finger_index = cache_handle->finger_index(); + size = cache_handle->size(); + + // If we have spare room, put new data into it, otherwise evict post finger + // entry which is likely to be the least recently used. + int index = -1; + if (size < cache_handle->length()) { + cache_handle->set_size(size + JSFunctionResultCache::kEntrySize); + index = size; } else { - int target_index = finger_index + JSFunctionResultCache::kEntrySize; - if (target_index == cache->length()) { - target_index = JSFunctionResultCache::kEntriesIndex; + index = finger_index + JSFunctionResultCache::kEntrySize; + if (index == cache_handle->length()) { + index = JSFunctionResultCache::kEntriesIndex; } - return CacheMiss(cache, target_index, key); } + + ASSERT(index % 2 == 0); + ASSERT(index >= JSFunctionResultCache::kEntriesIndex); + ASSERT(index < cache_handle->length()); + + cache_handle->set(index, *key_handle); + cache_handle->set(index + 1, *value); + cache_handle->set_finger_index(index); + +#ifdef DEBUG + cache_handle->JSFunctionResultCacheVerify(); +#endif + + return *value; } #ifdef DEBUG diff --git a/deps/v8/src/scopeinfo.cc b/deps/v8/src/scopeinfo.cc index e054d7de54..e06235af76 100644 --- a/deps/v8/src/scopeinfo.cc +++ b/deps/v8/src/scopeinfo.cc @@ -152,19 +152,18 @@ ScopeInfo<Allocator>::ScopeInfo(Scope* scope) // // - function name // +// - calls eval boolean flag +// // - number of variables in the context object (smi) (= function context // slot index + 1) // - list of pairs (name, Var mode) of context-allocated variables (starting // with context slot 0) -// - NULL (sentinel) // // - number of parameters (smi) // - list of parameter names (starting with parameter 0 first) -// - NULL (sentinel) // // - number of variables on the stack (smi) // - list of names of stack-allocated variables (starting with stack slot 0) -// - NULL (sentinel) // The ScopeInfo representation could be simplified and the ScopeInfo // re-implemented (with almost the same interface). Here is a diff --git a/deps/v8/src/scopes.cc b/deps/v8/src/scopes.cc index 58a10ee346..d3f54ad3f2 100644 --- a/deps/v8/src/scopes.cc +++ b/deps/v8/src/scopes.cc @@ -154,6 +154,24 @@ Scope::Scope(Scope* inner_scope, SerializedScopeInfo* scope_info) if (scope_info->HasHeapAllocatedLocals()) { num_heap_slots_ = scope_info_->NumberOfContextSlots(); } + + // This scope's arguments shadow (if present) is context-allocated if an inner + // scope accesses this one's parameters. Allocate the arguments_shadow_ + // variable if necessary. + Variable::Mode mode; + int arguments_shadow_index = + scope_info_->ContextSlotIndex(Heap::arguments_shadow_symbol(), &mode); + if (arguments_shadow_index >= 0) { + ASSERT(mode == Variable::INTERNAL); + arguments_shadow_ = new Variable(this, + Factory::arguments_shadow_symbol(), + Variable::INTERNAL, + true, + Variable::ARGUMENTS); + arguments_shadow_->set_rewrite( + new Slot(arguments_shadow_, Slot::CONTEXT, arguments_shadow_index)); + arguments_shadow_->set_is_used(true); + } } @@ -239,21 +257,49 @@ Variable* Scope::LocalLookup(Handle<String> name) { // If the scope is resolved, we can find a variable in serialized scope info. // We should never lookup 'arguments' in this scope - // as it is impllicitly present in any scope. + // as it is implicitly present in any scope. ASSERT(*name != *Factory::arguments_symbol()); + // Assert that there is no local slot with the given name. + ASSERT(scope_info_->StackSlotIndex(*name) < 0); + // Check context slot lookup. Variable::Mode mode; int index = scope_info_->ContextSlotIndex(*name, &mode); - if (index < 0) { - return NULL; + if (index >= 0) { + Variable* var = + variables_.Declare(this, name, mode, true, Variable::NORMAL); + var->set_rewrite(new Slot(var, Slot::CONTEXT, index)); + return var; } - // Check that there is no local slot with the given name. - ASSERT(scope_info_->StackSlotIndex(*name) < 0); - Variable* var = variables_.Declare(this, name, mode, true, Variable::NORMAL); - var->set_rewrite(new Slot(var, Slot::CONTEXT, index)); - return var; + index = scope_info_->ParameterIndex(*name); + if (index >= 0) { + // ".arguments" must be present in context slots. + ASSERT(arguments_shadow_ != NULL); + Variable* var = + variables_.Declare(this, name, Variable::VAR, true, Variable::NORMAL); + Property* rewrite = + new Property(new VariableProxy(arguments_shadow_), + new Literal(Handle<Object>(Smi::FromInt(index))), + RelocInfo::kNoPosition, + Property::SYNTHETIC); + rewrite->set_is_arguments_access(true); + var->set_rewrite(rewrite); + return var; + } + + index = scope_info_->FunctionContextSlotIndex(*name); + if (index >= 0) { + // Check that there is no local slot with the given name. + ASSERT(scope_info_->StackSlotIndex(*name) < 0); + Variable* var = + variables_.Declare(this, name, Variable::VAR, true, Variable::NORMAL); + var->set_rewrite(new Slot(var, Slot::CONTEXT, index)); + return var; + } + + return NULL; } diff --git a/deps/v8/src/stub-cache.cc b/deps/v8/src/stub-cache.cc index 86e7201213..295cc4a60b 100644 --- a/deps/v8/src/stub-cache.cc +++ b/deps/v8/src/stub-cache.cc @@ -29,6 +29,7 @@ #include "api.h" #include "arguments.h" +#include "gdb-jit.h" #include "ic-inl.h" #include "stub-cache.h" #include "vm-state-inl.h" @@ -122,6 +123,7 @@ MaybeObject* StubCache::ComputeLoadNonexistent(String* name, if (!maybe_code->ToObject(&code)) return maybe_code; } PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), cache_name)); + GDBJIT(AddCode(GDBJITInterface::LOAD_IC, cache_name, Code::cast(code))); Object* result; { MaybeObject* maybe_result = receiver->UpdateMapCodeCache(cache_name, Code::cast(code)); @@ -146,6 +148,7 @@ MaybeObject* StubCache::ComputeLoadField(String* name, if (!maybe_code->ToObject(&code)) return maybe_code; } PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name)); + GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code))); Object* result; { MaybeObject* maybe_result = receiver->UpdateMapCodeCache(name, Code::cast(code)); @@ -171,6 +174,7 @@ MaybeObject* StubCache::ComputeLoadCallback(String* name, if (!maybe_code->ToObject(&code)) return maybe_code; } PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name)); + GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code))); Object* result; { MaybeObject* maybe_result = receiver->UpdateMapCodeCache(name, Code::cast(code)); @@ -196,6 +200,7 @@ MaybeObject* StubCache::ComputeLoadConstant(String* name, if (!maybe_code->ToObject(&code)) return maybe_code; } PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name)); + GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code))); Object* result; { MaybeObject* maybe_result = receiver->UpdateMapCodeCache(name, Code::cast(code)); @@ -219,6 +224,7 @@ MaybeObject* StubCache::ComputeLoadInterceptor(String* name, if (!maybe_code->ToObject(&code)) return maybe_code; } PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name)); + GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code))); Object* result; { MaybeObject* maybe_result = receiver->UpdateMapCodeCache(name, Code::cast(code)); @@ -252,6 +258,7 @@ MaybeObject* StubCache::ComputeLoadGlobal(String* name, if (!maybe_code->ToObject(&code)) return maybe_code; } PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name)); + GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code))); Object* result; { MaybeObject* maybe_result = receiver->UpdateMapCodeCache(name, Code::cast(code)); @@ -276,6 +283,7 @@ MaybeObject* StubCache::ComputeKeyedLoadField(String* name, if (!maybe_code->ToObject(&code)) return maybe_code; } PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name)); + GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code))); Object* result; { MaybeObject* maybe_result = receiver->UpdateMapCodeCache(name, Code::cast(code)); @@ -301,6 +309,7 @@ MaybeObject* StubCache::ComputeKeyedLoadConstant(String* name, if (!maybe_code->ToObject(&code)) return maybe_code; } PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name)); + GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code))); Object* result; { MaybeObject* maybe_result = receiver->UpdateMapCodeCache(name, Code::cast(code)); @@ -325,6 +334,7 @@ MaybeObject* StubCache::ComputeKeyedLoadInterceptor(String* name, if (!maybe_code->ToObject(&code)) return maybe_code; } PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name)); + GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code))); Object* result; { MaybeObject* maybe_result = receiver->UpdateMapCodeCache(name, Code::cast(code)); @@ -350,6 +360,7 @@ MaybeObject* StubCache::ComputeKeyedLoadCallback(String* name, if (!maybe_code->ToObject(&code)) return maybe_code; } PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name)); + GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code))); Object* result; { MaybeObject* maybe_result = receiver->UpdateMapCodeCache(name, Code::cast(code)); @@ -373,6 +384,7 @@ MaybeObject* StubCache::ComputeKeyedLoadArrayLength(String* name, if (!maybe_code->ToObject(&code)) return maybe_code; } PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name)); + GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code))); Object* result; { MaybeObject* maybe_result = receiver->UpdateMapCodeCache(name, Code::cast(code)); @@ -395,6 +407,7 @@ MaybeObject* StubCache::ComputeKeyedLoadStringLength(String* name, if (!maybe_code->ToObject(&code)) return maybe_code; } PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name)); + GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code))); Object* result; { MaybeObject* maybe_result = map->UpdateCodeCache(name, Code::cast(code)); if (!maybe_result->ToObject(&result)) return maybe_result; @@ -416,6 +429,7 @@ MaybeObject* StubCache::ComputeKeyedLoadFunctionPrototype( if (!maybe_code->ToObject(&code)) return maybe_code; } PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name)); + GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code))); Object* result; { MaybeObject* maybe_result = receiver->UpdateMapCodeCache(name, Code::cast(code)); @@ -461,6 +475,7 @@ MaybeObject* StubCache::ComputeStoreField(String* name, if (!maybe_code->ToObject(&code)) return maybe_code; } PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name)); + GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code))); Object* result; { MaybeObject* maybe_result = receiver->UpdateMapCodeCache(name, Code::cast(code)); @@ -509,6 +524,7 @@ MaybeObject* StubCache::ComputeStoreGlobal(String* name, if (!maybe_code->ToObject(&code)) return maybe_code; } PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name)); + GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code))); Object* result; { MaybeObject* maybe_result = receiver->UpdateMapCodeCache(name, Code::cast(code)); @@ -532,6 +548,7 @@ MaybeObject* StubCache::ComputeStoreCallback(String* name, if (!maybe_code->ToObject(&code)) return maybe_code; } PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name)); + GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code))); Object* result; { MaybeObject* maybe_result = receiver->UpdateMapCodeCache(name, Code::cast(code)); @@ -554,6 +571,7 @@ MaybeObject* StubCache::ComputeStoreInterceptor(String* name, if (!maybe_code->ToObject(&code)) return maybe_code; } PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name)); + GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code))); Object* result; { MaybeObject* maybe_result = receiver->UpdateMapCodeCache(name, Code::cast(code)); @@ -579,6 +597,7 @@ MaybeObject* StubCache::ComputeKeyedStoreField(String* name, } PROFILE(CodeCreateEvent( Logger::KEYED_STORE_IC_TAG, Code::cast(code), name)); + GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC, name, Code::cast(code))); Object* result; { MaybeObject* maybe_result = receiver->UpdateMapCodeCache(name, Code::cast(code)); @@ -594,6 +613,7 @@ MaybeObject* StubCache::ComputeKeyedStoreField(String* name, MaybeObject* StubCache::ComputeCallConstant(int argc, InLoopFlag in_loop, Code::Kind kind, + Code::ExtraICState extra_ic_state, String* name, Object* object, JSObject* holder, @@ -613,12 +633,12 @@ MaybeObject* StubCache::ComputeCallConstant(int argc, check = BOOLEAN_CHECK; } - Code::Flags flags = - Code::ComputeMonomorphicFlags(kind, - CONSTANT_FUNCTION, - cache_holder, - in_loop, - argc); + Code::Flags flags = Code::ComputeMonomorphicFlags(kind, + CONSTANT_FUNCTION, + extra_ic_state, + cache_holder, + in_loop, + argc); Object* code = map_holder->map()->FindInCodeCache(name, flags); if (code->IsUndefined()) { // If the function hasn't been compiled yet, we cannot do it now @@ -627,7 +647,8 @@ MaybeObject* StubCache::ComputeCallConstant(int argc, // caches. if (!function->is_compiled()) return Failure::InternalError(); // Compile the stub - only create stubs for fully compiled functions. - CallStubCompiler compiler(argc, in_loop, kind, cache_holder); + CallStubCompiler compiler( + argc, in_loop, kind, extra_ic_state, cache_holder); { MaybeObject* maybe_code = compiler.CompileCallConstant(object, holder, function, name, check); if (!maybe_code->ToObject(&code)) return maybe_code; @@ -636,6 +657,7 @@ MaybeObject* StubCache::ComputeCallConstant(int argc, ASSERT_EQ(flags, Code::cast(code)->flags()); PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), Code::cast(code), name)); + GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code))); Object* result; { MaybeObject* maybe_result = map_holder->UpdateMapCodeCache(name, Code::cast(code)); @@ -667,12 +689,14 @@ MaybeObject* StubCache::ComputeCallField(int argc, Code::Flags flags = Code::ComputeMonomorphicFlags(kind, FIELD, + Code::kNoExtraICState, cache_holder, in_loop, argc); Object* code = map_holder->map()->FindInCodeCache(name, flags); if (code->IsUndefined()) { - CallStubCompiler compiler(argc, in_loop, kind, cache_holder); + CallStubCompiler compiler( + argc, in_loop, kind, Code::kNoExtraICState, cache_holder); { MaybeObject* maybe_code = compiler.CompileCallField(JSObject::cast(object), holder, @@ -683,6 +707,7 @@ MaybeObject* StubCache::ComputeCallField(int argc, ASSERT_EQ(flags, Code::cast(code)->flags()); PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), Code::cast(code), name)); + GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code))); Object* result; { MaybeObject* maybe_result = map_holder->UpdateMapCodeCache(name, Code::cast(code)); @@ -710,15 +735,16 @@ MaybeObject* StubCache::ComputeCallInterceptor(int argc, object = holder; } - Code::Flags flags = - Code::ComputeMonomorphicFlags(kind, - INTERCEPTOR, - cache_holder, - NOT_IN_LOOP, - argc); + Code::Flags flags = Code::ComputeMonomorphicFlags(kind, + INTERCEPTOR, + Code::kNoExtraICState, + cache_holder, + NOT_IN_LOOP, + argc); Object* code = map_holder->map()->FindInCodeCache(name, flags); if (code->IsUndefined()) { - CallStubCompiler compiler(argc, NOT_IN_LOOP, kind, cache_holder); + CallStubCompiler compiler( + argc, NOT_IN_LOOP, kind, Code::kNoExtraICState, cache_holder); { MaybeObject* maybe_code = compiler.CompileCallInterceptor(JSObject::cast(object), holder, name); if (!maybe_code->ToObject(&code)) return maybe_code; @@ -726,6 +752,7 @@ MaybeObject* StubCache::ComputeCallInterceptor(int argc, ASSERT_EQ(flags, Code::cast(code)->flags()); PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), Code::cast(code), name)); + GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code))); Object* result; { MaybeObject* maybe_result = map_holder->UpdateMapCodeCache(name, Code::cast(code)); @@ -760,12 +787,12 @@ MaybeObject* StubCache::ComputeCallGlobal(int argc, InlineCacheHolderFlag cache_holder = IC::GetCodeCacheForObject(receiver, holder); JSObject* map_holder = IC::GetCodeCacheHolder(receiver, cache_holder); - Code::Flags flags = - Code::ComputeMonomorphicFlags(kind, - NORMAL, - cache_holder, - in_loop, - argc); + Code::Flags flags = Code::ComputeMonomorphicFlags(kind, + NORMAL, + Code::kNoExtraICState, + cache_holder, + in_loop, + argc); Object* code = map_holder->map()->FindInCodeCache(name, flags); if (code->IsUndefined()) { // If the function hasn't been compiled yet, we cannot do it now @@ -773,7 +800,8 @@ MaybeObject* StubCache::ComputeCallGlobal(int argc, // internal error which will make sure we do not update any // caches. if (!function->is_compiled()) return Failure::InternalError(); - CallStubCompiler compiler(argc, in_loop, kind, cache_holder); + CallStubCompiler compiler( + argc, in_loop, kind, Code::kNoExtraICState, cache_holder); { MaybeObject* maybe_code = compiler.CompileCallGlobal(receiver, holder, cell, function, name); if (!maybe_code->ToObject(&code)) return maybe_code; @@ -781,6 +809,7 @@ MaybeObject* StubCache::ComputeCallGlobal(int argc, ASSERT_EQ(flags, Code::cast(code)->flags()); PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), Code::cast(code), name)); + GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code))); Object* result; { MaybeObject* maybe_result = map_holder->UpdateMapCodeCache(name, Code::cast(code)); @@ -839,8 +868,12 @@ static MaybeObject* FillCache(MaybeObject* maybe_code) { Code* StubCache::FindCallInitialize(int argc, InLoopFlag in_loop, Code::Kind kind) { - Code::Flags flags = - Code::ComputeFlags(kind, in_loop, UNINITIALIZED, NORMAL, argc); + Code::Flags flags = Code::ComputeFlags(kind, + in_loop, + UNINITIALIZED, + Code::kNoExtraICState, + NORMAL, + argc); Object* result = ProbeCache(flags)->ToObjectUnchecked(); ASSERT(!result->IsUndefined()); // This might be called during the marking phase of the collector @@ -852,8 +885,12 @@ Code* StubCache::FindCallInitialize(int argc, MaybeObject* StubCache::ComputeCallInitialize(int argc, InLoopFlag in_loop, Code::Kind kind) { - Code::Flags flags = - Code::ComputeFlags(kind, in_loop, UNINITIALIZED, NORMAL, argc); + Code::Flags flags = Code::ComputeFlags(kind, + in_loop, + UNINITIALIZED, + Code::kNoExtraICState, + NORMAL, + argc); Object* probe; { MaybeObject* maybe_probe = ProbeCache(flags); if (!maybe_probe->ToObject(&probe)) return maybe_probe; @@ -895,8 +932,12 @@ Handle<Code> StubCache::ComputeKeyedCallInitialize(int argc, MaybeObject* StubCache::ComputeCallPreMonomorphic(int argc, InLoopFlag in_loop, Code::Kind kind) { - Code::Flags flags = - Code::ComputeFlags(kind, in_loop, PREMONOMORPHIC, NORMAL, argc); + Code::Flags flags = Code::ComputeFlags(kind, + in_loop, + PREMONOMORPHIC, + Code::kNoExtraICState, + NORMAL, + argc); Object* probe; { MaybeObject* maybe_probe = ProbeCache(flags); if (!maybe_probe->ToObject(&probe)) return maybe_probe; @@ -910,8 +951,12 @@ MaybeObject* StubCache::ComputeCallPreMonomorphic(int argc, MaybeObject* StubCache::ComputeCallNormal(int argc, InLoopFlag in_loop, Code::Kind kind) { - Code::Flags flags = - Code::ComputeFlags(kind, in_loop, MONOMORPHIC, NORMAL, argc); + Code::Flags flags = Code::ComputeFlags(kind, + in_loop, + MONOMORPHIC, + Code::kNoExtraICState, + NORMAL, + argc); Object* probe; { MaybeObject* maybe_probe = ProbeCache(flags); if (!maybe_probe->ToObject(&probe)) return maybe_probe; @@ -925,8 +970,12 @@ MaybeObject* StubCache::ComputeCallNormal(int argc, MaybeObject* StubCache::ComputeCallMegamorphic(int argc, InLoopFlag in_loop, Code::Kind kind) { - Code::Flags flags = - Code::ComputeFlags(kind, in_loop, MEGAMORPHIC, NORMAL, argc); + Code::Flags flags = Code::ComputeFlags(kind, + in_loop, + MEGAMORPHIC, + Code::kNoExtraICState, + NORMAL, + argc); Object* probe; { MaybeObject* maybe_probe = ProbeCache(flags); if (!maybe_probe->ToObject(&probe)) return maybe_probe; @@ -940,8 +989,13 @@ MaybeObject* StubCache::ComputeCallMegamorphic(int argc, MaybeObject* StubCache::ComputeCallMiss(int argc, Code::Kind kind) { // MONOMORPHIC_PROTOTYPE_FAILURE state is used to make sure that miss stubs // and monomorphic stubs are not mixed up together in the stub cache. - Code::Flags flags = Code::ComputeFlags( - kind, NOT_IN_LOOP, MONOMORPHIC_PROTOTYPE_FAILURE, NORMAL, argc); + Code::Flags flags = Code::ComputeFlags(kind, + NOT_IN_LOOP, + MONOMORPHIC_PROTOTYPE_FAILURE, + Code::kNoExtraICState, + NORMAL, + argc, + OWN_MAP); Object* probe; { MaybeObject* maybe_probe = ProbeCache(flags); if (!maybe_probe->ToObject(&probe)) return maybe_probe; @@ -954,8 +1008,12 @@ MaybeObject* StubCache::ComputeCallMiss(int argc, Code::Kind kind) { #ifdef ENABLE_DEBUGGER_SUPPORT MaybeObject* StubCache::ComputeCallDebugBreak(int argc, Code::Kind kind) { - Code::Flags flags = - Code::ComputeFlags(kind, NOT_IN_LOOP, DEBUG_BREAK, NORMAL, argc); + Code::Flags flags = Code::ComputeFlags(kind, + NOT_IN_LOOP, + DEBUG_BREAK, + Code::kNoExtraICState, + NORMAL, + argc); Object* probe; { MaybeObject* maybe_probe = ProbeCache(flags); if (!maybe_probe->ToObject(&probe)) return maybe_probe; @@ -968,12 +1026,12 @@ MaybeObject* StubCache::ComputeCallDebugBreak(int argc, Code::Kind kind) { MaybeObject* StubCache::ComputeCallDebugPrepareStepIn(int argc, Code::Kind kind) { - Code::Flags flags = - Code::ComputeFlags(kind, - NOT_IN_LOOP, - DEBUG_PREPARE_STEP_IN, - NORMAL, - argc); + Code::Flags flags = Code::ComputeFlags(kind, + NOT_IN_LOOP, + DEBUG_PREPARE_STEP_IN, + Code::kNoExtraICState, + NORMAL, + argc); Object* probe; { MaybeObject* maybe_probe = ProbeCache(flags); if (!maybe_probe->ToObject(&probe)) return maybe_probe; @@ -1257,6 +1315,7 @@ MaybeObject* StubCompiler::CompileCallInitialize(Code::Flags flags) { USE(code); PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_INITIALIZE_TAG), code, code->arguments_count())); + GDBJIT(AddCode(GDBJITInterface::CALL_INITIALIZE, Code::cast(code))); return result; } @@ -1282,6 +1341,7 @@ MaybeObject* StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) { USE(code); PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_PRE_MONOMORPHIC_TAG), code, code->arguments_count())); + GDBJIT(AddCode(GDBJITInterface::CALL_PRE_MONOMORPHIC, Code::cast(code))); return result; } @@ -1304,6 +1364,7 @@ MaybeObject* StubCompiler::CompileCallNormal(Code::Flags flags) { USE(code); PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_NORMAL_TAG), code, code->arguments_count())); + GDBJIT(AddCode(GDBJITInterface::CALL_NORMAL, Code::cast(code))); return result; } @@ -1328,6 +1389,7 @@ MaybeObject* StubCompiler::CompileCallMegamorphic(Code::Flags flags) { USE(code); PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MEGAMORPHIC_TAG), code, code->arguments_count())); + GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, Code::cast(code))); return result; } @@ -1350,6 +1412,7 @@ MaybeObject* StubCompiler::CompileCallMiss(Code::Flags flags) { USE(code); PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MISS_TAG), code, code->arguments_count())); + GDBJIT(AddCode(GDBJITInterface::CALL_MISS, Code::cast(code))); return result; } @@ -1449,6 +1512,9 @@ MaybeObject* LoadStubCompiler::GetCode(PropertyType type, String* name) { PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(result->ToObjectUnchecked()), name)); + GDBJIT(AddCode(GDBJITInterface::LOAD_IC, + name, + Code::cast(result->ToObjectUnchecked()))); } return result; } @@ -1461,6 +1527,9 @@ MaybeObject* KeyedLoadStubCompiler::GetCode(PropertyType type, String* name) { PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(result->ToObjectUnchecked()), name)); + GDBJIT(AddCode(GDBJITInterface::LOAD_IC, + name, + Code::cast(result->ToObjectUnchecked()))); } return result; } @@ -1473,6 +1542,9 @@ MaybeObject* StoreStubCompiler::GetCode(PropertyType type, String* name) { PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(result->ToObjectUnchecked()), name)); + GDBJIT(AddCode(GDBJITInterface::STORE_IC, + name, + Code::cast(result->ToObjectUnchecked()))); } return result; } @@ -1485,6 +1557,9 @@ MaybeObject* KeyedStoreStubCompiler::GetCode(PropertyType type, String* name) { PROFILE(CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, Code::cast(result->ToObjectUnchecked()), name)); + GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC, + name, + Code::cast(result->ToObjectUnchecked()))); } return result; } @@ -1493,11 +1568,13 @@ MaybeObject* KeyedStoreStubCompiler::GetCode(PropertyType type, String* name) { CallStubCompiler::CallStubCompiler(int argc, InLoopFlag in_loop, Code::Kind kind, + Code::ExtraICState extra_ic_state, InlineCacheHolderFlag cache_holder) - : arguments_(argc) - , in_loop_(in_loop) - , kind_(kind) - , cache_holder_(cache_holder) { + : arguments_(argc), + in_loop_(in_loop), + kind_(kind), + extra_ic_state_(extra_ic_state), + cache_holder_(cache_holder) { } @@ -1534,6 +1611,7 @@ MaybeObject* CallStubCompiler::GetCode(PropertyType type, String* name) { int argc = arguments_.immediate(); Code::Flags flags = Code::ComputeMonomorphicFlags(kind_, type, + extra_ic_state_, cache_holder_, in_loop_, argc); @@ -1559,6 +1637,7 @@ MaybeObject* ConstructStubCompiler::GetCode() { Code* code = Code::cast(result); USE(code); PROFILE(CodeCreateEvent(Logger::STUB_TAG, code, "ConstructStub")); + GDBJIT(AddCode(GDBJITInterface::STUB, "ConstructStub", Code::cast(code))); return result; } diff --git a/deps/v8/src/stub-cache.h b/deps/v8/src/stub-cache.h index a7829a600e..85dd5f6aae 100644 --- a/deps/v8/src/stub-cache.h +++ b/deps/v8/src/stub-cache.h @@ -177,13 +177,15 @@ class StubCache : public AllStatic { JSObject* holder, int index); - MUST_USE_RESULT static MaybeObject* ComputeCallConstant(int argc, - InLoopFlag in_loop, - Code::Kind, - String* name, - Object* object, - JSObject* holder, - JSFunction* function); + MUST_USE_RESULT static MaybeObject* ComputeCallConstant( + int argc, + InLoopFlag in_loop, + Code::Kind, + Code::ExtraICState extra_ic_state, + String* name, + Object* object, + JSObject* holder, + JSFunction* function); MUST_USE_RESULT static MaybeObject* ComputeCallNormal(int argc, InLoopFlag in_loop, @@ -660,6 +662,7 @@ class CallStubCompiler: public StubCompiler { CallStubCompiler(int argc, InLoopFlag in_loop, Code::Kind kind, + Code::ExtraICState extra_ic_state, InlineCacheHolderFlag cache_holder); MUST_USE_RESULT MaybeObject* CompileCallField(JSObject* object, @@ -705,6 +708,7 @@ class CallStubCompiler: public StubCompiler { const ParameterCount arguments_; const InLoopFlag in_loop_; const Code::Kind kind_; + const Code::ExtraICState extra_ic_state_; const InlineCacheHolderFlag cache_holder_; const ParameterCount& arguments() { return arguments_; } diff --git a/deps/v8/src/third_party/strongtalk/LICENSE b/deps/v8/src/third_party/strongtalk/LICENSE new file mode 100644 index 0000000000..7473a7b2b5 --- /dev/null +++ b/deps/v8/src/third_party/strongtalk/LICENSE @@ -0,0 +1,29 @@ +Copyright (c) 1994-2006 Sun Microsystems Inc. +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. + +- Redistribution 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 Sun Microsystems or the names of 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. diff --git a/deps/v8/src/third_party/strongtalk/README.chromium b/deps/v8/src/third_party/strongtalk/README.chromium new file mode 100644 index 0000000000..ba2b789f38 --- /dev/null +++ b/deps/v8/src/third_party/strongtalk/README.chromium @@ -0,0 +1,18 @@ +Name: Strongtalk +URL: http://www.strongtalk.org/ + +Code from the Strongtalk assembler is used with modification in the following +files: + +src/assembler.h +src/assembler.cc +src/arm/assembler-arm.cc +src/arm/assembler-arm.h +src/arm/assembler-arm-inl.h +src/ia32/assembler-ia32.cc +src/ia32/assembler-ia32.h +src/ia32/assembler-ia32-inl.h +src/mips/assembler-mips.cc +src/mips/assembler-mips.h +src/mips/assembler-mips-inl.h +src/x64/assembler-x64.h diff --git a/deps/v8/src/type-info.cc b/deps/v8/src/type-info.cc index 032d98567e..f4f65e99b4 100644 --- a/deps/v8/src/type-info.cc +++ b/deps/v8/src/type-info.cc @@ -58,6 +58,9 @@ TypeInfo TypeInfo::TypeFromValue(Handle<Object> value) { } +STATIC_ASSERT(DEFAULT_STRING_STUB == Code::kNoExtraICState); + + TypeFeedbackOracle::TypeFeedbackOracle(Handle<Code> code, Handle<Context> global_context) { global_context_ = global_context; @@ -117,8 +120,16 @@ ZoneMapList* TypeFeedbackOracle::StoreReceiverTypes(Assignment* expr, ZoneMapList* TypeFeedbackOracle::CallReceiverTypes(Call* expr, Handle<String> name) { int arity = expr->arguments()->length(); - Code::Flags flags = Code::ComputeMonomorphicFlags( - Code::CALL_IC, NORMAL, OWN_MAP, NOT_IN_LOOP, arity); + // Note: these flags won't let us get maps from stubs with + // non-default extra ic state in the megamorphic case. In the more + // important monomorphic case the map is obtained directly, so it's + // not a problem until we decide to emit more polymorphic code. + Code::Flags flags = Code::ComputeMonomorphicFlags(Code::CALL_IC, + NORMAL, + Code::kNoExtraICState, + OWN_MAP, + NOT_IN_LOOP, + arity); return CollectReceiverTypes(expr->position(), name, flags); } diff --git a/deps/v8/src/type-info.h b/deps/v8/src/type-info.h index 98d97def29..e026e88c0f 100644 --- a/deps/v8/src/type-info.h +++ b/deps/v8/src/type-info.h @@ -219,6 +219,12 @@ class TypeInfo { }; +enum StringStubFeedback { + DEFAULT_STRING_STUB = 0, + STRING_INDEX_OUT_OF_BOUNDS = 1 +}; + + // Forward declarations. class Assignment; class BinaryOperation; diff --git a/deps/v8/src/version.cc b/deps/v8/src/version.cc index a77d85f75f..495de31404 100644 --- a/deps/v8/src/version.cc +++ b/deps/v8/src/version.cc @@ -34,7 +34,7 @@ // cannot be changed without changing the SCons build script. #define MAJOR_VERSION 3 #define MINOR_VERSION 0 -#define BUILD_NUMBER 8 +#define BUILD_NUMBER 9 #define PATCH_LEVEL 0 #define CANDIDATE_VERSION false diff --git a/deps/v8/src/x64/assembler-x64.cc b/deps/v8/src/x64/assembler-x64.cc index 9060d57586..de01cfa3c1 100644 --- a/deps/v8/src/x64/assembler-x64.cc +++ b/deps/v8/src/x64/assembler-x64.cc @@ -2950,6 +2950,12 @@ void Assembler::emit_sse_operand(Register dst, XMMRegister src) { } +void Assembler::db(uint8_t data) { + EnsureSpace ensure_space(this); + emit(data); +} + + void Assembler::dd(uint32_t data) { EnsureSpace ensure_space(this); emitl(data); diff --git a/deps/v8/src/x64/assembler-x64.h b/deps/v8/src/x64/assembler-x64.h index fa2f4c3518..be837f0448 100644 --- a/deps/v8/src/x64/assembler-x64.h +++ b/deps/v8/src/x64/assembler-x64.h @@ -1261,7 +1261,7 @@ class Assembler : public Malloced { // Writes a single word of data in the code stream. // Used for inline tables, e.g., jump-tables. - void db(uint8_t data) { UNIMPLEMENTED(); } + void db(uint8_t data); void dd(uint32_t data); int pc_offset() const { return static_cast<int>(pc_ - buffer_); } diff --git a/deps/v8/src/x64/code-stubs-x64.h b/deps/v8/src/x64/code-stubs-x64.h index 5056f34849..9feced2f94 100644 --- a/deps/v8/src/x64/code-stubs-x64.h +++ b/deps/v8/src/x64/code-stubs-x64.h @@ -198,6 +198,7 @@ class GenericBinaryOpStub: public CodeStub { } friend class CodeGenerator; + friend class LCodeGen; }; diff --git a/deps/v8/src/x64/deoptimizer-x64.cc b/deps/v8/src/x64/deoptimizer-x64.cc index 8bb3ac09fd..6b19d3f141 100644 --- a/deps/v8/src/x64/deoptimizer-x64.cc +++ b/deps/v8/src/x64/deoptimizer-x64.cc @@ -41,7 +41,8 @@ namespace internal { int Deoptimizer::table_entry_size_ = 10; void Deoptimizer::DeoptimizeFunction(JSFunction* function) { - UNIMPLEMENTED(); + // UNIMPLEMENTED, for now just return. + return; } @@ -68,7 +69,8 @@ void Deoptimizer::DoComputeFrame(TranslationIterator* iterator, void Deoptimizer::EntryGenerator::Generate() { - UNIMPLEMENTED(); + // UNIMPLEMENTED, for now just return. + return; } diff --git a/deps/v8/src/x64/frames-x64.h b/deps/v8/src/x64/frames-x64.h index fbbf176e4a..a2a0e7e9ff 100644 --- a/deps/v8/src/x64/frames-x64.h +++ b/deps/v8/src/x64/frames-x64.h @@ -45,7 +45,7 @@ typedef Object* JSCallerSavedBuffer[kNumJSCallerSaved]; // Number of registers for which space is reserved in safepoints. // TODO(x64): This should not be 0. -static const int kNumSafepointRegisters = 0; +static const int kNumSafepointRegisters = 8; // ---------------------------------------------------- diff --git a/deps/v8/src/x64/ic-x64.cc b/deps/v8/src/x64/ic-x64.cc index 29cbed05e1..b54aeb977d 100644 --- a/deps/v8/src/x64/ic-x64.cc +++ b/deps/v8/src/x64/ic-x64.cc @@ -1178,8 +1178,12 @@ static void GenerateMonomorphicCacheProbe(MacroAssembler* masm, Label number, non_number, non_string, boolean, probe, miss; // Probe the stub cache. - Code::Flags flags = - Code::ComputeFlags(kind, NOT_IN_LOOP, MONOMORPHIC, NORMAL, argc); + Code::Flags flags = Code::ComputeFlags(kind, + NOT_IN_LOOP, + MONOMORPHIC, + Code::kNoExtraICState, + NORMAL, + argc); StubCache::GenerateProbe(masm, flags, rdx, rcx, rbx, rax); // If the stub cache probing failed, the receiver might be a value. diff --git a/deps/v8/src/x64/lithium-codegen-x64.cc b/deps/v8/src/x64/lithium-codegen-x64.cc index e586851e8e..151fad7362 100644 --- a/deps/v8/src/x64/lithium-codegen-x64.cc +++ b/deps/v8/src/x64/lithium-codegen-x64.cc @@ -155,13 +155,13 @@ bool LGapResolver::CanReach(LGapNode* a, LGapNode* b) { void LGapResolver::RegisterMove(LMoveOperands move) { - if (move.from()->IsConstantOperand()) { + if (move.source()->IsConstantOperand()) { // Constant moves should be last in the machine code. Therefore add them // first to the result set. - AddResultMove(move.from(), move.to()); + AddResultMove(move.source(), move.destination()); } else { - LGapNode* from = LookupNode(move.from()); - LGapNode* to = LookupNode(move.to()); + LGapNode* from = LookupNode(move.source()); + LGapNode* to = LookupNode(move.destination()); if (to->IsAssigned() && to->assigned_from() == from) { move.Eliminate(); return; @@ -338,8 +338,9 @@ bool LCodeGen::GenerateDeferredCode() { bool LCodeGen::GenerateSafepointTable() { - Abort("Unimplemented: %s", "GeneratePrologue"); - return false; + ASSERT(is_done()); + safepoints_.Emit(masm(), StackSlotCount()); + return !is_aborted(); } @@ -492,7 +493,24 @@ void LCodeGen::AddToTranslation(Translation* translation, void LCodeGen::CallCode(Handle<Code> code, RelocInfo::Mode mode, LInstruction* instr) { - Abort("Unimplemented: %s", "CallCode"); + if (instr != NULL) { + LPointerMap* pointers = instr->pointer_map(); + RecordPosition(pointers->position()); + __ call(code, mode); + RegisterLazyDeoptimization(instr); + } else { + LPointerMap no_pointers(0); + RecordPosition(no_pointers.position()); + __ call(code, mode); + RecordSafepoint(&no_pointers, Safepoint::kNoDeoptimizationIndex); + } + + // Signal that we don't inline smi code before these stubs in the + // optimizing code generator. + if (code->kind() == Code::TYPE_RECORDING_BINARY_OP_IC || + code->kind() == Code::COMPARE_IC) { + __ nop(); + } } @@ -521,7 +539,30 @@ void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr) { void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment) { - Abort("Unimplemented: %s", "RegisterEnvironmentForDeoptimization"); + if (!environment->HasBeenRegistered()) { + // Physical stack frame layout: + // -x ............. -4 0 ..................................... y + // [incoming arguments] [spill slots] [pushed outgoing arguments] + + // Layout of the environment: + // 0 ..................................................... size-1 + // [parameters] [locals] [expression stack including arguments] + + // Layout of the translation: + // 0 ........................................................ size - 1 + 4 + // [expression stack including arguments] [locals] [4 words] [parameters] + // |>------------ translation_size ------------<| + + int frame_count = 0; + for (LEnvironment* e = environment; e != NULL; e = e->outer()) { + ++frame_count; + } + Translation translation(&translations_, frame_count); + WriteTranslation(environment, &translation); + int deoptimization_index = deoptimizations_.length(); + environment->Register(deoptimization_index, translation.index()); + deoptimizations_.Add(environment); + } } @@ -651,8 +692,8 @@ void LCodeGen::DoParallelMove(LParallelMove* move) { resolver_.Resolve(move->move_operands(), &marker_operand); for (int i = moves->length() - 1; i >= 0; --i) { LMoveOperands move = moves->at(i); - LOperand* from = move.from(); - LOperand* to = move.to(); + LOperand* from = move.source(); + LOperand* to = move.destination(); ASSERT(!from->IsDoubleRegister() || !ToDoubleRegister(from).is(xmm_scratch)); ASSERT(!to->IsDoubleRegister() || !ToDoubleRegister(to).is(xmm_scratch)); @@ -784,12 +825,31 @@ void LCodeGen::DoSubI(LSubI* instr) { void LCodeGen::DoConstantI(LConstantI* instr) { - Abort("Unimplemented: %s", "DoConstantI"); + ASSERT(instr->result()->IsRegister()); + __ movl(ToRegister(instr->result()), Immediate(instr->value())); } void LCodeGen::DoConstantD(LConstantD* instr) { - Abort("Unimplemented: %s", "DoConstantI"); + ASSERT(instr->result()->IsDoubleRegister()); + XMMRegister res = ToDoubleRegister(instr->result()); + double v = instr->value(); + // Use xor to produce +0.0 in a fast and compact way, but avoid to + // do so if the constant is -0.0. + if (BitCast<uint64_t, double>(v) == 0) { + __ xorpd(res, res); + } else { + Register tmp = ToRegister(instr->TempAt(0)); + int32_t v_int32 = static_cast<int32_t>(v); + if (static_cast<double>(v_int32) == v) { + __ movl(tmp, Immediate(v_int32)); + __ cvtlsi2sd(res, tmp); + } else { + uint64_t int_val = BitCast<uint64_t, double>(v); + __ Set(tmp, int_val); + __ movd(res, tmp); + } + } } @@ -825,7 +885,22 @@ void LCodeGen::DoThrow(LThrow* instr) { void LCodeGen::DoAddI(LAddI* instr) { - Abort("Unimplemented: %s", "DoAddI"); + LOperand* left = instr->InputAt(0); + LOperand* right = instr->InputAt(1); + ASSERT(left->Equals(instr->result())); + + if (right->IsConstantOperand()) { + __ addl(ToRegister(left), + Immediate(ToInteger32(LConstantOperand::cast(right)))); + } else if (right->IsRegister()) { + __ addl(ToRegister(left), ToRegister(right)); + } else { + __ addl(ToRegister(left), ToOperand(right)); + } + + if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { + DeoptimizeIf(overflow, instr->environment()); + } } @@ -835,7 +910,13 @@ void LCodeGen::DoArithmeticD(LArithmeticD* instr) { void LCodeGen::DoArithmeticT(LArithmeticT* instr) { - Abort("Unimplemented: %s", "DoArithmeticT"); + ASSERT(ToRegister(instr->InputAt(0)).is(rdx)); + ASSERT(ToRegister(instr->InputAt(1)).is(rax)); + ASSERT(ToRegister(instr->result()).is(rax)); + + GenericBinaryOpStub stub(instr->op(), NO_OVERWRITE, NO_GENERIC_BINARY_FLAGS); + stub.SetArgsInRegisters(); + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); } @@ -859,7 +940,19 @@ void LCodeGen::DoBranch(LBranch* instr) { void LCodeGen::EmitGoto(int block, LDeferredCode* deferred_stack_check) { - Abort("Unimplemented: %s", "EmitGoto"); + block = chunk_->LookupDestination(block); + int next_block = GetNextEmittedBlock(current_block_); + if (block != next_block) { + // Perform stack overflow check if this goto needs it before jumping. + if (deferred_stack_check != NULL) { + __ CompareRoot(rsp, Heap::kStackLimitRootIndex); + __ j(above_equal, chunk_->GetAssemblyLabel(block)); + __ jmp(deferred_stack_check->entry()); + deferred_stack_check->SetExit(chunk_->GetAssemblyLabel(block)); + } else { + __ jmp(chunk_->GetAssemblyLabel(block)); + } + } } @@ -979,27 +1072,6 @@ void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { } -InstanceType LHasInstanceType::TestType() { - InstanceType from = hydrogen()->from(); - InstanceType to = hydrogen()->to(); - if (from == FIRST_TYPE) return to; - ASSERT(from == to || to == LAST_TYPE); - return from; -} - - - -Condition LHasInstanceType::BranchCondition() { - InstanceType from = hydrogen()->from(); - InstanceType to = hydrogen()->to(); - if (from == to) return equal; - if (to == LAST_TYPE) return above_equal; - if (from == FIRST_TYPE) return below_equal; - UNREACHABLE(); - return equal; -} - - void LCodeGen::DoHasInstanceType(LHasInstanceType* instr) { Abort("Unimplemented: %s", "DoHasInstanceType"); } diff --git a/deps/v8/src/x64/lithium-x64.cc b/deps/v8/src/x64/lithium-x64.cc index 25a048bad0..5ef6eb7534 100644 --- a/deps/v8/src/x64/lithium-x64.cc +++ b/deps/v8/src/x64/lithium-x64.cc @@ -90,18 +90,22 @@ void LInstruction::PrintTo(StringStream* stream) { template<int R, int I, int T> void LTemplateInstruction<R, I, T>::PrintDataTo(StringStream* stream) { - for (int i = 0; i < I; i++) { - stream->Add(i == 0 ? "= " : " "); - inputs_.at(i)->PrintTo(stream); - } + stream->Add("= "); + inputs_.PrintOperandsTo(stream); } template<int R, int I, int T> void LTemplateInstruction<R, I, T>::PrintOutputOperandTo(StringStream* stream) { - if (this->HasResult()) { - this->result()->PrintTo(stream); - stream->Add(" "); + results_.PrintOperandsTo(stream); +} + + +template<typename T, int N> +void OperandContainer<T, N>::PrintOperandsTo(StringStream* stream) { + for (int i = 0; i < N; i++) { + if (i > 0) stream->Add(" "); + elems_[i]->PrintTo(stream); } } @@ -172,22 +176,22 @@ void LGoto::PrintDataTo(StringStream* stream) { void LBranch::PrintDataTo(StringStream* stream) { stream->Add("B%d | B%d on ", true_block_id(), false_block_id()); - input()->PrintTo(stream); + InputAt(0)->PrintTo(stream); } void LCmpIDAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if "); - left()->PrintTo(stream); + InputAt(0)->PrintTo(stream); stream->Add(" %s ", Token::String(op())); - right()->PrintTo(stream); + InputAt(1)->PrintTo(stream); stream->Add(" then B%d else B%d", true_block_id(), false_block_id()); } void LIsNullAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if "); - input()->PrintTo(stream); + InputAt(0)->PrintTo(stream); stream->Add(is_strict() ? " === null" : " == null"); stream->Add(" then B%d else B%d", true_block_id(), false_block_id()); } @@ -195,35 +199,35 @@ void LIsNullAndBranch::PrintDataTo(StringStream* stream) { void LIsObjectAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if is_object("); - input()->PrintTo(stream); + InputAt(0)->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LIsSmiAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if is_smi("); - input()->PrintTo(stream); + InputAt(0)->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if has_instance_type("); - input()->PrintTo(stream); + InputAt(0)->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if has_cached_array_index("); - input()->PrintTo(stream); + InputAt(0)->PrintTo(stream); stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); } void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if class_of_test("); - input()->PrintTo(stream); + InputAt(0)->PrintTo(stream); stream->Add(", \"%o\") then B%d else B%d", *hydrogen()->class_name(), true_block_id(), @@ -232,14 +236,14 @@ void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) { void LTypeofIs::PrintDataTo(StringStream* stream) { - input()->PrintTo(stream); + InputAt(0)->PrintTo(stream); stream->Add(" == \"%s\"", *hydrogen()->type_literal()->ToCString()); } void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if typeof "); - input()->PrintTo(stream); + InputAt(0)->PrintTo(stream); stream->Add(" == \"%s\" then B%d else B%d", *hydrogen()->type_literal()->ToCString(), true_block_id(), false_block_id()); @@ -253,7 +257,7 @@ void LCallConstantFunction::PrintDataTo(StringStream* stream) { void LUnaryMathOperation::PrintDataTo(StringStream* stream) { stream->Add("/%s ", hydrogen()->OpName()); - input()->PrintTo(stream); + InputAt(0)->PrintTo(stream); } @@ -263,7 +267,7 @@ void LLoadContextSlot::PrintDataTo(StringStream* stream) { void LCallKeyed::PrintDataTo(StringStream* stream) { - stream->Add("[rcx] #%d / ", arity()); + stream->Add("[ecx] #%d / ", arity()); } @@ -286,14 +290,14 @@ void LCallKnownGlobal::PrintDataTo(StringStream* stream) { void LCallNew::PrintDataTo(StringStream* stream) { stream->Add("= "); - input()->PrintTo(stream); + InputAt(0)->PrintTo(stream); stream->Add(" #%d / ", arity()); } void LClassOfTest::PrintDataTo(StringStream* stream) { stream->Add("= class_of_test("); - input()->PrintTo(stream); + InputAt(0)->PrintTo(stream); stream->Add(", \"%o\")", *hydrogen()->class_name()); } @@ -571,6 +575,13 @@ LOperand* LChunkBuilder::UseRegisterOrConstantAtStart(HValue* value) { } +LOperand* LChunkBuilder::UseAny(HValue* value) { + return value->IsConstant() + ? chunk_->DefineConstantOperand(HConstant::cast(value)) + : Use(value, new LUnallocated(LUnallocated::ANY)); +} + + LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) { if (value->EmitAtUses()) { HInstruction* instr = HInstruction::cast(value); @@ -743,8 +754,19 @@ LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op, LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op, HArithmeticBinaryOperation* instr) { - Abort("Unimplemented: %s", "DoArithmeticT"); - return NULL; + ASSERT(op == Token::ADD || + op == Token::DIV || + op == Token::MOD || + op == Token::MUL || + op == Token::SUB); + HValue* left = instr->left(); + HValue* right = instr->right(); + ASSERT(left->representation().IsTagged()); + ASSERT(right->representation().IsTagged()); + LOperand* left_operand = UseFixed(left, rdx); + LOperand* right_operand = UseFixed(right, rax); + LArithmeticT* result = new LArithmeticT(op, left_operand, right_operand); + return MarkAsCall(DefineFixed(result, rax), instr); } @@ -825,8 +847,17 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) { if (FLAG_stress_environments && !instr->HasEnvironment()) { instr = AssignEnvironment(instr); } - if (current->IsBranch()) { - instr->set_hydrogen_value(HBranch::cast(current)->value()); + if (current->IsBranch() && !instr->IsGoto()) { + // TODO(fschneider): Handle branch instructions uniformly like + // other instructions. This requires us to generate the right + // branch instruction already at the HIR level. + ASSERT(instr->IsControl()); + HBranch* branch = HBranch::cast(current); + instr->set_hydrogen_value(branch->value()); + HBasicBlock* first = branch->FirstSuccessor(); + HBasicBlock* second = branch->SecondSuccessor(); + ASSERT(first != NULL && second != NULL); + instr->SetBranchTargets(first->block_id(), second->block_id()); } else { instr->set_hydrogen_value(current); } @@ -863,11 +894,7 @@ LEnvironment* LChunkBuilder::CreateEnvironment(HEnvironment* hydrogen_env) { } else if (value->IsPushArgument()) { op = new LArgument(argument_index++); } else { - op = UseOrConstant(value); - if (op->IsUnallocated()) { - LUnallocated* unalloc = LUnallocated::cast(op); - unalloc->set_policy(LUnallocated::ANY); - } + op = UseAny(value); } result->AddValue(op, value->representation()); } @@ -1069,7 +1096,23 @@ LInstruction* LChunkBuilder::DoSub(HSub* instr) { LInstruction* LChunkBuilder::DoAdd(HAdd* instr) { - Abort("Unimplemented: %s", "DoAdd"); + if (instr->representation().IsInteger32()) { + ASSERT(instr->left()->representation().IsInteger32()); + ASSERT(instr->right()->representation().IsInteger32()); + LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand()); + LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand()); + LAddI* add = new LAddI(left, right); + LInstruction* result = DefineSameAsFirst(add); + if (instr->CheckFlag(HValue::kCanOverflow)) { + result = AssignEnvironment(result); + } + return result; + } else if (instr->representation().IsDouble()) { + Abort("Unimplemented: %s", "DoAdd on Doubles"); + } else { + ASSERT(instr->representation().IsTagged()); + return DoArithmeticT(Token::ADD, instr); + } return NULL; } @@ -1214,7 +1257,8 @@ LInstruction* LChunkBuilder::DoConstant(HConstant* instr) { return DefineAsRegister(new LConstantI(value)); } else if (r.IsDouble()) { double value = instr->DoubleValue(); - return DefineAsRegister(new LConstantD(value)); + LOperand* temp = TempRegister(); + return DefineAsRegister(new LConstantD(value, temp)); } else if (r.IsTagged()) { return DefineAsRegister(new LConstantT(instr->handle())); } else { diff --git a/deps/v8/src/x64/lithium-x64.h b/deps/v8/src/x64/lithium-x64.h index f3023f9792..17d9dda108 100644 --- a/deps/v8/src/x64/lithium-x64.h +++ b/deps/v8/src/x64/lithium-x64.h @@ -43,10 +43,22 @@ class LCodeGen; // Type hierarchy: // // LInstruction -// LAccessArgumentsAt -// LArgumentsElements -// LArgumentsLength -// LBinaryOperation +// LTemplateInstruction +// LControlInstruction +// LBranch +// LClassOfTestAndBranch +// LCmpJSObjectEqAndBranch +// LCmpIDAndBranch +// LHasCachedArrayIndexAndBranch +// LHasInstanceTypeAndBranch +// LInstanceOfAndBranch +// LIsNullAndBranch +// LIsObjectAndBranch +// LIsSmiAndBranch +// LTypeofIsAndBranch +// LAccessArgumentsAt +// LArgumentsElements +// LArgumentsLength // LAddI // LApplyArguments // LArithmeticD @@ -54,13 +66,10 @@ class LCodeGen; // LBitI // LBoundsCheck // LCmpID -// LCmpIDAndBranch // LCmpJSObjectEq -// LCmpJSObjectEqAndBranch // LCmpT // LDivI // LInstanceOf -// LInstanceOfAndBranch // LInstanceOfKnownGlobal // LLoadKeyedFastElement // LLoadKeyedGeneric @@ -69,67 +78,59 @@ class LCodeGen; // LPower // LShiftI // LSubI -// LCallConstantFunction -// LCallFunction -// LCallGlobal -// LCallKeyed -// LCallKnownGlobal -// LCallNamed -// LCallRuntime -// LCallStub -// LCheckPrototypeMaps -// LConstant -// LConstantD -// LConstantI -// LConstantT -// LDeoptimize -// LFunctionLiteral -// LGap -// LLabel -// LGlobalObject -// LGlobalReceiver -// LGoto -// LLazyBailout -// LLoadContextSlot -// LLoadGlobal -// LMaterializedLiteral +// LCallConstantFunction +// LCallFunction +// LCallGlobal +// LCallKeyed +// LCallKnownGlobal +// LCallNamed +// LCallRuntime +// LCallStub +// LConstant +// LConstantD +// LConstantI +// LConstantT +// LDeoptimize +// LFunctionLiteral +// LGap +// LLabel +// LGlobalObject +// LGlobalReceiver +// LGoto +// LLazyBailout +// LLoadGlobal +// LCheckPrototypeMaps +// LLoadContextSlot // LArrayLiteral // LObjectLiteral // LRegExpLiteral -// LOsrEntry -// LParameter -// LRegExpConstructResult -// LStackCheck -// LStoreKeyed -// LStoreKeyedFastElement -// LStoreKeyedGeneric -// LStoreNamed -// LStoreNamedField -// LStoreNamedGeneric -// LUnaryOperation +// LOsrEntry +// LParameter +// LRegExpConstructResult +// LStackCheck +// LStoreKeyed +// LStoreKeyedFastElement +// LStoreKeyedGeneric +// LStoreNamed +// LStoreNamedField +// LStoreNamedGeneric // LBitNotI -// LBranch // LCallNew // LCheckFunction +// LCheckPrototypeMaps // LCheckInstanceType // LCheckMap // LCheckSmi // LClassOfTest -// LClassOfTestAndBranch // LDeleteProperty // LDoubleToI // LFixedArrayLength // LHasCachedArrayIndex -// LHasCachedArrayIndexAndBranch // LHasInstanceType -// LHasInstanceTypeAndBranch // LInteger32ToDouble // LIsNull -// LIsNullAndBranch // LIsObject -// LIsObjectAndBranch // LIsSmi -// LIsSmiAndBranch // LJSArrayLength // LLoadNamedField // LLoadNamedGeneric @@ -144,19 +145,16 @@ class LCodeGen; // LThrow // LTypeof // LTypeofIs -// LTypeofIsAndBranch // LUnaryMathOperation // LValueOf -// LUnknownOSRValue +// LUnknownOSRValue #define LITHIUM_ALL_INSTRUCTION_LIST(V) \ - V(BinaryOperation) \ + V(ControlInstruction) \ V(Constant) \ V(Call) \ - V(MaterializedLiteral) \ V(StoreKeyed) \ V(StoreNamed) \ - V(UnaryOperation) \ LITHIUM_CONCRETE_INSTRUCTION_LIST(V) @@ -302,7 +300,9 @@ class LInstruction: public ZoneObject { #define DECLARE_DO(type) virtual bool Is##type() const { return false; } LITHIUM_ALL_INSTRUCTION_LIST(DECLARE_DO) #undef DECLARE_DO + virtual bool IsControl() const { return false; } + virtual void SetBranchTargets(int true_block_id, int false_block_id) { } void set_environment(LEnvironment* env) { environment_.set(env); } LEnvironment* environment() const { return environment_.get(); } @@ -341,9 +341,13 @@ class OperandContainer { OperandContainer() { for (int i = 0; i < N; i++) elems_[i] = NULL; } - int length() const { return N; } - T at(int i) const { return elems_[i]; } - void set_at(int i, T value) { elems_[i] = value; } + int length() { return N; } + T& operator[](int i) { + ASSERT(i < length()); + return elems_[i]; + } + void PrintOperandsTo(StringStream* stream); + private: T elems_[N]; }; @@ -352,38 +356,31 @@ class OperandContainer { template<typename T> class OperandContainer<T, 0> { public: - int length() const { return 0; } - T at(int i) const { - UNREACHABLE(); - return NULL; - } - void set_at(int i, T value) { - UNREACHABLE(); - } + int length() { return 0; } + void PrintOperandsTo(StringStream* stream) { } }; -template<int R, int I, int T> +template<int R, int I, int T = 0> class LTemplateInstruction: public LInstruction { public: // Allow 0 or 1 output operands. STATIC_ASSERT(R == 0 || R == 1); virtual bool HasResult() const { return R != 0; } - void set_result(LOperand* operand) { outputs_.set_at(0, operand); } - LOperand* result() const { return outputs_.at(0); } + void set_result(LOperand* operand) { results_[0] = operand; } + LOperand* result() { return results_[0]; } - int InputCount() const { return inputs_.length(); } - LOperand* InputAt(int i) const { return inputs_.at(i); } - void SetInputAt(int i, LOperand* operand) { inputs_.set_at(i, operand); } + int InputCount() { return I; } + LOperand* InputAt(int i) { return inputs_[i]; } - int TempCount() const { return temps_.length(); } - LOperand* TempAt(int i) const { return temps_.at(i); } + int TempCount() { return T; } + LOperand* TempAt(int i) { return temps_[i]; } virtual void PrintDataTo(StringStream* stream); virtual void PrintOutputOperandTo(StringStream* stream); - private: - OperandContainer<LOperand*, R> outputs_; + protected: + OperandContainer<LOperand*, R> results_; OperandContainer<LOperand*, I> inputs_; OperandContainer<LOperand*, T> temps_; }; @@ -515,31 +512,22 @@ class LUnknownOSRValue: public LTemplateInstruction<1, 0, 0> { }; -template<int R> -class LUnaryOperation: public LTemplateInstruction<R, 1, 0> { +template<int I, int T = 0> +class LControlInstruction: public LTemplateInstruction<0, I, T> { public: - explicit LUnaryOperation<R>(LOperand* input) { - this->SetInputAt(0, input); - } - - LOperand* input() const { return this->InputAt(0); } - - DECLARE_INSTRUCTION(UnaryOperation) -}; - + DECLARE_INSTRUCTION(ControlInstruction) + virtual bool IsControl() const { return true; } -template<int R> -class LBinaryOperation: public LTemplateInstruction<R, 2, 0> { - public: - LBinaryOperation(LOperand* left, LOperand* right) { - this->SetInputAt(0, left); - this->SetInputAt(1, right); + int true_block_id() const { return true_block_id_; } + int false_block_id() const { return false_block_id_; } + void SetBranchTargets(int true_block_id, int false_block_id) { + true_block_id_ = true_block_id; + false_block_id_ = false_block_id; } - DECLARE_INSTRUCTION(BinaryOperation) - - LOperand* left() const { return this->InputAt(0); } - LOperand* right() const { return this->InputAt(1); } + private: + int true_block_id_; + int false_block_id_; }; @@ -549,43 +537,44 @@ class LApplyArguments: public LTemplateInstruction<1, 4, 0> { LOperand* receiver, LOperand* length, LOperand* elements) { - this->SetInputAt(0, function); - this->SetInputAt(1, receiver); - this->SetInputAt(2, length); - this->SetInputAt(3, elements); + inputs_[0] = function; + inputs_[1] = receiver; + inputs_[2] = length; + inputs_[3] = elements; } DECLARE_CONCRETE_INSTRUCTION(ApplyArguments, "apply-arguments") - LOperand* function() const { return InputAt(0); } - LOperand* receiver() const { return InputAt(1); } - LOperand* length() const { return InputAt(2); } - LOperand* elements() const { return InputAt(3); } + LOperand* function() { return inputs_[0]; } + LOperand* receiver() { return inputs_[1]; } + LOperand* length() { return inputs_[2]; } + LOperand* elements() { return inputs_[3]; } }; class LAccessArgumentsAt: public LTemplateInstruction<1, 3, 0> { public: LAccessArgumentsAt(LOperand* arguments, LOperand* length, LOperand* index) { - this->SetInputAt(0, arguments); - this->SetInputAt(1, length); - this->SetInputAt(2, index); + inputs_[0] = arguments; + inputs_[1] = length; + inputs_[2] = index; } DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt, "access-arguments-at") - LOperand* arguments() const { return this->InputAt(0); } - LOperand* length() const { return this->InputAt(1); } - LOperand* index() const { return this->InputAt(2); } + LOperand* arguments() { return inputs_[0]; } + LOperand* length() { return inputs_[1]; } + LOperand* index() { return inputs_[2]; } virtual void PrintDataTo(StringStream* stream); }; -class LArgumentsLength: public LUnaryOperation<1> { +class LArgumentsLength: public LTemplateInstruction<1, 1> { public: - explicit LArgumentsLength(LOperand* elements) - : LUnaryOperation<1>(elements) {} + explicit LArgumentsLength(LOperand* elements) { + inputs_[0] = elements; + } DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength, "arguments-length") }; @@ -599,82 +588,86 @@ class LArgumentsElements: public LTemplateInstruction<1, 0, 0> { }; -class LModI: public LBinaryOperation<1> { +class LModI: public LTemplateInstruction<1, 2, 1> { public: - LModI(LOperand* left, LOperand* right) : LBinaryOperation<1>(left, right) { } + LModI(LOperand* left, LOperand* right, LOperand* temp) { + inputs_[0] = left; + inputs_[1] = right; + temps_[0] = temp; + } DECLARE_CONCRETE_INSTRUCTION(ModI, "mod-i") DECLARE_HYDROGEN_ACCESSOR(Mod) }; -class LDivI: public LBinaryOperation<1> { +class LDivI: public LTemplateInstruction<1, 2, 1> { public: - LDivI(LOperand* left, LOperand* right) - : LBinaryOperation<1>(left, right) { } + LDivI(LOperand* left, LOperand* right, LOperand* temp) { + inputs_[0] = left; + inputs_[1] = right; + temps_[0] = temp; + } DECLARE_CONCRETE_INSTRUCTION(DivI, "div-i") DECLARE_HYDROGEN_ACCESSOR(Div) }; -class LMulI: public LBinaryOperation<1> { +class LMulI: public LTemplateInstruction<1, 2, 1> { public: - LMulI(LOperand* left, LOperand* right, LOperand* temp) - : LBinaryOperation<1>(left, right), temp_(temp) { } + LMulI(LOperand* left, LOperand* right, LOperand* temp) { + inputs_[0] = left; + inputs_[1] = right; + temps_[0] = temp; + } DECLARE_CONCRETE_INSTRUCTION(MulI, "mul-i") DECLARE_HYDROGEN_ACCESSOR(Mul) - - LOperand* temp() const { return temp_; } - - private: - LOperand* temp_; }; -class LCmpID: public LBinaryOperation<1> { +class LCmpID: public LTemplateInstruction<1, 2> { public: - LCmpID(LOperand* left, LOperand* right) - : LBinaryOperation<1>(left, right) { } + LCmpID(LOperand* left, LOperand* right) { + inputs_[0] = left; + inputs_[1] = right; + } + + DECLARE_CONCRETE_INSTRUCTION(CmpID, "cmp-id") + DECLARE_HYDROGEN_ACCESSOR(Compare) Token::Value op() const { return hydrogen()->token(); } bool is_double() const { return hydrogen()->GetInputRepresentation().IsDouble(); } - - DECLARE_CONCRETE_INSTRUCTION(CmpID, "cmp-id") - DECLARE_HYDROGEN_ACCESSOR(Compare) }; -class LCmpIDAndBranch: public LCmpID { +class LCmpIDAndBranch: public LControlInstruction<2> { public: - LCmpIDAndBranch(LOperand* left, - LOperand* right, - int true_block_id, - int false_block_id) - : LCmpID(left, right), - true_block_id_(true_block_id), - false_block_id_(false_block_id) { } + LCmpIDAndBranch(LOperand* left, LOperand* right) { + inputs_[0] = left; + inputs_[1] = right; + } DECLARE_CONCRETE_INSTRUCTION(CmpIDAndBranch, "cmp-id-and-branch") - virtual void PrintDataTo(StringStream* stream); - virtual bool IsControl() const { return true; } + DECLARE_HYDROGEN_ACCESSOR(Compare) - int true_block_id() const { return true_block_id_; } - int false_block_id() const { return false_block_id_; } + Token::Value op() const { return hydrogen()->token(); } + bool is_double() const { + return hydrogen()->GetInputRepresentation().IsDouble(); + } - private: - int true_block_id_; - int false_block_id_; + virtual void PrintDataTo(StringStream* stream); }; -class LUnaryMathOperation: public LUnaryOperation<1> { +class LUnaryMathOperation: public LTemplateInstruction<1, 1> { public: - explicit LUnaryMathOperation(LOperand* value) - : LUnaryOperation<1>(value) { } + explicit LUnaryMathOperation(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation, "unary-math-operation") DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation) @@ -684,40 +677,34 @@ class LUnaryMathOperation: public LUnaryOperation<1> { }; -class LCmpJSObjectEq: public LBinaryOperation<1> { +class LCmpJSObjectEq: public LTemplateInstruction<1, 2> { public: - LCmpJSObjectEq(LOperand* left, LOperand* right) - : LBinaryOperation<1>(left, right) {} + LCmpJSObjectEq(LOperand* left, LOperand* right) { + inputs_[0] = left; + inputs_[1] = right; + } DECLARE_CONCRETE_INSTRUCTION(CmpJSObjectEq, "cmp-jsobject-eq") }; -class LCmpJSObjectEqAndBranch: public LCmpJSObjectEq { +class LCmpJSObjectEqAndBranch: public LControlInstruction<2> { public: - LCmpJSObjectEqAndBranch(LOperand* left, - LOperand* right, - int true_block_id, - int false_block_id) - : LCmpJSObjectEq(left, right), - true_block_id_(true_block_id), - false_block_id_(false_block_id) { } + LCmpJSObjectEqAndBranch(LOperand* left, LOperand* right) { + inputs_[0] = left; + inputs_[1] = right; + } DECLARE_CONCRETE_INSTRUCTION(CmpJSObjectEqAndBranch, "cmp-jsobject-eq-and-branch") - - int true_block_id() const { return true_block_id_; } - int false_block_id() const { return false_block_id_; } - - private: - int true_block_id_; - int false_block_id_; }; -class LIsNull: public LUnaryOperation<1> { +class LIsNull: public LTemplateInstruction<1, 1> { public: - explicit LIsNull(LOperand* value) : LUnaryOperation<1>(value) { } + explicit LIsNull(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(IsNull, "is-null") DECLARE_HYDROGEN_ACCESSOR(IsNull) @@ -726,227 +713,155 @@ class LIsNull: public LUnaryOperation<1> { }; -class LIsNullAndBranch: public LIsNull { +class LIsNullAndBranch: public LControlInstruction<1, 1> { public: - LIsNullAndBranch(LOperand* value, - LOperand* temp, - int true_block_id, - int false_block_id) - : LIsNull(value), - temp_(temp), - true_block_id_(true_block_id), - false_block_id_(false_block_id) { } + LIsNullAndBranch(LOperand* value, LOperand* temp) { + inputs_[0] = value; + temps_[0] = temp; + } DECLARE_CONCRETE_INSTRUCTION(IsNullAndBranch, "is-null-and-branch") - virtual void PrintDataTo(StringStream* stream); - virtual bool IsControl() const { return true; } - - int true_block_id() const { return true_block_id_; } - int false_block_id() const { return false_block_id_; } + DECLARE_HYDROGEN_ACCESSOR(IsNull) - LOperand* temp() const { return temp_; } + bool is_strict() const { return hydrogen()->is_strict(); } - private: - LOperand* temp_; - int true_block_id_; - int false_block_id_; + virtual void PrintDataTo(StringStream* stream); }; -class LIsObject: public LUnaryOperation<1> { +class LIsObject: public LTemplateInstruction<1, 1, 1> { public: - LIsObject(LOperand* value, LOperand* temp) - : LUnaryOperation<1>(value), temp_(temp) {} + LIsObject(LOperand* value, LOperand* temp) { + inputs_[0] = value; + temps_[0] = temp; + } DECLARE_CONCRETE_INSTRUCTION(IsObject, "is-object") - - LOperand* temp() const { return temp_; } - - private: - LOperand* temp_; }; -class LIsObjectAndBranch: public LIsObject { +class LIsObjectAndBranch: public LControlInstruction<1, 2> { public: - LIsObjectAndBranch(LOperand* value, - LOperand* temp, - LOperand* temp2, - int true_block_id, - int false_block_id) - : LIsObject(value, temp), - temp2_(temp2), - true_block_id_(true_block_id), - false_block_id_(false_block_id) { } + LIsObjectAndBranch(LOperand* value, LOperand* temp, LOperand* temp2) { + inputs_[0] = value; + temps_[0] = temp; + temps_[1] = temp2; + } DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch") - virtual void PrintDataTo(StringStream* stream); - virtual bool IsControl() const { return true; } - - int true_block_id() const { return true_block_id_; } - int false_block_id() const { return false_block_id_; } - LOperand* temp2() const { return temp2_; } - - private: - LOperand* temp2_; - int true_block_id_; - int false_block_id_; + virtual void PrintDataTo(StringStream* stream); }; -class LIsSmi: public LUnaryOperation<1> { +class LIsSmi: public LTemplateInstruction<1, 1> { public: - explicit LIsSmi(LOperand* value) : LUnaryOperation<1>(value) {} + explicit LIsSmi(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(IsSmi, "is-smi") DECLARE_HYDROGEN_ACCESSOR(IsSmi) }; -class LIsSmiAndBranch: public LIsSmi { +class LIsSmiAndBranch: public LControlInstruction<1> { public: - LIsSmiAndBranch(LOperand* value, - int true_block_id, - int false_block_id) - : LIsSmi(value), - true_block_id_(true_block_id), - false_block_id_(false_block_id) { } + explicit LIsSmiAndBranch(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch, "is-smi-and-branch") - virtual void PrintDataTo(StringStream* stream); - virtual bool IsControl() const { return true; } - - int true_block_id() const { return true_block_id_; } - int false_block_id() const { return false_block_id_; } - private: - int true_block_id_; - int false_block_id_; + virtual void PrintDataTo(StringStream* stream); }; -class LHasInstanceType: public LUnaryOperation<1> { +class LHasInstanceType: public LTemplateInstruction<1, 1> { public: - explicit LHasInstanceType(LOperand* value) - : LUnaryOperation<1>(value) { } + explicit LHasInstanceType(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(HasInstanceType, "has-instance-type") DECLARE_HYDROGEN_ACCESSOR(HasInstanceType) - - InstanceType TestType(); // The type to test against when generating code. - Condition BranchCondition(); // The branch condition for 'true'. }; -class LHasInstanceTypeAndBranch: public LHasInstanceType { +class LHasInstanceTypeAndBranch: public LControlInstruction<1, 1> { public: - LHasInstanceTypeAndBranch(LOperand* value, - LOperand* temporary, - int true_block_id, - int false_block_id) - : LHasInstanceType(value), - temp_(temporary), - true_block_id_(true_block_id), - false_block_id_(false_block_id) { } + LHasInstanceTypeAndBranch(LOperand* value, LOperand* temp) { + inputs_[0] = value; + temps_[0] = temp; + } DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch, "has-instance-type-and-branch") - virtual void PrintDataTo(StringStream* stream); - virtual bool IsControl() const { return true; } - - int true_block_id() const { return true_block_id_; } - int false_block_id() const { return false_block_id_; } - - LOperand* temp() { return temp_; } + DECLARE_HYDROGEN_ACCESSOR(HasInstanceType) - private: - LOperand* temp_; - int true_block_id_; - int false_block_id_; + virtual void PrintDataTo(StringStream* stream); }; -class LHasCachedArrayIndex: public LUnaryOperation<1> { +class LHasCachedArrayIndex: public LTemplateInstruction<1, 1> { public: - explicit LHasCachedArrayIndex(LOperand* value) : LUnaryOperation<1>(value) {} + explicit LHasCachedArrayIndex(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndex, "has-cached-array-index") DECLARE_HYDROGEN_ACCESSOR(HasCachedArrayIndex) }; -class LHasCachedArrayIndexAndBranch: public LHasCachedArrayIndex { +class LHasCachedArrayIndexAndBranch: public LControlInstruction<1> { public: - LHasCachedArrayIndexAndBranch(LOperand* value, - int true_block_id, - int false_block_id) - : LHasCachedArrayIndex(value), - true_block_id_(true_block_id), - false_block_id_(false_block_id) { } + explicit LHasCachedArrayIndexAndBranch(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch, "has-cached-array-index-and-branch") virtual void PrintDataTo(StringStream* stream); - virtual bool IsControl() const { return true; } - - int true_block_id() const { return true_block_id_; } - int false_block_id() const { return false_block_id_; } - - private: - int true_block_id_; - int false_block_id_; }; -class LClassOfTest: public LUnaryOperation<1> { +class LClassOfTest: public LTemplateInstruction<1, 1, 1> { public: - LClassOfTest(LOperand* value, LOperand* temp) - : LUnaryOperation<1>(value), temporary_(temp) {} + LClassOfTest(LOperand* value, LOperand* temp) { + inputs_[0] = value; + temps_[0] = temp; + } DECLARE_CONCRETE_INSTRUCTION(ClassOfTest, "class-of-test") DECLARE_HYDROGEN_ACCESSOR(ClassOfTest) virtual void PrintDataTo(StringStream* stream); - - LOperand* temporary() { return temporary_; } - - private: - LOperand* temporary_; }; -class LClassOfTestAndBranch: public LClassOfTest { +class LClassOfTestAndBranch: public LControlInstruction<1, 2> { public: - LClassOfTestAndBranch(LOperand* value, - LOperand* temporary, - LOperand* temporary2, - int true_block_id, - int false_block_id) - : LClassOfTest(value, temporary), - temporary2_(temporary2), - true_block_id_(true_block_id), - false_block_id_(false_block_id) { } + LClassOfTestAndBranch(LOperand* value, LOperand* temp, LOperand* temp2) { + inputs_[0] = value; + temps_[0] = temp; + temps_[1] = temp2; + } DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch, "class-of-test-and-branch") - virtual void PrintDataTo(StringStream* stream); - virtual bool IsControl() const { return true; } - - int true_block_id() const { return true_block_id_; } - int false_block_id() const { return false_block_id_; } - LOperand* temporary2() { return temporary2_; } + DECLARE_HYDROGEN_ACCESSOR(ClassOfTest) - private: - LOperand* temporary2_; - int true_block_id_; - int false_block_id_; + virtual void PrintDataTo(StringStream* stream); }; -class LCmpT: public LBinaryOperation<1> { +class LCmpT: public LTemplateInstruction<1, 2> { public: - LCmpT(LOperand* left, LOperand* right) : LBinaryOperation<1>(left, right) {} + LCmpT(LOperand* left, LOperand* right) { + inputs_[0] = left; + inputs_[1] = right; + } DECLARE_CONCRETE_INSTRUCTION(CmpT, "cmp-t") DECLARE_HYDROGEN_ACCESSOR(Compare) @@ -955,90 +870,78 @@ class LCmpT: public LBinaryOperation<1> { }; -class LCmpTAndBranch: public LCmpT { +class LCmpTAndBranch: public LControlInstruction<2> { public: - LCmpTAndBranch(LOperand* left, - LOperand* right, - int true_block_id, - int false_block_id) - : LCmpT(left, right), - true_block_id_(true_block_id), - false_block_id_(false_block_id) { } + LCmpTAndBranch(LOperand* left, LOperand* right) { + inputs_[0] = left; + inputs_[1] = right; + } DECLARE_CONCRETE_INSTRUCTION(CmpTAndBranch, "cmp-t-and-branch") + DECLARE_HYDROGEN_ACCESSOR(Compare) - int true_block_id() const { return true_block_id_; } - int false_block_id() const { return false_block_id_; } - - private: - int true_block_id_; - int false_block_id_; + Token::Value op() const { return hydrogen()->token(); } }; -class LInstanceOf: public LBinaryOperation<1> { +class LInstanceOf: public LTemplateInstruction<1, 2> { public: - LInstanceOf(LOperand* left, LOperand* right) - : LBinaryOperation<1>(left, right) { } + LInstanceOf(LOperand* left, LOperand* right) { + inputs_[0] = left; + inputs_[1] = right; + } DECLARE_CONCRETE_INSTRUCTION(InstanceOf, "instance-of") }; -class LInstanceOfAndBranch: public LInstanceOf { +class LInstanceOfAndBranch: public LControlInstruction<2> { public: - LInstanceOfAndBranch(LOperand* left, - LOperand* right, - int true_block_id, - int false_block_id) - : LInstanceOf(left, right), - true_block_id_(true_block_id), - false_block_id_(false_block_id) { } + LInstanceOfAndBranch(LOperand* left, LOperand* right) { + inputs_[0] = left; + inputs_[1] = right; + } DECLARE_CONCRETE_INSTRUCTION(InstanceOfAndBranch, "instance-of-and-branch") - - int true_block_id() const { return true_block_id_; } - int false_block_id() const { return false_block_id_; } - - private: - int true_block_id_; - int false_block_id_; }; -class LInstanceOfKnownGlobal: public LUnaryOperation<1> { +class LInstanceOfKnownGlobal: public LTemplateInstruction<1, 1, 1> { public: - LInstanceOfKnownGlobal(LOperand* left, LOperand* temp) - : LUnaryOperation<1>(left), temp_(temp) { } + LInstanceOfKnownGlobal(LOperand* value, LOperand* temp) { + inputs_[0] = value; + temps_[0] = temp; + } DECLARE_CONCRETE_INSTRUCTION(InstanceOfKnownGlobal, "instance-of-known-global") DECLARE_HYDROGEN_ACCESSOR(InstanceOfKnownGlobal) Handle<JSFunction> function() const { return hydrogen()->function(); } - LOperand* temp() const { return temp_; } - - private: - LOperand* temp_; }; -class LBoundsCheck: public LBinaryOperation<0> { +class LBoundsCheck: public LTemplateInstruction<0, 2, 0> { public: - LBoundsCheck(LOperand* index, LOperand* length) - : LBinaryOperation<0>(index, length) { } + LBoundsCheck(LOperand* index, LOperand* length) { + inputs_[0] = index; + inputs_[1] = length; + } - LOperand* index() const { return left(); } - LOperand* length() const { return right(); } + LOperand* index() { return inputs_[0]; } + LOperand* length() { return inputs_[1]; } DECLARE_CONCRETE_INSTRUCTION(BoundsCheck, "bounds-check") }; -class LBitI: public LBinaryOperation<1> { +class LBitI: public LTemplateInstruction<1, 2> { public: LBitI(Token::Value op, LOperand* left, LOperand* right) - : LBinaryOperation<1>(left, right), op_(op) { } + : op_(op) { + inputs_[0] = left; + inputs_[1] = right; + } Token::Value op() const { return op_; } @@ -1049,10 +952,13 @@ class LBitI: public LBinaryOperation<1> { }; -class LShiftI: public LBinaryOperation<1> { +class LShiftI: public LTemplateInstruction<1, 2> { public: LShiftI(Token::Value op, LOperand* left, LOperand* right, bool can_deopt) - : LBinaryOperation<1>(left, right), op_(op), can_deopt_(can_deopt) { } + : op_(op), can_deopt_(can_deopt) { + inputs_[0] = left; + inputs_[1] = right; + } Token::Value op() const { return op_; } @@ -1066,22 +972,25 @@ class LShiftI: public LBinaryOperation<1> { }; -class LSubI: public LBinaryOperation<1> { +class LSubI: public LTemplateInstruction<1, 2> { public: - LSubI(LOperand* left, LOperand* right) - : LBinaryOperation<1>(left, right) { } + LSubI(LOperand* left, LOperand* right) { + inputs_[0] = left; + inputs_[1] = right; + } DECLARE_CONCRETE_INSTRUCTION(SubI, "sub-i") DECLARE_HYDROGEN_ACCESSOR(Sub) }; -class LConstant: public LTemplateInstruction<1, 0, 0> { +template <int temp_count> +class LConstant: public LTemplateInstruction<1, 0, temp_count> { DECLARE_INSTRUCTION(Constant) }; -class LConstantI: public LConstant { +class LConstantI: public LConstant<0> { public: explicit LConstantI(int32_t value) : value_(value) { } int32_t value() const { return value_; } @@ -1093,9 +1002,11 @@ class LConstantI: public LConstant { }; -class LConstantD: public LConstant { +class LConstantD: public LConstant<1> { public: - explicit LConstantD(double value) : value_(value) { } + explicit LConstantD(double value, LOperand* temp) : value_(value) { + temps_[0] = temp; + } double value() const { return value_; } DECLARE_CONCRETE_INSTRUCTION(ConstantD, "constant-d") @@ -1105,7 +1016,7 @@ class LConstantD: public LConstant { }; -class LConstantT: public LConstant { +class LConstantT: public LConstant<0> { public: explicit LConstantT(Handle<Object> value) : value_(value) { } Handle<Object> value() const { return value_; } @@ -1117,31 +1028,24 @@ class LConstantT: public LConstant { }; -class LBranch: public LUnaryOperation<0> { +class LBranch: public LControlInstruction<1> { public: - LBranch(LOperand* input, int true_block_id, int false_block_id) - : LUnaryOperation<0>(input), - true_block_id_(true_block_id), - false_block_id_(false_block_id) { } + explicit LBranch(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(Branch, "branch") DECLARE_HYDROGEN_ACCESSOR(Value) virtual void PrintDataTo(StringStream* stream); - virtual bool IsControl() const { return true; } - - int true_block_id() const { return true_block_id_; } - int false_block_id() const { return false_block_id_; } - - private: - int true_block_id_; - int false_block_id_; }; -class LCmpMapAndBranch: public LUnaryOperation<0> { +class LCmpMapAndBranch: public LTemplateInstruction<0, 1> { public: - explicit LCmpMapAndBranch(LOperand* value) : LUnaryOperation<0>(value) { } + explicit LCmpMapAndBranch(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(CmpMapAndBranch, "cmp-map-and-branch") DECLARE_HYDROGEN_ACCESSOR(CompareMapAndBranch) @@ -1158,79 +1062,91 @@ class LCmpMapAndBranch: public LUnaryOperation<0> { }; -class LJSArrayLength: public LUnaryOperation<1> { +class LJSArrayLength: public LTemplateInstruction<1, 1> { public: - explicit LJSArrayLength(LOperand* input) : LUnaryOperation<1>(input) { } + explicit LJSArrayLength(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(JSArrayLength, "js-array-length") DECLARE_HYDROGEN_ACCESSOR(JSArrayLength) }; -class LFixedArrayLength: public LUnaryOperation<1> { +class LFixedArrayLength: public LTemplateInstruction<1, 1> { public: - explicit LFixedArrayLength(LOperand* input) : LUnaryOperation<1>(input) { } + explicit LFixedArrayLength(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(FixedArrayLength, "fixed-array-length") DECLARE_HYDROGEN_ACCESSOR(FixedArrayLength) }; -class LValueOf: public LUnaryOperation<1> { +class LValueOf: public LTemplateInstruction<1, 1, 1> { public: - LValueOf(LOperand* input, LOperand* temporary) - : LUnaryOperation<1>(input), temporary_(temporary) { } - - LOperand* temporary() const { return temporary_; } + LValueOf(LOperand* value, LOperand* temp) { + inputs_[0] = value; + temps_[0] = temp; + } DECLARE_CONCRETE_INSTRUCTION(ValueOf, "value-of") DECLARE_HYDROGEN_ACCESSOR(ValueOf) - - private: - LOperand* temporary_; }; -class LThrow: public LUnaryOperation<0> { +class LThrow: public LTemplateInstruction<0, 1> { public: - explicit LThrow(LOperand* value) : LUnaryOperation<0>(value) { } + explicit LThrow(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(Throw, "throw") }; -class LBitNotI: public LUnaryOperation<1> { +class LBitNotI: public LTemplateInstruction<1, 1> { public: - explicit LBitNotI(LOperand* input) : LUnaryOperation<1>(input) { } + explicit LBitNotI(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(BitNotI, "bit-not-i") }; -class LAddI: public LBinaryOperation<1> { +class LAddI: public LTemplateInstruction<1, 2> { public: - LAddI(LOperand* left, LOperand* right) - : LBinaryOperation<1>(left, right) { } + LAddI(LOperand* left, LOperand* right) { + inputs_[0] = left; + inputs_[1] = right; + } DECLARE_CONCRETE_INSTRUCTION(AddI, "add-i") DECLARE_HYDROGEN_ACCESSOR(Add) }; -class LPower: public LBinaryOperation<1> { +class LPower: public LTemplateInstruction<1, 2> { public: - LPower(LOperand* left, LOperand* right) - : LBinaryOperation<1>(left, right) { } + LPower(LOperand* left, LOperand* right) { + inputs_[0] = left; + inputs_[1] = right; + } DECLARE_CONCRETE_INSTRUCTION(Power, "power") DECLARE_HYDROGEN_ACCESSOR(Power) }; -class LArithmeticD: public LBinaryOperation<1> { +class LArithmeticD: public LTemplateInstruction<1, 2> { public: LArithmeticD(Token::Value op, LOperand* left, LOperand* right) - : LBinaryOperation<1>(left, right), op_(op) { } + : op_(op) { + inputs_[0] = left; + inputs_[1] = right; + } Token::Value op() const { return op_; } @@ -1242,10 +1158,13 @@ class LArithmeticD: public LBinaryOperation<1> { }; -class LArithmeticT: public LBinaryOperation<1> { +class LArithmeticT: public LTemplateInstruction<1, 2> { public: LArithmeticT(Token::Value op, LOperand* left, LOperand* right) - : LBinaryOperation<1>(left, right), op_(op) { } + : op_(op) { + inputs_[0] = left; + inputs_[1] = right; + } virtual void CompileToNative(LCodeGen* generator); virtual const char* Mnemonic() const; @@ -1257,81 +1176,91 @@ class LArithmeticT: public LBinaryOperation<1> { }; -class LReturn: public LUnaryOperation<0> { +class LReturn: public LTemplateInstruction<0, 1> { public: - explicit LReturn(LOperand* use) : LUnaryOperation<0>(use) { } + explicit LReturn(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(Return, "return") }; -class LLoadNamedField: public LUnaryOperation<1> { +class LLoadNamedField: public LTemplateInstruction<1, 1> { public: - explicit LLoadNamedField(LOperand* object) : LUnaryOperation<1>(object) { } + explicit LLoadNamedField(LOperand* object) { + inputs_[0] = object; + } DECLARE_CONCRETE_INSTRUCTION(LoadNamedField, "load-named-field") DECLARE_HYDROGEN_ACCESSOR(LoadNamedField) }; -class LLoadNamedGeneric: public LUnaryOperation<1> { +class LLoadNamedGeneric: public LTemplateInstruction<1, 1> { public: - explicit LLoadNamedGeneric(LOperand* object) : LUnaryOperation<1>(object) { } + explicit LLoadNamedGeneric(LOperand* object) { + inputs_[0] = object; + } DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric, "load-named-generic") DECLARE_HYDROGEN_ACCESSOR(LoadNamedGeneric) - LOperand* object() const { return input(); } + LOperand* object() { return inputs_[0]; } Handle<Object> name() const { return hydrogen()->name(); } }; -class LLoadFunctionPrototype: public LUnaryOperation<1> { +class LLoadFunctionPrototype: public LTemplateInstruction<1, 1, 1> { public: - LLoadFunctionPrototype(LOperand* function, LOperand* temporary) - : LUnaryOperation<1>(function), temporary_(temporary) { } + LLoadFunctionPrototype(LOperand* function, LOperand* temp) { + inputs_[0] = function; + temps_[0] = temp; + } DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype, "load-function-prototype") DECLARE_HYDROGEN_ACCESSOR(LoadFunctionPrototype) - LOperand* function() const { return input(); } - LOperand* temporary() const { return temporary_; } - - private: - LOperand* temporary_; + LOperand* function() { return inputs_[0]; } }; -class LLoadElements: public LUnaryOperation<1> { +class LLoadElements: public LTemplateInstruction<1, 1> { public: - explicit LLoadElements(LOperand* obj) : LUnaryOperation<1>(obj) { } + explicit LLoadElements(LOperand* object) { + inputs_[0] = object; + } DECLARE_CONCRETE_INSTRUCTION(LoadElements, "load-elements") }; -class LLoadKeyedFastElement: public LBinaryOperation<1> { +class LLoadKeyedFastElement: public LTemplateInstruction<1, 2> { public: - LLoadKeyedFastElement(LOperand* elements, LOperand* key) - : LBinaryOperation<1>(elements, key) { } + LLoadKeyedFastElement(LOperand* elements, LOperand* key) { + inputs_[0] = elements; + inputs_[1] = key; + } DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastElement, "load-keyed-fast-element") DECLARE_HYDROGEN_ACCESSOR(LoadKeyedFastElement) - LOperand* elements() const { return left(); } - LOperand* key() const { return right(); } + LOperand* elements() { return inputs_[0]; } + LOperand* key() { return inputs_[1]; } }; -class LLoadKeyedGeneric: public LBinaryOperation<1> { +class LLoadKeyedGeneric: public LTemplateInstruction<1, 2> { public: - LLoadKeyedGeneric(LOperand* obj, LOperand* key) - : LBinaryOperation<1>(obj, key) { } + LLoadKeyedGeneric(LOperand* obj, LOperand* key) { + inputs_[0] = obj; + inputs_[1] = key; + } DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric, "load-keyed-generic") - LOperand* object() const { return left(); } - LOperand* key() const { return right(); } + LOperand* object() { return inputs_[0]; } + LOperand* key() { return inputs_[1]; } }; @@ -1342,9 +1271,11 @@ class LLoadGlobal: public LTemplateInstruction<1, 0, 0> { }; -class LStoreGlobal: public LUnaryOperation<0> { +class LStoreGlobal: public LTemplateInstruction<0, 1> { public: - explicit LStoreGlobal(LOperand* value) : LUnaryOperation<0>(value) {} + explicit LStoreGlobal(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(StoreGlobal, "store-global") DECLARE_HYDROGEN_ACCESSOR(StoreGlobal) @@ -1356,18 +1287,18 @@ class LLoadContextSlot: public LTemplateInstruction<1, 0, 0> { DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot, "load-context-slot") DECLARE_HYDROGEN_ACCESSOR(LoadContextSlot) - int context_chain_length() const { - return hydrogen()->context_chain_length(); - } - int slot_index() const { return hydrogen()->slot_index(); } + int context_chain_length() { return hydrogen()->context_chain_length(); } + int slot_index() { return hydrogen()->slot_index(); } virtual void PrintDataTo(StringStream* stream); }; -class LPushArgument: public LUnaryOperation<0> { +class LPushArgument: public LTemplateInstruction<0, 1> { public: - explicit LPushArgument(LOperand* argument) : LUnaryOperation<0>(argument) {} + explicit LPushArgument(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(PushArgument, "push-argument") }; @@ -1397,8 +1328,12 @@ class LCallConstantFunction: public LTemplateInstruction<1, 0, 0> { }; -class LCallKeyed: public LTemplateInstruction<1, 0, 0> { +class LCallKeyed: public LTemplateInstruction<1, 0, 1> { public: + explicit LCallKeyed(LOperand* temp) { + temps_[0] = temp; + } + DECLARE_CONCRETE_INSTRUCTION(CallKeyed, "call-keyed") DECLARE_HYDROGEN_ACCESSOR(CallKeyed) @@ -1453,9 +1388,11 @@ class LCallKnownGlobal: public LTemplateInstruction<1, 0, 0> { }; -class LCallNew: public LUnaryOperation<1> { +class LCallNew: public LTemplateInstruction<1, 1> { public: - explicit LCallNew(LOperand* constructor) : LUnaryOperation<1>(constructor) { } + explicit LCallNew(LOperand* constructor) { + inputs_[0] = constructor; + } DECLARE_CONCRETE_INSTRUCTION(CallNew, "call-new") DECLARE_HYDROGEN_ACCESSOR(CallNew) @@ -1476,90 +1413,93 @@ class LCallRuntime: public LTemplateInstruction<1, 0, 0> { }; -class LInteger32ToDouble: public LUnaryOperation<1> { +class LInteger32ToDouble: public LTemplateInstruction<1, 1> { public: - explicit LInteger32ToDouble(LOperand* use) : LUnaryOperation<1>(use) { } + explicit LInteger32ToDouble(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(Integer32ToDouble, "int32-to-double") }; -class LNumberTagI: public LUnaryOperation<1> { +class LNumberTagI: public LTemplateInstruction<1, 1> { public: - explicit LNumberTagI(LOperand* use) : LUnaryOperation<1>(use) { } + explicit LNumberTagI(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(NumberTagI, "number-tag-i") }; -class LNumberTagD: public LUnaryOperation<1> { +class LNumberTagD: public LTemplateInstruction<1, 1, 1> { public: - explicit LNumberTagD(LOperand* value, LOperand* temp) - : LUnaryOperation<1>(value), temp_(temp) { } + explicit LNumberTagD(LOperand* value, LOperand* temp) { + inputs_[0] = value; + temps_[0] = temp; + } DECLARE_CONCRETE_INSTRUCTION(NumberTagD, "number-tag-d") - - LOperand* temp() const { return temp_; } - - private: - LOperand* temp_; }; // Sometimes truncating conversion from a tagged value to an int32. -class LDoubleToI: public LUnaryOperation<1> { +class LDoubleToI: public LTemplateInstruction<1, 1, 1> { public: - LDoubleToI(LOperand* value, LOperand* temporary) - : LUnaryOperation<1>(value), temporary_(temporary) { } + LDoubleToI(LOperand* value, LOperand* temp) { + inputs_[0] = value; + temps_[0] = temp; + } DECLARE_CONCRETE_INSTRUCTION(DoubleToI, "double-to-i") DECLARE_HYDROGEN_ACCESSOR(Change) bool truncating() { return hydrogen()->CanTruncateToInt32(); } - LOperand* temporary() const { return temporary_; } - - private: - LOperand* temporary_; }; // Truncating conversion from a tagged value to an int32. -class LTaggedToI: public LUnaryOperation<1> { +class LTaggedToI: public LTemplateInstruction<1, 1, 1> { public: - LTaggedToI(LOperand* value, LOperand* temp) - : LUnaryOperation<1>(value), temp_(temp) { } + LTaggedToI(LOperand* value, LOperand* temp) { + inputs_[0] = value; + temps_[0] = temp; + } DECLARE_CONCRETE_INSTRUCTION(TaggedToI, "tagged-to-i") DECLARE_HYDROGEN_ACCESSOR(Change) bool truncating() { return hydrogen()->CanTruncateToInt32(); } - LOperand* temp() const { return temp_; } - - private: - LOperand* temp_; }; -class LSmiTag: public LUnaryOperation<1> { +class LSmiTag: public LTemplateInstruction<1, 1> { public: - explicit LSmiTag(LOperand* use) : LUnaryOperation<1>(use) { } + explicit LSmiTag(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(SmiTag, "smi-tag") }; -class LNumberUntagD: public LUnaryOperation<1> { +class LNumberUntagD: public LTemplateInstruction<1, 1> { public: - explicit LNumberUntagD(LOperand* value) : LUnaryOperation<1>(value) { } + explicit LNumberUntagD(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(NumberUntagD, "double-untag") }; -class LSmiUntag: public LUnaryOperation<1> { +class LSmiUntag: public LTemplateInstruction<1, 1> { public: - LSmiUntag(LOperand* use, bool needs_check) - : LUnaryOperation<1>(use), needs_check_(needs_check) { } + LSmiUntag(LOperand* value, bool needs_check) + : needs_check_(needs_check) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(SmiUntag, "smi-untag") @@ -1570,11 +1510,11 @@ class LSmiUntag: public LUnaryOperation<1> { }; -class LStoreNamed: public LTemplateInstruction<0, 2, 0> { +class LStoreNamed: public LTemplateInstruction<0, 2, 1> { public: LStoreNamed(LOperand* obj, LOperand* val) { - this->SetInputAt(0, obj); - this->SetInputAt(1, val); + inputs_[0] = obj; + inputs_[1] = val; } DECLARE_INSTRUCTION(StoreNamed) @@ -1582,8 +1522,8 @@ class LStoreNamed: public LTemplateInstruction<0, 2, 0> { virtual void PrintDataTo(StringStream* stream); - LOperand* object() const { return this->InputAt(0); } - LOperand* value() const { return this->InputAt(1); } + LOperand* object() { return inputs_[0]; } + LOperand* value() { return inputs_[1]; } Handle<Object> name() const { return hydrogen()->name(); } }; @@ -1591,7 +1531,9 @@ class LStoreNamed: public LTemplateInstruction<0, 2, 0> { class LStoreNamedField: public LStoreNamed { public: LStoreNamedField(LOperand* obj, LOperand* val, LOperand* temp) - : LStoreNamed(obj, val), temp_(temp) { } + : LStoreNamed(obj, val) { + temps_[0] = temp; + } DECLARE_CONCRETE_INSTRUCTION(StoreNamedField, "store-named-field") DECLARE_HYDROGEN_ACCESSOR(StoreNamedField) @@ -1600,11 +1542,6 @@ class LStoreNamedField: public LStoreNamed { int offset() { return hydrogen()->offset(); } bool needs_write_barrier() { return hydrogen()->NeedsWriteBarrier(); } Handle<Map> transition() const { return hydrogen()->transition(); } - - LOperand* temp() { return temp_; } - - private: - LOperand* temp_; }; @@ -1621,18 +1558,18 @@ class LStoreNamedGeneric: public LStoreNamed { class LStoreKeyed: public LTemplateInstruction<0, 3, 0> { public: LStoreKeyed(LOperand* obj, LOperand* key, LOperand* val) { - this->SetInputAt(0, obj); - this->SetInputAt(1, key); - this->SetInputAt(2, val); + inputs_[0] = obj; + inputs_[1] = key; + inputs_[2] = val; } DECLARE_INSTRUCTION(StoreKeyed) virtual void PrintDataTo(StringStream* stream); - LOperand* object() const { return this->InputAt(0); } - LOperand* key() const { return this->InputAt(1); } - LOperand* value() const { return this->InputAt(2); } + LOperand* object() { return inputs_[0]; } + LOperand* key() { return inputs_[1]; } + LOperand* value() { return inputs_[2]; } }; @@ -1656,60 +1593,60 @@ class LStoreKeyedGeneric: public LStoreKeyed { }; -class LCheckFunction: public LUnaryOperation<0> { +class LCheckFunction: public LTemplateInstruction<0, 1> { public: - explicit LCheckFunction(LOperand* use) : LUnaryOperation<0>(use) { } + explicit LCheckFunction(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(CheckFunction, "check-function") DECLARE_HYDROGEN_ACCESSOR(CheckFunction) }; -class LCheckInstanceType: public LUnaryOperation<0> { +class LCheckInstanceType: public LTemplateInstruction<0, 1, 1> { public: - LCheckInstanceType(LOperand* use, LOperand* temp) - : LUnaryOperation<0>(use), temp_(temp) { } + LCheckInstanceType(LOperand* value, LOperand* temp) { + inputs_[0] = value; + temps_[0] = temp; + } DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType, "check-instance-type") DECLARE_HYDROGEN_ACCESSOR(CheckInstanceType) - - LOperand* temp() const { return temp_; } - - private: - LOperand* temp_; }; -class LCheckMap: public LUnaryOperation<0> { +class LCheckMap: public LTemplateInstruction<0, 1> { public: - explicit LCheckMap(LOperand* use) : LUnaryOperation<0>(use) { } + explicit LCheckMap(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(CheckMap, "check-map") DECLARE_HYDROGEN_ACCESSOR(CheckMap) }; -class LCheckPrototypeMaps: public LTemplateInstruction<0, 0, 0> { +class LCheckPrototypeMaps: public LTemplateInstruction<0, 0, 1> { public: - explicit LCheckPrototypeMaps(LOperand* temp) : temp_(temp) { } + explicit LCheckPrototypeMaps(LOperand* temp) { + temps_[0] = temp; + } DECLARE_CONCRETE_INSTRUCTION(CheckPrototypeMaps, "check-prototype-maps") DECLARE_HYDROGEN_ACCESSOR(CheckPrototypeMaps) Handle<JSObject> prototype() const { return hydrogen()->prototype(); } Handle<JSObject> holder() const { return hydrogen()->holder(); } - - LOperand* temp() const { return temp_; } - - private: - LOperand* temp_; }; -class LCheckSmi: public LUnaryOperation<0> { +class LCheckSmi: public LTemplateInstruction<0, 1> { public: - LCheckSmi(LOperand* use, Condition condition) - : LUnaryOperation<0>(use), condition_(condition) { } + LCheckSmi(LOperand* value, Condition condition) + : condition_(condition) { + inputs_[0] = value; + } Condition condition() const { return condition_; } @@ -1723,27 +1660,21 @@ class LCheckSmi: public LUnaryOperation<0> { }; -class LMaterializedLiteral: public LTemplateInstruction<1, 0, 0> { - public: - DECLARE_INSTRUCTION(MaterializedLiteral) -}; - - -class LArrayLiteral: public LMaterializedLiteral { +class LArrayLiteral: public LTemplateInstruction<1, 0, 0> { public: DECLARE_CONCRETE_INSTRUCTION(ArrayLiteral, "array-literal") DECLARE_HYDROGEN_ACCESSOR(ArrayLiteral) }; -class LObjectLiteral: public LMaterializedLiteral { +class LObjectLiteral: public LTemplateInstruction<1, 0, 0> { public: DECLARE_CONCRETE_INSTRUCTION(ObjectLiteral, "object-literal") DECLARE_HYDROGEN_ACCESSOR(ObjectLiteral) }; -class LRegExpLiteral: public LMaterializedLiteral { +class LRegExpLiteral: public LTemplateInstruction<1, 0, 0> { public: DECLARE_CONCRETE_INSTRUCTION(RegExpLiteral, "regexp-literal") DECLARE_HYDROGEN_ACCESSOR(RegExpLiteral) @@ -1759,58 +1690,57 @@ class LFunctionLiteral: public LTemplateInstruction<1, 0, 0> { }; -class LTypeof: public LUnaryOperation<1> { +class LTypeof: public LTemplateInstruction<1, 1> { public: - explicit LTypeof(LOperand* input) : LUnaryOperation<1>(input) { } + explicit LTypeof(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(Typeof, "typeof") }; -class LTypeofIs: public LUnaryOperation<1> { +class LTypeofIs: public LTemplateInstruction<1, 1> { public: - explicit LTypeofIs(LOperand* input) : LUnaryOperation<1>(input) { } - virtual void PrintDataTo(StringStream* stream); + explicit LTypeofIs(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(TypeofIs, "typeof-is") DECLARE_HYDROGEN_ACCESSOR(TypeofIs) Handle<String> type_literal() { return hydrogen()->type_literal(); } + + virtual void PrintDataTo(StringStream* stream); }; -class LTypeofIsAndBranch: public LTypeofIs { +class LTypeofIsAndBranch: public LControlInstruction<1> { public: - LTypeofIsAndBranch(LOperand* value, - int true_block_id, - int false_block_id) - : LTypeofIs(value), - true_block_id_(true_block_id), - false_block_id_(false_block_id) { } + explicit LTypeofIsAndBranch(LOperand* value) { + inputs_[0] = value; + } DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch, "typeof-is-and-branch") + DECLARE_HYDROGEN_ACCESSOR(TypeofIs) - virtual void PrintDataTo(StringStream* stream); - virtual bool IsControl() const { return true; } - - int true_block_id() const { return true_block_id_; } - int false_block_id() const { return false_block_id_; } + Handle<String> type_literal() { return hydrogen()->type_literal(); } - private: - int true_block_id_; - int false_block_id_; + virtual void PrintDataTo(StringStream* stream); }; -class LDeleteProperty: public LBinaryOperation<1> { +class LDeleteProperty: public LTemplateInstruction<1, 2> { public: - LDeleteProperty(LOperand* obj, LOperand* key) - : LBinaryOperation<1>(obj, key) { } + LDeleteProperty(LOperand* obj, LOperand* key) { + inputs_[0] = obj; + inputs_[1] = key; + } DECLARE_CONCRETE_INSTRUCTION(DeleteProperty, "delete-property") - LOperand* object() const { return left(); } - LOperand* key() const { return right(); } + LOperand* object() { return inputs_[0]; } + LOperand* key() { return inputs_[1]; } }; @@ -1954,9 +1884,10 @@ class LChunkBuilder BASE_EMBEDDED { LUnallocated* ToUnallocated(XMMRegister reg); // Methods for setting up define-use relationships. - LOperand* Use(HValue* value, LUnallocated* operand); - LOperand* UseFixed(HValue* value, Register fixed_register); - LOperand* UseFixedDouble(HValue* value, XMMRegister fixed_register); + MUST_USE_RESULT LOperand* Use(HValue* value, LUnallocated* operand); + MUST_USE_RESULT LOperand* UseFixed(HValue* value, Register fixed_register); + MUST_USE_RESULT LOperand* UseFixedDouble(HValue* value, + XMMRegister fixed_register); // A value that is guaranteed to be allocated to a register. // Operand created by UseRegister is guaranteed to be live until the end of @@ -1966,17 +1897,32 @@ class LChunkBuilder BASE_EMBEDDED { // instruction start. Register allocator is free to assign the same register // to some other operand used inside instruction (i.e. temporary or // output). - LOperand* UseRegister(HValue* value); - LOperand* UseRegisterAtStart(HValue* value); + MUST_USE_RESULT LOperand* UseRegister(HValue* value); + MUST_USE_RESULT LOperand* UseRegisterAtStart(HValue* value); // A value in a register that may be trashed. - LOperand* UseTempRegister(HValue* value); - LOperand* Use(HValue* value); - LOperand* UseAtStart(HValue* value); - LOperand* UseOrConstant(HValue* value); - LOperand* UseOrConstantAtStart(HValue* value); - LOperand* UseRegisterOrConstant(HValue* value); - LOperand* UseRegisterOrConstantAtStart(HValue* value); + MUST_USE_RESULT LOperand* UseTempRegister(HValue* value); + + // An operand value in a register or stack slot. + MUST_USE_RESULT LOperand* Use(HValue* value); + MUST_USE_RESULT LOperand* UseAtStart(HValue* value); + + // An operand value in a register, stack slot or a constant operand. + MUST_USE_RESULT LOperand* UseOrConstant(HValue* value); + MUST_USE_RESULT LOperand* UseOrConstantAtStart(HValue* value); + + // An operand value in a register or a constant operand. + MUST_USE_RESULT LOperand* UseRegisterOrConstant(HValue* value); + MUST_USE_RESULT LOperand* UseRegisterOrConstantAtStart(HValue* value); + + // Temporary operand that must be in a register. + MUST_USE_RESULT LUnallocated* TempRegister(); + MUST_USE_RESULT LOperand* FixedTemp(Register reg); + MUST_USE_RESULT LOperand* FixedTemp(XMMRegister reg); + + // An operand value in register, stack slot or a constant operand. + // Will not be moved to a register even if one is freely available. + LOperand* UseAny(HValue* value); // Methods for setting up define-use relationships. // Return the same instruction that they are passed. @@ -2018,11 +1964,6 @@ class LChunkBuilder BASE_EMBEDDED { LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env); - // Temporary operand that must be in a register. - LUnallocated* TempRegister(); - LOperand* FixedTemp(Register reg); - LOperand* FixedTemp(XMMRegister reg); - void VisitInstruction(HInstruction* current); void DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block); @@ -2052,6 +1993,6 @@ class LChunkBuilder BASE_EMBEDDED { #undef DECLARE_INSTRUCTION #undef DECLARE_CONCRETE_INSTRUCTION -} } // namespace v8::internal +} } // namespace v8::int #endif // V8_X64_LITHIUM_X64_H_ diff --git a/deps/v8/src/x64/stub-cache-x64.cc b/deps/v8/src/x64/stub-cache-x64.cc index 57cba14212..8c1b5794d0 100644 --- a/deps/v8/src/x64/stub-cache-x64.cc +++ b/deps/v8/src/x64/stub-cache-x64.cc @@ -1327,8 +1327,8 @@ void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell, MaybeObject* CallStubCompiler::GenerateMissBranch() { - MaybeObject* maybe_obj = - StubCache::ComputeCallMiss(arguments().immediate(), kind_); + MaybeObject* maybe_obj = StubCache::ComputeCallMiss(arguments().immediate(), + kind_); Object* obj; if (!maybe_obj->ToObject(&obj)) return maybe_obj; __ Jump(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET); @@ -1660,9 +1660,15 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall( const int argc = arguments().immediate(); Label miss; + Label name_miss; Label index_out_of_range; + Label* index_out_of_range_label = &index_out_of_range; - GenerateNameCheck(name, &miss); + if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) { + index_out_of_range_label = &miss; + } + + GenerateNameCheck(name, &name_miss); // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype(masm(), @@ -1690,7 +1696,7 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall( result, &miss, // When not a string. &miss, // When not a number. - &index_out_of_range, + index_out_of_range_label, STRING_INDEX_IS_NUMBER); char_code_at_generator.GenerateFast(masm()); __ ret((argc + 1) * kPointerSize); @@ -1698,11 +1704,16 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall( StubRuntimeCallHelper call_helper; char_code_at_generator.GenerateSlow(masm(), call_helper); - __ bind(&index_out_of_range); - __ LoadRoot(rax, Heap::kNanValueRootIndex); - __ ret((argc + 1) * kPointerSize); + if (index_out_of_range.is_linked()) { + __ bind(&index_out_of_range); + __ LoadRoot(rax, Heap::kNanValueRootIndex); + __ ret((argc + 1) * kPointerSize); + } __ bind(&miss); + // Restore function name in rcx. + __ Move(rcx, Handle<String>(name)); + __ bind(&name_miss); Object* obj; { MaybeObject* maybe_obj = GenerateMissBranch(); if (!maybe_obj->ToObject(&obj)) return maybe_obj; @@ -1733,9 +1744,15 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall( const int argc = arguments().immediate(); Label miss; + Label name_miss; Label index_out_of_range; + Label* index_out_of_range_label = &index_out_of_range; - GenerateNameCheck(name, &miss); + if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) { + index_out_of_range_label = &miss; + } + + GenerateNameCheck(name, &name_miss); // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype(masm(), @@ -1765,7 +1782,7 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall( result, &miss, // When not a string. &miss, // When not a number. - &index_out_of_range, + index_out_of_range_label, STRING_INDEX_IS_NUMBER); char_at_generator.GenerateFast(masm()); __ ret((argc + 1) * kPointerSize); @@ -1773,11 +1790,16 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall( StubRuntimeCallHelper call_helper; char_at_generator.GenerateSlow(masm(), call_helper); - __ bind(&index_out_of_range); - __ LoadRoot(rax, Heap::kEmptyStringRootIndex); - __ ret((argc + 1) * kPointerSize); + if (index_out_of_range.is_linked()) { + __ bind(&index_out_of_range); + __ LoadRoot(rax, Heap::kEmptyStringRootIndex); + __ ret((argc + 1) * kPointerSize); + } __ bind(&miss); + // Restore function name in rcx. + __ Move(rcx, Handle<String>(name)); + __ bind(&name_miss); Object* obj; { MaybeObject* maybe_obj = GenerateMissBranch(); if (!maybe_obj->ToObject(&obj)) return maybe_obj; @@ -2262,17 +2284,24 @@ MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object, __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx); } - // Setup the context (function already in edi). + // Setup the context (function already in rdi). __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); // Jump to the cached code (tail call). __ IncrementCounter(&Counters::call_global_inline, 1); ASSERT(function->is_compiled()); - Handle<Code> code(function->code()); ParameterCount expected(function->shared()->formal_parameter_count()); - __ InvokeCode(code, expected, arguments(), - RelocInfo::CODE_TARGET, JUMP_FUNCTION); - + if (V8::UseCrankshaft()) { + // TODO(kasperl): For now, we always call indirectly through the + // code field in the function to allow recompilation to take effect + // without changing any of the call sites. + __ movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset)); + __ InvokeCode(rdx, expected, arguments(), JUMP_FUNCTION); + } else { + Handle<Code> code(function->code()); + __ InvokeCode(code, expected, arguments(), + RelocInfo::CODE_TARGET, JUMP_FUNCTION); + } // Handle call cache miss. __ bind(&miss); __ IncrementCounter(&Counters::call_global_inline_miss, 1); |