summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--deps/v8/ChangeLog10
-rw-r--r--deps/v8/LICENSE2
-rw-r--r--deps/v8/SConstruct20
-rwxr-xr-xdeps/v8/src/SConscript3
-rw-r--r--deps/v8/src/arm/assembler-arm.cc8
-rw-r--r--deps/v8/src/arm/assembler-arm.h6
-rw-r--r--deps/v8/src/arm/ic-arm.cc8
-rw-r--r--deps/v8/src/arm/lithium-arm.cc13
-rw-r--r--deps/v8/src/arm/lithium-arm.h12
-rw-r--r--deps/v8/src/arm/lithium-codegen-arm.cc33
-rw-r--r--deps/v8/src/arm/stub-cache-arm.cc54
-rw-r--r--deps/v8/src/assembler.cc10
-rw-r--r--deps/v8/src/assembler.h28
-rw-r--r--deps/v8/src/builtins.cc9
-rw-r--r--deps/v8/src/code-stubs.cc2
-rw-r--r--deps/v8/src/codegen.cc11
-rwxr-xr-xdeps/v8/src/compiler.cc12
-rw-r--r--deps/v8/src/compiler.h10
-rw-r--r--deps/v8/src/flag-definitions.h8
-rw-r--r--deps/v8/src/frames.cc1
-rw-r--r--deps/v8/src/full-codegen.cc11
-rw-r--r--deps/v8/src/gdb-jit.cc1170
-rw-r--r--deps/v8/src/gdb-jit.h136
-rw-r--r--deps/v8/src/hydrogen-instructions.cc3
-rw-r--r--deps/v8/src/hydrogen-instructions.h18
-rw-r--r--deps/v8/src/hydrogen.cc13
-rw-r--r--deps/v8/src/hydrogen.h3
-rw-r--r--deps/v8/src/ia32/ic-ia32.cc12
-rw-r--r--deps/v8/src/ia32/lithium-codegen-ia32.cc463
-rw-r--r--deps/v8/src/ia32/lithium-codegen-ia32.h44
-rw-r--r--deps/v8/src/ia32/lithium-gap-resolver-ia32.cc461
-rw-r--r--deps/v8/src/ia32/lithium-gap-resolver-ia32.h110
-rw-r--r--deps/v8/src/ia32/lithium-ia32.cc145
-rw-r--r--deps/v8/src/ia32/lithium-ia32.h1064
-rw-r--r--deps/v8/src/ia32/stub-cache-ia32.cc49
-rw-r--r--deps/v8/src/ic.cc309
-rw-r--r--deps/v8/src/ic.h13
-rw-r--r--deps/v8/src/inspector.cc63
-rw-r--r--deps/v8/src/inspector.h62
-rw-r--r--deps/v8/src/lithium-allocator.cc12
-rw-r--r--deps/v8/src/lithium-allocator.h48
-rw-r--r--deps/v8/src/lithium.cc19
-rw-r--r--deps/v8/src/lithium.h3
-rw-r--r--deps/v8/src/mark-compact.cc12
-rw-r--r--deps/v8/src/objects-debug.cc13
-rw-r--r--deps/v8/src/objects-inl.h49
-rw-r--r--deps/v8/src/objects.h162
-rw-r--r--deps/v8/src/platform-win32.cc2
-rw-r--r--deps/v8/src/preparse-data.h2
-rw-r--r--deps/v8/src/runtime-profiler.cc1
-rw-r--r--deps/v8/src/runtime.cc112
-rw-r--r--deps/v8/src/scopeinfo.cc5
-rw-r--r--deps/v8/src/scopes.cc62
-rw-r--r--deps/v8/src/stub-cache.cc171
-rw-r--r--deps/v8/src/stub-cache.h18
-rw-r--r--deps/v8/src/third_party/strongtalk/LICENSE29
-rw-r--r--deps/v8/src/third_party/strongtalk/README.chromium18
-rw-r--r--deps/v8/src/type-info.cc15
-rw-r--r--deps/v8/src/type-info.h6
-rw-r--r--deps/v8/src/version.cc2
-rw-r--r--deps/v8/src/x64/assembler-x64.cc6
-rw-r--r--deps/v8/src/x64/assembler-x64.h2
-rw-r--r--deps/v8/src/x64/code-stubs-x64.h1
-rw-r--r--deps/v8/src/x64/deoptimizer-x64.cc6
-rw-r--r--deps/v8/src/x64/frames-x64.h2
-rw-r--r--deps/v8/src/x64/ic-x64.cc8
-rw-r--r--deps/v8/src/x64/lithium-codegen-x64.cc144
-rw-r--r--deps/v8/src/x64/lithium-x64.cc110
-rw-r--r--deps/v8/src/x64/lithium-x64.h1075
-rw-r--r--deps/v8/src/x64/stub-cache-x64.cc63
-rw-r--r--deps/v8/test/cctest/cctest.status10
-rw-r--r--deps/v8/test/mjsunit/compiler/regress-serialized-slots.js61
-rw-r--r--deps/v8/test/mjsunit/mjsunit.status3
-rw-r--r--deps/v8/test/mozilla/mozilla.status13
-rw-r--r--deps/v8/tools/gyp/v8.gyp6
75 files changed, 4604 insertions, 2076 deletions
diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog
index 6c4bf4276..c9ff2978d 100644
--- a/deps/v8/ChangeLog
+++ b/deps/v8/ChangeLog
@@ -1,7 +1,15 @@
+2011-01-19: Version 3.0.9
+
+ Added basic GDB JIT Interface integration.
+
+ Make invalid break/continue statements a syntax error instead of a
+ runtime error.
+
+
2011-01-17: Version 3.0.8
Exposed heap size limit to the heap statistics gathered by
- the GetHeapStatistics API.
+ the GetHeapStatistics API.
Wrapped external pointers more carefully (issue 1037).
diff --git a/deps/v8/LICENSE b/deps/v8/LICENSE
index c1fcb1a14..e435050e9 100644
--- a/deps/v8/LICENSE
+++ b/deps/v8/LICENSE
@@ -24,7 +24,7 @@ are:
These libraries have their own licenses; we recommend you read them,
as their terms may differ from the terms below.
-Copyright 2006-2009, Google Inc. All rights reserved.
+Copyright 2006-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:
diff --git a/deps/v8/SConstruct b/deps/v8/SConstruct
index e10f8117c..50babbae8 100644
--- a/deps/v8/SConstruct
+++ b/deps/v8/SConstruct
@@ -124,12 +124,15 @@ LIBRARY_FLAGS = {
},
'debuggersupport:on': {
'CPPDEFINES': ['ENABLE_DEBUGGER_SUPPORT'],
+ },
+ 'inspector:on': {
+ 'CPPDEFINES': ['INSPECTOR'],
}
},
'gcc': {
'all': {
'CCFLAGS': ['$DIALECTFLAGS', '$WARNINGFLAGS'],
- 'CXXFLAGS': ['$CCFLAGS', '-fno-rtti', '-fno-exceptions', '-fno-builtin-memcpy'],
+ 'CXXFLAGS': ['$CCFLAGS', '-fno-rtti', '-fno-exceptions'],
},
'visibility:hidden': {
# Use visibility=default to disable this.
@@ -229,6 +232,9 @@ LIBRARY_FLAGS = {
},
'prof:oprofile': {
'CPPDEFINES': ['ENABLE_OPROFILE_AGENT']
+ },
+ 'gdbjit:on': {
+ 'CPPDEFINES': ['ENABLE_GDB_JIT_INTERFACE']
}
},
'msvc': {
@@ -705,6 +711,11 @@ SIMPLE_OPTIONS = {
'default': 'off',
'help': 'enable profiling of build target'
},
+ 'gdbjit': {
+ 'values': ['on', 'off'],
+ 'default': 'off',
+ 'help': 'enable GDB JIT interface'
+ },
'library': {
'values': ['static', 'shared'],
'default': 'static',
@@ -735,6 +746,11 @@ SIMPLE_OPTIONS = {
'default': 'on',
'help': 'enable debugging of JavaScript code'
},
+ 'inspector': {
+ 'values': ['on', 'off'],
+ 'default': 'off',
+ 'help': 'enable inspector features'
+ },
'soname': {
'values': ['on', 'off'],
'default': 'off',
@@ -871,6 +887,8 @@ def VerifyOptions(env):
return False
if env['os'] == 'win32' and env['library'] == 'shared' and env['prof'] == 'on':
Abort("Profiling on windows only supported for static library.")
+ if env['gdbjit'] == 'on' and (env['os'] != 'linux' or (env['arch'] != 'ia32' and env['arch'] != 'x64')):
+ Abort("GDBJIT interface is supported only for Intel-compatible (ia32 or x64) Linux target.")
if env['prof'] == 'oprofile' and env['os'] != 'linux':
Abort("OProfile is only supported on Linux.")
if env['os'] == 'win32' and env['soname'] == 'on':
diff --git a/deps/v8/src/SConscript b/deps/v8/src/SConscript
index 79b12040b..708edeff0 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 a7c1897ae..11a9c3930 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 e0ea819e9..ad1bdabd0 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 340bc1ef9..6120bba45 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 df890ab55..b51633e70 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 c6b89a504..aab408111 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 dca95f236..55df8b4cb 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 20e280182..b7ec5d245 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 cdcf48189..fb9a4af14 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 5817a15b4..4ef61e4b1 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 a659c461c..c4c9fc11c 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 ba027e933..69f8477f8 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 da479e8fc..c7e6f1c83 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 0bd973045..bbe7f2fc9 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 68066aa67..44ac9c85c 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 daadef69f..fb892d624 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 16ffbf5a9..7f28ff175 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 58540f07b..9366e427a 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 000000000..b1782cbdd
--- /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 000000000..5d348b69a
--- /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 89478f5e3..b13bb0c4d 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 4a23f2a32..eebec5a9e 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 7aa66fd61..da41ef94d 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 35165ae97..19f898381 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 90bfd4b66..f570fe01e 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 24ee1fefd..2d3eac148 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 ef8fb5c49..ab62e6fe9 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 000000000..88869590e
--- /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 000000000..f0bd260aa
--- /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 254a47af7..cca07c8c8 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 07f0a8d90..67f87518a 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 bcb02ed79..45d63c5a0 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 645c6fdcf..afae32353 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 8562bcc24..9996affa7 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 000000000..8fb80f1a2
--- /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 000000000..f8b304286
--- /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 29662c94a..2bbc6b652 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 dfe1953df..48c65631d 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 e066e7da9..d6cff2565 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 f4ae2aa2c..5f7c92fce 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 8ade41cd2..a946ffa23 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 7d50bfb6f..f9c57e696 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 abfd4436d..df44674a1 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 c136dc59b..f9cab45fb 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 a97785e4c..bf1737a54 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 cc82bcc62..bb5707b61 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 1efc6ef62..d7792acea 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 0cde7779a..2f1f54c69 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 e054d7de5..e06235af7 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 58a10ee34..d3f54ad3f 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 86e720121..295cc4a60 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 a7829a600..85dd5f6aa 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 000000000..7473a7b2b
--- /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 000000000..ba2b789f3
--- /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 032d98567..f4f65e99b 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 98d97def2..e026e88c0 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 a77d85f75..495de3140 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 9060d5758..de01cfa3c 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 fa2f4c351..be837f044 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 5056f3484..9feced2f9 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 8bb3ac09f..6b19d3f14 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 fbbf176e4..a2a0e7e9f 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 29cbed05e..b54aeb977 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 e586851e8..151fad736 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 25a048bad..5ef6eb753 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 f3023f979..17d9dda10 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 57cba1421..8c1b5794d 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);
diff --git a/deps/v8/test/cctest/cctest.status b/deps/v8/test/cctest/cctest.status
index 23c209222..a7eca5b39 100644
--- a/deps/v8/test/cctest/cctest.status
+++ b/deps/v8/test/cctest/cctest.status
@@ -77,6 +77,12 @@ test-deoptimization/DeoptimizeCompare: FAIL
# Tests that time out with crankshaft.
test-api/Threading: SKIP
+# BUG(1049): Currently no deoptimization support.
+test-serialize/ContextSerialization: SKIP
+test-serialize/ContextDeserialization: SKIP
+test-debug/BreakPointReturn: SKIP
+test-debug/DebugStepLinearMixedICs: SKIP
+
##############################################################################
[ $arch == arm ]
@@ -102,10 +108,6 @@ test-sockets/Socket: SKIP
##############################################################################
[ $arch == arm && $crankshaft ]
-# Tests that can fail with crankshaft.
-test-deoptimization/DeoptimizeBinaryOperationMOD: PASS || FAIL
-test-deoptimization/DeoptimizeBinaryOperationDIV: PASS || FAIL
-
# Tests that time out with crankshaft.
test-debug/ThreadedDebugging: SKIP
test-debug/DebugBreakLoop: SKIP
diff --git a/deps/v8/test/mjsunit/compiler/regress-serialized-slots.js b/deps/v8/test/mjsunit/compiler/regress-serialized-slots.js
new file mode 100644
index 000000000..0bd7528f1
--- /dev/null
+++ b/deps/v8/test/mjsunit/compiler/regress-serialized-slots.js
@@ -0,0 +1,61 @@
+// 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.
+
+// The test verifies that parameters of the outer function are correctly
+// accessible from the inner closure.
+
+function runner(f, expected) {
+ for (var i = 0; i < 10000; i++) { // Loop to trigger optimization.
+ assertEquals(expected, f.call(this, 10));
+ }
+}
+
+Function.prototype.bind = function(thisObject)
+{
+ var func = this;
+ var args = Array.prototype.slice.call(arguments, 1);
+ function bound()
+ {
+ // Note outer function parameter access (|thisObject|).
+ return func.apply(
+ thisObject,
+ args.concat(Array.prototype.slice.call(arguments, 0)));
+ }
+ return bound;
+}
+
+function sum(x, y) {
+ return x + y;
+}
+
+function test(n) {
+ runner(sum.bind(this, n), n + 10);
+}
+
+test(1);
+test(42);
+test(239);
diff --git a/deps/v8/test/mjsunit/mjsunit.status b/deps/v8/test/mjsunit/mjsunit.status
index 057c0fa87..39ddf5a41 100644
--- a/deps/v8/test/mjsunit/mjsunit.status
+++ b/deps/v8/test/mjsunit/mjsunit.status
@@ -119,6 +119,9 @@ compiler/simple-osr: FAIL
# BUG (1026) This test is currently flaky.
compiler/simple-osr: SKIP
+# BUG(1049): Currently no deoptimization support.
+debug-liveedit-newsource: SKIP
+debug-liveedit-1: SKIP
##############################################################################
[ $arch == mips ]
diff --git a/deps/v8/test/mozilla/mozilla.status b/deps/v8/test/mozilla/mozilla.status
index ba35bb6ed..a119bf2a7 100644
--- a/deps/v8/test/mozilla/mozilla.status
+++ b/deps/v8/test/mozilla/mozilla.status
@@ -836,19 +836,6 @@ js1_5/extensions/regress-371636: SKIP
# BUG(1040): Allow this test to timeout.
js1_5/GC/regress-203278-2: PASS || TIMEOUT
-[ $arch == arm && $crankshaft ]
-
-# Test that only fail with crankshaft.
-js1_5/Regress/regress-416628: CRASH
-js1_5/Regress/regress-96128-n: PASS || CRASH
-
-# BUG(1032): test crashes.
-ecma/Date/15.9.3.1-1: PASS || CRASH
-ecma/Date/15.9.3.1-2: PASS || CRASH
-ecma/Date/15.9.3.1-3: PASS || CRASH
-ecma/Date/15.9.3.1-4: PASS || CRASH
-ecma/Date/15.9.3.1-5: PASS || CRASH
-
[ $fast == yes && $arch == arm ]
diff --git a/deps/v8/tools/gyp/v8.gyp b/deps/v8/tools/gyp/v8.gyp
index 816343bb0..024ecd7a1 100644
--- a/deps/v8/tools/gyp/v8.gyp
+++ b/deps/v8/tools/gyp/v8.gyp
@@ -581,10 +581,10 @@
'../../src/arm/full-codegen-arm.cc',
'../../src/arm/ic-arm.cc',
'../../src/arm/jump-target-arm.cc',
- '../../src/arm/lithium-codegen-arm.cc',
- '../../src/arm/lithium-codegen-arm.h',
'../../src/arm/lithium-arm.cc',
'../../src/arm/lithium-arm.h',
+ '../../src/arm/lithium-codegen-arm.cc',
+ '../../src/arm/lithium-codegen-arm.h',
'../../src/arm/macro-assembler-arm.cc',
'../../src/arm/macro-assembler-arm.h',
'../../src/arm/regexp-macro-assembler-arm.cc',
@@ -634,6 +634,8 @@
'../../src/ia32/jump-target-ia32.cc',
'../../src/ia32/lithium-codegen-ia32.cc',
'../../src/ia32/lithium-codegen-ia32.h',
+ '../../src/ia32/lithium-gap-resolver-ia32.cc',
+ '../../src/ia32/lithium-gap-resolver-ia32.h',
'../../src/ia32/lithium-ia32.cc',
'../../src/ia32/lithium-ia32.h',
'../../src/ia32/macro-assembler-ia32.cc',