Upgrade V8 to 3.0.9
authorRyan Dahl <ry@tinyclouds.org>
Wed, 19 Jan 2011 19:06:13 +0000 (11:06 -0800)
committerRyan Dahl <ry@tinyclouds.org>
Wed, 19 Jan 2011 19:06:13 +0000 (11:06 -0800)
75 files changed:
deps/v8/ChangeLog
deps/v8/LICENSE
deps/v8/SConstruct
deps/v8/src/SConscript
deps/v8/src/arm/assembler-arm.cc
deps/v8/src/arm/assembler-arm.h
deps/v8/src/arm/ic-arm.cc
deps/v8/src/arm/lithium-arm.cc
deps/v8/src/arm/lithium-arm.h
deps/v8/src/arm/lithium-codegen-arm.cc
deps/v8/src/arm/stub-cache-arm.cc
deps/v8/src/assembler.cc
deps/v8/src/assembler.h
deps/v8/src/builtins.cc
deps/v8/src/code-stubs.cc
deps/v8/src/codegen.cc
deps/v8/src/compiler.cc
deps/v8/src/compiler.h
deps/v8/src/flag-definitions.h
deps/v8/src/frames.cc
deps/v8/src/full-codegen.cc
deps/v8/src/gdb-jit.cc [new file with mode: 0644]
deps/v8/src/gdb-jit.h [new file with mode: 0644]
deps/v8/src/hydrogen-instructions.cc
deps/v8/src/hydrogen-instructions.h
deps/v8/src/hydrogen.cc
deps/v8/src/hydrogen.h
deps/v8/src/ia32/ic-ia32.cc
deps/v8/src/ia32/lithium-codegen-ia32.cc
deps/v8/src/ia32/lithium-codegen-ia32.h
deps/v8/src/ia32/lithium-gap-resolver-ia32.cc [new file with mode: 0644]
deps/v8/src/ia32/lithium-gap-resolver-ia32.h [new file with mode: 0644]
deps/v8/src/ia32/lithium-ia32.cc
deps/v8/src/ia32/lithium-ia32.h
deps/v8/src/ia32/stub-cache-ia32.cc
deps/v8/src/ic.cc
deps/v8/src/ic.h
deps/v8/src/inspector.cc [new file with mode: 0644]
deps/v8/src/inspector.h [new file with mode: 0644]
deps/v8/src/lithium-allocator.cc
deps/v8/src/lithium-allocator.h
deps/v8/src/lithium.cc
deps/v8/src/lithium.h
deps/v8/src/mark-compact.cc
deps/v8/src/objects-debug.cc
deps/v8/src/objects-inl.h
deps/v8/src/objects.h
deps/v8/src/platform-win32.cc
deps/v8/src/preparse-data.h
deps/v8/src/runtime-profiler.cc
deps/v8/src/runtime.cc
deps/v8/src/scopeinfo.cc
deps/v8/src/scopes.cc
deps/v8/src/stub-cache.cc
deps/v8/src/stub-cache.h
deps/v8/src/third_party/strongtalk/LICENSE [new file with mode: 0644]
deps/v8/src/third_party/strongtalk/README.chromium [new file with mode: 0644]
deps/v8/src/type-info.cc
deps/v8/src/type-info.h
deps/v8/src/version.cc
deps/v8/src/x64/assembler-x64.cc
deps/v8/src/x64/assembler-x64.h
deps/v8/src/x64/code-stubs-x64.h
deps/v8/src/x64/deoptimizer-x64.cc
deps/v8/src/x64/frames-x64.h
deps/v8/src/x64/ic-x64.cc
deps/v8/src/x64/lithium-codegen-x64.cc
deps/v8/src/x64/lithium-x64.cc
deps/v8/src/x64/lithium-x64.h
deps/v8/src/x64/stub-cache-x64.cc
deps/v8/test/cctest/cctest.status
deps/v8/test/mjsunit/compiler/regress-serialized-slots.js [new file with mode: 0644]
deps/v8/test/mjsunit/mjsunit.status
deps/v8/test/mozilla/mozilla.status
deps/v8/tools/gyp/v8.gyp

index 6c4bf42..c9ff297 100644 (file)
@@ -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).
 
index c1fcb1a..e435050 100644 (file)
@@ -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:
index e10f811..50babba 100644 (file)
@@ -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':
index 79b1204..708edef 100755 (executable)
@@ -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
index a7c1897..11a9c39 100644 (file)
@@ -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);
index e0ea819..ad1bdab 100644 (file)
@@ -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);
 
index 340bc1e..6120bba 100644 (file)
@@ -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.
index df890ab..b51633e 100644 (file)
@@ -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());
   }
index c6b89a5..aab4081 100644 (file)
@@ -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);
index dca95f2..55df8b4 100644 (file)
@@ -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);
 }
 
 
index 20e2801..b7ec5d2 100644 (file)
@@ -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;
index cdcf481..fb9a4af 100644 (file)
@@ -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
 }
 
 
index 5817a15..4ef61e4 100644 (file)
@@ -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;
 
index a659c46..c4c9fc1 100644 (file)
@@ -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) {
index ba027e9..69f8477 100644 (file)
@@ -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
index da479e8..c7e6f1c 100644 (file)
@@ -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();
 }
 
index 0bd9730..bbe7f2f 100755 (executable)
@@ -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
index 68066aa..44ac9c8 100644 (file)
@@ -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,
index daadef6..fb892d6 100644 (file)
@@ -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
 //
index 16ffbf5..7f28ff1 100644 (file)
@@ -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;
index 58540f0..9366e42 100644 (file)
@@ -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 (file)
index 0000000..b1782cb
--- /dev/null
@@ -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 (file)
index 0000000..5d348b6
--- /dev/null
@@ -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
index 89478f5..b13bb0c 100644 (file)
@@ -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;
index 4a23f2a..eebec5a 100644 (file)
@@ -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();
   }
index 7aa66fd..da41ef9 100644 (file)
@@ -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) {
index 35165ae..19f8983 100644 (file)
@@ -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(); }
index 90bfd4b..f570fe0 100644 (file)
@@ -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
index 24ee1fe..2d3eac1 100644 (file)
@@ -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);
index ef8fb5c..ab62e6f 100644 (file)
@@ -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 (file)
index 0000000..8886959
--- /dev/null
@@ -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 (file)
index 0000000..f0bd260
--- /dev/null
@@ -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_
index 254a47a..cca07c8 100644 (file)
@@ -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))
index 07f0a8d..67f8751 100644 (file)
@@ -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);
index bcb02ed..45d63c5 100644 (file)
@@ -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;
index 645c6fd..afae323 100644 (file)
@@ -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
index 8562bcc..9996aff 100644 (file)
@@ -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 (file)
index 0000000..8fb80f1
--- /dev/null
@@ -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 (file)
index 0000000..f8b3042
--- /dev/null
@@ -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_
+
index 29662c9..2bbc6b6 100644 (file)
@@ -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;
         }
index dfe1953..48c6563 100644 (file)
@@ -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_;
 };
 
 
index e066e7d..d6cff25 100644 (file)
@@ -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(";");
     }
   }
 }
index f4ae2aa..5f7c92f 100644 (file)
@@ -35,9 +35,6 @@
 namespace v8 {
 namespace internal {
 
-class LCodeGen;
-class Translation;
-
 class LParallelMove : public ZoneObject {
  public:
   LParallelMove() : move_operands_(4) { }
index 8ade41c..a946ffa 100644 (file)
@@ -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()));
index 7d50bfb..f9c57e6 100644 (file)
@@ -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());
     }
   }
 }
index abfd443..df44674 100644 (file)
@@ -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;
index c136dc5..f9cab45 100644 (file)
@@ -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);
index a97785e..bf1737a 100644 (file)
@@ -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';
 }
 
index cc82bcc..bb5707b 100644 (file)
@@ -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;
index 1efc6ef..d7792ac 100644 (file)
@@ -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();
 }
index 0cde777..2f1f54c 100644 (file)
@@ -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
index e054d7d..e06235a 100644 (file)
@@ -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
index 58a10ee..d3f54ad 100644 (file)
@@ -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;
 }
 
 
index 86e7201..295cc4a 100644 (file)
@@ -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;
 }
 
index a7829a6..85dd5f6 100644 (file)
@@ -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 (file)
index 0000000..7473a7b
--- /dev/null
@@ -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 (file)
index 0000000..ba2b789
--- /dev/null
@@ -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
index 032d985..f4f65e9 100644 (file)
@@ -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);
 }
 
index 98d97de..e026e88 100644 (file)
@@ -219,6 +219,12 @@ class TypeInfo {
 };
 
 
+enum StringStubFeedback {
+  DEFAULT_STRING_STUB = 0,
+  STRING_INDEX_OUT_OF_BOUNDS = 1
+};
+
+
 // Forward declarations.
 class Assignment;
 class BinaryOperation;
index a77d85f..495de31 100644 (file)
@@ -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
 
index 9060d57..de01cfa 100644 (file)
@@ -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);
index fa2f4c3..be837f0 100644 (file)
@@ -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_); }
index 5056f34..9feced2 100644 (file)
@@ -198,6 +198,7 @@ class GenericBinaryOpStub: public CodeStub {
   }
 
   friend class CodeGenerator;
+  friend class LCodeGen;
 };
 
 
index 8bb3ac0..6b19d3f 100644 (file)
@@ -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;
 }
 
 
index fbbf176..a2a0e7e 100644 (file)
@@ -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;
 
 // ----------------------------------------------------
 
index 29cbed0..b54aeb9 100644 (file)
@@ -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.
index e586851..151fad7 100644 (file)
@@ -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");
 }
index 25a048b..5ef6eb7 100644 (file)
@@ -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 {
index f3023f9..17d9dda 100644 (file)
@@ -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_
index 57cba14..8c1b579 100644 (file)
@@ -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);
index 23c2092..a7eca5b 100644 (file)
@@ -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 (file)
index 0000000..0bd7528
--- /dev/null
@@ -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);
index 057c0fa..39ddf5a 100644 (file)
@@ -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 ]
index ba35bb6..a119bf2 100644 (file)
@@ -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 ]
 
index 816343b..024ecd7 100644 (file)
                 '../../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',
                 '../../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',