Elide unnecessary context reload in generated stubs.
authordanno@chromium.org <danno@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 28 Dec 2012 16:25:38 +0000 (16:25 +0000)
committerdanno@chromium.org <danno@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 28 Dec 2012 16:25:38 +0000 (16:25 +0000)
Review URL: https://codereview.chromium.org/11550005

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13290 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

12 files changed:
src/arm/lithium-arm.cc
src/arm/lithium-codegen-arm.cc
src/code-stubs-hydrogen.cc
src/hydrogen-instructions.h
src/hydrogen.cc
src/ia32/lithium-codegen-ia32.cc
src/ia32/lithium-ia32.cc
src/ia32/lithium-ia32.h
src/lithium-allocator-inl.h
src/lithium.h
src/x64/lithium-codegen-x64.cc
src/x64/lithium-x64.cc

index 38092a7ff7738c6786a4f57cc285acf47d976b91..fe6a8834d820adaff79df149e3a5ce239c43d5f0 100644 (file)
@@ -999,7 +999,14 @@ LInstruction* LChunkBuilder::DoThisFunction(HThisFunction* instr) {
 
 
 LInstruction* LChunkBuilder::DoContext(HContext* instr) {
-  return instr->HasNoUses() ? NULL : DefineAsRegister(new(zone()) LContext);
+  // If there is a non-return use, the context must be allocated in a register.
+  for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) {
+    if (!it.value()->IsReturn()) {
+      return DefineAsRegister(new(zone()) LContext);
+    }
+  }
+
+  return NULL;
 }
 
 
index 0ac64fd99904c036b1946a7b6487dcd743f481b2..e2a0f2de867fd9ded3683e40d29f8300e952b04c 100644 (file)
@@ -2820,9 +2820,6 @@ void LCodeGen::DoReturn(LReturn* instr) {
     __ ldm(ia_w, sp, fp.bit() | lr.bit());
     __ add(sp, sp, Operand(sp_delta));
   }
-  if (info()->IsStub()) {
-    __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
-  }
   __ Jump(lr);
 }
 
index 74bd93f8805b768fbcb9806d2da04f754c80dfff..58e17f43f2adf7f98883e97db94b7297710949cb 100644 (file)
@@ -51,17 +51,19 @@ Handle<Code> HydrogenCodeStub::CodeFromGraph(HGraph* graph) {
 class CodeStubGraphBuilderBase : public HGraphBuilder {
  public:
   CodeStubGraphBuilderBase(Isolate* isolate, HydrogenCodeStub* stub)
-      : HGraphBuilder(&info_), info_(stub, isolate) {}
+      : HGraphBuilder(&info_), info_(stub, isolate), context_(NULL) {}
   virtual bool BuildGraph();
 
  protected:
   virtual void BuildCodeStub() = 0;
   HParameter* GetParameter(int parameter) { return parameters_[parameter]; }
   HydrogenCodeStub* stub() { return info_.code_stub(); }
+  HContext* context() { return context_; }
 
  private:
   SmartArrayPointer<HParameter*> parameters_;
   CompilationInfoWithZone info_;
+  HContext* context_;
 };
 
 
@@ -77,6 +79,9 @@ bool CodeStubGraphBuilderBase::BuildGraph() {
   graph()->entry_block()->Finish(jump);
   set_current_block(next_block);
 
+  context_ = new(zone()) HContext();
+  AddInstruction(context_);
+
   int major_key = stub()->MajorKey();
   CodeStubInterfaceDescriptor* descriptor =
       info_.isolate()->code_stub_interface_descriptor(major_key);
@@ -121,7 +126,7 @@ void CodeStubGraphBuilder<KeyedLoadFastElementStub>::BuildCodeStub() {
       casted_stub()->is_js_array(), casted_stub()->elements_kind(), false);
   AddInstruction(load);
 
-  HReturn* ret = new(zone) HReturn(load);
+  HReturn* ret = new(zone) HReturn(load, context());
   current_block()->Finish(ret);
 }
 
index d8f5dec0f7d90b4bc93c9da0da0e604dd0e65050..ee3fd9ba16818b30144d67b18c80425fa7515e73 100644 (file)
@@ -1171,10 +1171,11 @@ class HCompareMap: public HUnaryControlInstruction {
 };
 
 
-class HReturn: public HTemplateControlInstruction<0, 1> {
+class HReturn: public HTemplateControlInstruction<0, 2> {
  public:
-  explicit HReturn(HValue* value) {
+  HReturn(HValue* value, HValue* context) {
     SetOperandAt(0, value);
+    SetOperandAt(1, context);
   }
 
   virtual Representation RequiredInputRepresentation(int index) {
@@ -1184,6 +1185,7 @@ class HReturn: public HTemplateControlInstruction<0, 1> {
   virtual void PrintDataTo(StringStream* stream);
 
   HValue* value() { return OperandAt(0); }
+  HValue* context() { return OperandAt(1); }
 
   DECLARE_CONCRETE_INSTRUCTION(Return)
 };
index bf508dac28d7aeea2af3cfa3eb5281c7d0f83513..55beb3a2b9d5b6a535f12f9850d8e2da928a5d8a 100644 (file)
@@ -3399,7 +3399,8 @@ bool HOptimizedGraphBuilder::BuildGraph() {
   if (HasStackOverflow()) return false;
 
   if (current_block() != NULL) {
-    HReturn* instr = new(zone()) HReturn(graph()->GetConstantUndefined());
+    HReturn* instr = new(zone()) HReturn(graph()->GetConstantUndefined(),
+                                         context);
     current_block()->FinishExit(instr);
     set_current_block(NULL);
   }
@@ -4215,7 +4216,9 @@ void HOptimizedGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
     // Not an inlined return, so an actual one.
     CHECK_ALIVE(VisitForValue(stmt->expression()));
     HValue* result = environment()->Pop();
-    current_block()->FinishExit(new(zone()) HReturn(result));
+    current_block()->FinishExit(new(zone()) HReturn(
+        result,
+        environment()->LookupContext()));
   } else if (state->inlining_kind() == CONSTRUCT_CALL_RETURN) {
     // Return from an inlined construct call. In a test context the return value
     // will always evaluate to true, in a value context the return value needs
index 882aa85d8d65abcec2d615f42100e547d50fdf3f..761f5164dd81920777368707d8a10c61960fda2a 100644 (file)
@@ -804,9 +804,9 @@ void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) {
   ASSERT(environment->HasBeenRegistered());
   int id = environment->deoptimization_index();
   ASSERT(info()->IsOptimizing() || info()->IsStub());
-  Deoptimizer::BailoutType bailout_type = frame_is_built_
-      ? Deoptimizer::EAGER
-      : Deoptimizer::LAZY;
+  Deoptimizer::BailoutType bailout_type = info()->IsStub()
+      ? Deoptimizer::LAZY
+      : Deoptimizer::EAGER;
   Address entry = Deoptimizer::GetDeoptimizationEntry(id, bailout_type);
   if (entry == NULL) {
     Abort("bailout was not prepared");
@@ -2661,7 +2661,6 @@ void LCodeGen::DoReturn(LReturn* instr) {
     __ bind(&no_padding);
   }
   if (info()->IsStub()) {
-    __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
     __ Ret();
   } else {
     __ Ret((GetParameterCount() + 1) * kPointerSize, ecx);
@@ -3396,7 +3395,12 @@ void LCodeGen::DoThisFunction(LThisFunction* instr) {
 
 void LCodeGen::DoContext(LContext* instr) {
   Register result = ToRegister(instr->result());
-  __ mov(result, Operand(ebp, StandardFrameConstants::kContextOffset));
+  if (info()->IsOptimizing()) {
+    __ mov(result, Operand(ebp, StandardFrameConstants::kContextOffset));
+  } else {
+    // If there is no frame, the context must be in esi.
+    ASSERT(result.is(esi));
+  }
 }
 
 
index 70592b048a924b84ad82ad1ec1b0fc329e5418c3..ba1501e891644e0a135ec52e75c57cdd6ffabb80 100644 (file)
@@ -1055,7 +1055,13 @@ LInstruction* LChunkBuilder::DoThisFunction(HThisFunction* instr) {
 
 
 LInstruction* LChunkBuilder::DoContext(HContext* instr) {
-  return instr->HasNoUses() ? NULL : DefineAsRegister(new(zone()) LContext);
+  if (instr->HasNoUses()) return NULL;
+
+  if (info()->IsStub()) {
+    return DefineFixed(new(zone()) LContext, esi);
+  }
+
+  return DefineAsRegister(new(zone()) LContext);
 }
 
 
@@ -1884,7 +1890,10 @@ LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
 
 
 LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
-  return new(zone()) LReturn(UseFixed(instr->value(), eax));
+  LOperand* context = info()->IsStub()
+      ? UseFixed(instr->context(), esi)
+      : NULL;
+  return new(zone()) LReturn(UseFixed(instr->value(), eax), context);
 }
 
 
index 5ca70f27e6b9fae636d25e56d27efe570c7a6eda..02eb6d38fd80532d23ad583765a40a01cbd4c0e5 100644 (file)
@@ -1344,10 +1344,11 @@ class LArithmeticT: public LTemplateInstruction<1, 3, 0> {
 };
 
 
-class LReturn: public LTemplateInstruction<0, 1, 0> {
+class LReturn: public LTemplateInstruction<0, 2, 0> {
  public:
-  explicit LReturn(LOperand* value) {
+  explicit LReturn(LOperand* value, LOperand* context) {
     inputs_[0] = value;
+    inputs_[1] = context;
   }
 
   DECLARE_CONCRETE_INSTRUCTION(Return, "return")
index 8f660ce0e00373bdd5521b183527e972fc68c75c..1f59cb47783fac74a42fb94502e97eecc352ab54 100644 (file)
@@ -99,6 +99,7 @@ bool InputIterator::Done() { return current_ >= limit_; }
 
 LOperand* InputIterator::Current() {
   ASSERT(!Done());
+  ASSERT(instr_->InputAt(current_) != NULL);
   return instr_->InputAt(current_);
 }
 
@@ -110,7 +111,9 @@ void InputIterator::Advance() {
 
 
 void InputIterator::SkipUninteresting() {
-  while (current_ < limit_ && instr_->InputAt(current_)->IsConstantOperand()) {
+  while (current_ < limit_) {
+    LOperand* current = instr_->InputAt(current_);
+    if (current != NULL && !current->IsConstantOperand()) break;
     ++current_;
   }
 }
@@ -127,9 +130,11 @@ bool UseIterator::Done() {
 
 LOperand* UseIterator::Current() {
   ASSERT(!Done());
-  return input_iterator_.Done()
+  LOperand* result = input_iterator_.Done()
       ? env_iterator_.Current()
       : input_iterator_.Current();
+  ASSERT(result != NULL);
+  return result;
 }
 
 
index cc2cde015a4539dbf2b2aa77440ccba8a78e88e1..ea61ff5ca8acb5461d3b7b7d12f136d5dd102406 100644 (file)
@@ -581,6 +581,7 @@ class ShallowIterator BASE_EMBEDDED {
 
   LOperand* Current() {
     ASSERT(!Done());
+    ASSERT(env_->values()->at(current_) != NULL);
     return env_->values()->at(current_);
   }
 
@@ -622,6 +623,7 @@ class DeepIterator BASE_EMBEDDED {
 
   LOperand* Current() {
     ASSERT(!current_iterator_.Done());
+    ASSERT(current_iterator_.Current() != NULL);
     return current_iterator_.Current();
   }
 
index 2d12ebb035e18f2fb34468cb755ff36fc83c033f..b865cecbd2424b6d74b6413ba7709ac36135b145 100644 (file)
@@ -2463,7 +2463,6 @@ void LCodeGen::DoReturn(LReturn* instr) {
     __ pop(rbp);
   }
   if (info()->IsStub()) {
-    __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
     __ Ret(0, r10);
   } else {
     __ Ret((GetParameterCount() + 1) * kPointerSize, rcx);
index fb167eccf1af061df4c4576d6132b018276ecdad..070f1a896f184fed5b22765fb48324ac779e837c 100644 (file)
@@ -1006,7 +1006,14 @@ LInstruction* LChunkBuilder::DoThisFunction(HThisFunction* instr) {
 
 
 LInstruction* LChunkBuilder::DoContext(HContext* instr) {
-  return instr->HasNoUses() ? NULL : DefineAsRegister(new(zone()) LContext);
+  // If there is a non-return use, the context must be allocated in a register.
+  for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) {
+    if (!it.value()->IsReturn()) {
+      return DefineAsRegister(new(zone()) LContext);
+    }
+  }
+
+  return NULL;
 }