Mark the simulate before EnterInlined with BailoutId::None(), and set ReturnId on...
authorverwaest@chromium.org <verwaest@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 24 Apr 2014 15:20:53 +0000 (15:20 +0000)
committerverwaest@chromium.org <verwaest@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 24 Apr 2014 15:20:53 +0000 (15:20 +0000)
BUG=v8:3282
LOG=n
R=titzer@chromium.org

Review URL: https://codereview.chromium.org/257583004

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

src/arm/lithium-arm.cc
src/arm64/lithium-arm64.cc
src/hydrogen-instructions.cc
src/hydrogen-instructions.h
src/hydrogen.cc
src/ia32/lithium-ia32.cc
src/mips/lithium-mips.cc
src/x64/lithium-x64.cc
test/mjsunit/regress/regress-lazy-deopt-inlining.js [new file with mode: 0644]

index b173853..1515278 100644 (file)
@@ -2521,6 +2521,7 @@ LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
 
 LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
   HEnvironment* outer = current_block_->last_environment();
+  outer->set_ast_id(instr->ReturnId());
   HConstant* undefined = graph()->GetConstantUndefined();
   HEnvironment* inner = outer->CopyForInlining(instr->closure(),
                                                instr->arguments_count(),
index 61bfdf4..b5802ab 100644 (file)
@@ -1454,6 +1454,7 @@ LInstruction* LChunkBuilder::DoDummyUse(HDummyUse* instr) {
 
 LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
   HEnvironment* outer = current_block_->last_environment();
+  outer->set_ast_id(instr->ReturnId());
   HConstant* undefined = graph()->GetConstantUndefined();
   HEnvironment* inner = outer->CopyForInlining(instr->closure(),
                                                instr->arguments_count(),
index c56f5dc..ceedafc 100644 (file)
@@ -2595,6 +2595,9 @@ void HPhi::AddIndirectUsesTo(int* dest) {
 
 
 void HSimulate::MergeWith(ZoneList<HSimulate*>* list) {
+  if (!list->is_empty() && !HasAstId()) {
+    set_ast_id(list->last()->ast_id());
+  }
   while (!list->is_empty()) {
     HSimulate* from = list->RemoveLast();
     ZoneList<HValue*>* from_values = &from->values_;
@@ -4504,7 +4507,7 @@ void HPhi::Verify() {
 
 void HSimulate::Verify() {
   HInstruction::Verify();
-  ASSERT(HasAstId());
+  ASSERT(HasAstId() || next()->IsEnterInlined());
 }
 
 
index 3b486e7..eb0d4e1 100644 (file)
@@ -2085,14 +2085,15 @@ class HEnterInlined V8_FINAL : public HTemplateInstruction<0> {
  public:
   static HEnterInlined* New(Zone* zone,
                             HValue* context,
+                            BailoutId return_id,
                             Handle<JSFunction> closure,
                             int arguments_count,
                             FunctionLiteral* function,
                             InliningKind inlining_kind,
                             Variable* arguments_var,
                             HArgumentsObject* arguments_object) {
-    return new(zone) HEnterInlined(closure, arguments_count, function,
-                                   inlining_kind, arguments_var,
+    return new(zone) HEnterInlined(return_id, closure, arguments_count,
+                                   function, inlining_kind, arguments_var,
                                    arguments_object, zone);
   }
 
@@ -2107,6 +2108,7 @@ class HEnterInlined V8_FINAL : public HTemplateInstruction<0> {
   void set_arguments_pushed() { arguments_pushed_ = true; }
   FunctionLiteral* function() const { return function_; }
   InliningKind inlining_kind() const { return inlining_kind_; }
+  BailoutId ReturnId() const { return return_id_; }
 
   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
     return Representation::None();
@@ -2118,14 +2120,16 @@ class HEnterInlined V8_FINAL : public HTemplateInstruction<0> {
   DECLARE_CONCRETE_INSTRUCTION(EnterInlined)
 
  private:
-  HEnterInlined(Handle<JSFunction> closure,
+  HEnterInlined(BailoutId return_id,
+                Handle<JSFunction> closure,
                 int arguments_count,
                 FunctionLiteral* function,
                 InliningKind inlining_kind,
                 Variable* arguments_var,
                 HArgumentsObject* arguments_object,
                 Zone* zone)
-      : closure_(closure),
+      : return_id_(return_id),
+        closure_(closure),
         arguments_count_(arguments_count),
         arguments_pushed_(false),
         function_(function),
@@ -2135,6 +2139,7 @@ class HEnterInlined V8_FINAL : public HTemplateInstruction<0> {
         return_targets_(2, zone) {
   }
 
+  BailoutId return_id_;
   Handle<JSFunction> closure_;
   int arguments_count_;
   bool arguments_pushed_;
index 6d932d4..4c02c90 100644 (file)
@@ -7383,8 +7383,6 @@ bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target,
   HConstant* context = Add<HConstant>(Handle<Context>(target->context()));
   inner_env->BindContext(context);
 
-  Add<HSimulate>(return_id);
-  current_block()->UpdateEnvironment(inner_env);
   HArgumentsObject* arguments_object = NULL;
 
   // If the function uses arguments object create and bind one, also copy
@@ -7400,8 +7398,17 @@ bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target,
     }
   }
 
+  // Capture the state before invoking the inlined function for deopt in the
+  // inlined function. This simulate has no bailout-id since it's not directly
+  // reachable for deopt, and is only used to capture the state. If the simulate
+  // becomes reachable by merging, the ast id of the simulate merged into it is
+  // adopted.
+  Add<HSimulate>(BailoutId::None());
+
+  current_block()->UpdateEnvironment(inner_env);
+
   HEnterInlined* enter_inlined =
-      Add<HEnterInlined>(target, arguments_count, function,
+      Add<HEnterInlined>(return_id, target, arguments_count, function,
                          function_state()->inlining_kind(),
                          function->scope()->arguments(),
                          arguments_object);
index cfd49ca..965b15a 100644 (file)
@@ -2658,6 +2658,7 @@ LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
 
 LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
   HEnvironment* outer = current_block_->last_environment();
+  outer->set_ast_id(instr->ReturnId());
   HConstant* undefined = graph()->GetConstantUndefined();
   HEnvironment* inner = outer->CopyForInlining(instr->closure(),
                                                instr->arguments_count(),
index 886d941..bbf422f 100644 (file)
@@ -2472,6 +2472,7 @@ LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
 
 LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
   HEnvironment* outer = current_block_->last_environment();
+  outer->set_ast_id(instr->ReturnId());
   HConstant* undefined = graph()->GetConstantUndefined();
   HEnvironment* inner = outer->CopyForInlining(instr->closure(),
                                                instr->arguments_count(),
index 978fafd..a6f9140 100644 (file)
@@ -2546,6 +2546,7 @@ LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
 
 LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
   HEnvironment* outer = current_block_->last_environment();
+  outer->set_ast_id(instr->ReturnId());
   HConstant* undefined = graph()->GetConstantUndefined();
   HEnvironment* inner = outer->CopyForInlining(instr->closure(),
                                                instr->arguments_count(),
diff --git a/test/mjsunit/regress/regress-lazy-deopt-inlining.js b/test/mjsunit/regress/regress-lazy-deopt-inlining.js
new file mode 100644 (file)
index 0000000..6cda168
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+"use strict";
+function f1(d) {
+  return 1 + f2(f3(d));
+}
+
+function f2(v) { return v; }
+
+function f3(d) {
+  if (d) %DeoptimizeFunction(f1);
+  return 2;
+}
+
+%NeverOptimizeFunction(f3);
+
+f1(false);
+f1(false);
+%OptimizeFunctionOnNextCall(f1);
+assertEquals(3, f1(true));