[turbofan] Add new JSFrameSpecialization reducer.
authorbmeurer <bmeurer@chromium.org>
Mon, 6 Jul 2015 08:27:03 +0000 (01:27 -0700)
committerCommit bot <commit-bot@chromium.org>
Mon, 6 Jul 2015 08:27:12 +0000 (08:27 +0000)
The JSFrameSpecialization specializes an OSR graph to the current
unoptimized frame on which we will perform the on-stack replacement.
This is used for asm.js functions, where we cannot reuse the OSR code
object anyway because of context specialization, and so we could as well
specialize to the max instead.

It works by replacing all OsrValues in the graph with their values in
the JavaScriptFrame.

The idea is that using this trick we get better performance without
doing the unsound backpropagation of types to OsrValues later. This is
the first step towards fixing OSR for TurboFan.

R=jarin@chromium.org
BUG=v8:4273
LOG=n

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

Cr-Commit-Position: refs/heads/master@{#29476}

BUILD.gn
src/compiler.cc
src/compiler.h
src/compiler/js-frame-specialization.cc [new file with mode: 0644]
src/compiler/js-frame-specialization.h [new file with mode: 0644]
src/compiler/pipeline.cc
src/runtime/runtime-compiler.cc
tools/gyp/v8.gyp

index 882e2bc..a18161b 100644 (file)
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -672,6 +672,8 @@ source_set("v8_base") {
     "src/compiler/js-builtin-reducer.h",
     "src/compiler/js-context-specialization.cc",
     "src/compiler/js-context-specialization.h",
+    "src/compiler/js-frame-specialization.cc",
+    "src/compiler/js-frame-specialization.h",
     "src/compiler/js-generic-lowering.cc",
     "src/compiler/js-generic-lowering.h",
     "src/compiler/js-graph.cc",
index 495ba4f..0f3ebe0 100644 (file)
@@ -394,6 +394,7 @@ OptimizedCompileJob::Status OptimizedCompileJob::CreateGraph() {
     }
 
     if (info()->shared_info()->asm_function()) {
+      if (info()->osr_frame()) info()->MarkAsFrameSpecializing();
       info()->MarkAsContextSpecializing();
     } else if (FLAG_turbo_type_feedback) {
       info()->MarkAsTypeFeedbackEnabled();
@@ -712,7 +713,9 @@ static void InsertCodeIntoOptimizedCodeMap(CompilationInfo* info) {
   if (code->kind() != Code::OPTIMIZED_FUNCTION) return;  // Nothing to do.
 
   // Context specialization folds-in the context, so no sharing can occur.
-  if (code->is_turbofanned() && info->is_context_specializing()) return;
+  if (info->is_context_specializing()) return;
+  // Frame specialization implies context specialization.
+  DCHECK(!info->is_frame_specializing());
 
   // Do not cache bound functions.
   Handle<JSFunction> function = info->closure();
@@ -1469,7 +1472,8 @@ Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfo(
 MaybeHandle<Code> Compiler::GetOptimizedCode(Handle<JSFunction> function,
                                              Handle<Code> current_code,
                                              ConcurrencyMode mode,
-                                             BailoutId osr_ast_id) {
+                                             BailoutId osr_ast_id,
+                                             JavaScriptFrame* osr_frame) {
   Handle<Code> cached_code;
   if (GetCodeFromOptimizedCodeMap(
           function, osr_ast_id).ToHandle(&cached_code)) {
@@ -1527,6 +1531,7 @@ MaybeHandle<Code> Compiler::GetOptimizedCode(Handle<JSFunction> function,
       return isolate->builtins()->InOptimizationQueue();
     }
   } else {
+    info->set_osr_frame(osr_frame);
     if (GetOptimizedCodeNow(info.get())) return info->code();
   }
 
index e1e4be3..45863f6 100644 (file)
@@ -17,6 +17,7 @@ namespace internal {
 
 class AstValueFactory;
 class HydrogenCodeStub;
+class JavaScriptFrame;
 class ParseInfo;
 class ScriptData;
 
@@ -122,14 +123,15 @@ class CompilationInfo {
     kCompilingForDebugging = 1 << 7,
     kSerializing = 1 << 8,
     kContextSpecializing = 1 << 9,
-    kInliningEnabled = 1 << 10,
-    kTypingEnabled = 1 << 11,
-    kDisableFutureOptimization = 1 << 12,
-    kSplittingEnabled = 1 << 13,
-    kTypeFeedbackEnabled = 1 << 14,
-    kDeoptimizationEnabled = 1 << 15,
-    kSourcePositionsEnabled = 1 << 16,
-    kFirstCompile = 1 << 17,
+    kFrameSpecializing = 1 << 10,
+    kInliningEnabled = 1 << 11,
+    kTypingEnabled = 1 << 12,
+    kDisableFutureOptimization = 1 << 13,
+    kSplittingEnabled = 1 << 14,
+    kTypeFeedbackEnabled = 1 << 15,
+    kDeoptimizationEnabled = 1 << 16,
+    kSourcePositionsEnabled = 1 << 17,
+    kFirstCompile = 1 << 18,
   };
 
   explicit CompilationInfo(ParseInfo* parse_info);
@@ -217,6 +219,10 @@ class CompilationInfo {
 
   bool is_context_specializing() const { return GetFlag(kContextSpecializing); }
 
+  void MarkAsFrameSpecializing() { SetFlag(kFrameSpecializing); }
+
+  bool is_frame_specializing() const { return GetFlag(kFrameSpecializing); }
+
   void MarkAsTypeFeedbackEnabled() { SetFlag(kTypeFeedbackEnabled); }
 
   bool is_type_feedback_enabled() const {
@@ -388,6 +394,8 @@ class CompilationInfo {
     DCHECK(height >= 0);
     osr_expr_stack_height_ = height;
   }
+  JavaScriptFrame* osr_frame() const { return osr_frame_; }
+  void set_osr_frame(JavaScriptFrame* osr_frame) { osr_frame_ = osr_frame; }
 
 #if DEBUG
   void PrintAstForTesting();
@@ -492,6 +500,9 @@ class CompilationInfo {
 
   int osr_expr_stack_height_;
 
+  // The current OSR frame for specialization or {nullptr}.
+  JavaScriptFrame* osr_frame_ = nullptr;
+
   Type::FunctionType* function_type_;
 
   DISALLOW_COPY_AND_ASSIGN(CompilationInfo);
@@ -662,10 +673,9 @@ class Compiler : public AllStatic {
   // In the latter case, return the InOptimizationQueue builtin.  On failure,
   // return the empty handle.
   MUST_USE_RESULT static MaybeHandle<Code> GetOptimizedCode(
-      Handle<JSFunction> function,
-      Handle<Code> current_code,
-      ConcurrencyMode mode,
-      BailoutId osr_ast_id = BailoutId::None());
+      Handle<JSFunction> function, Handle<Code> current_code,
+      ConcurrencyMode mode, BailoutId osr_ast_id = BailoutId::None(),
+      JavaScriptFrame* osr_frame = nullptr);
 
   // Generate and return code from previously queued optimization job.
   // On failure, return the empty handle.
diff --git a/src/compiler/js-frame-specialization.cc b/src/compiler/js-frame-specialization.cc
new file mode 100644 (file)
index 0000000..98b1827
--- /dev/null
@@ -0,0 +1,69 @@
+// Copyright 2015 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.
+
+#include "src/compiler/js-frame-specialization.h"
+
+#include "src/compiler/js-graph.h"
+#include "src/compiler/linkage.h"
+#include "src/frames-inl.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+Reduction JSFrameSpecialization::Reduce(Node* node) {
+  switch (node->opcode()) {
+    case IrOpcode::kOsrValue:
+      return ReduceOsrValue(node);
+    case IrOpcode::kParameter:
+      return ReduceParameter(node);
+    default:
+      break;
+  }
+  return NoChange();
+}
+
+
+Reduction JSFrameSpecialization::ReduceOsrValue(Node* node) {
+  DCHECK_EQ(IrOpcode::kOsrValue, node->opcode());
+  DisallowHeapAllocation no_gc;
+  Object* object;
+  int const index = OpParameter<int>(node);
+  int const parameters_count = frame()->ComputeParametersCount() + 1;
+  if (index == Linkage::kOsrContextSpillSlotIndex) {
+    object = frame()->context();
+  } else if (index >= parameters_count) {
+    object = frame()->GetExpression(index - parameters_count);
+  } else {
+    // The OsrValue index 0 is the receiver.
+    object = index ? frame()->GetParameter(index - 1) : frame()->receiver();
+  }
+  return Replace(jsgraph()->Constant(handle(object, isolate())));
+}
+
+
+Reduction JSFrameSpecialization::ReduceParameter(Node* node) {
+  DCHECK_EQ(IrOpcode::kParameter, node->opcode());
+  DisallowHeapAllocation no_gc;
+  Object* object;
+  int const index = ParameterIndexOf(node->op());
+  int const parameters_count = frame()->ComputeParametersCount() + 1;
+  if (index == Linkage::kJSFunctionCallClosureParamIndex) {
+    object = frame()->function();
+  } else if (index == parameters_count) {
+    // The Parameter index (arity + 1) is the context.
+    object = frame()->context();
+  } else {
+    // The Parameter index 0 is the receiver.
+    object = index ? frame()->GetParameter(index - 1) : frame()->receiver();
+  }
+  return Replace(jsgraph()->Constant(handle(object, isolate())));
+}
+
+
+Isolate* JSFrameSpecialization::isolate() const { return jsgraph()->isolate(); }
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/src/compiler/js-frame-specialization.h b/src/compiler/js-frame-specialization.h
new file mode 100644 (file)
index 0000000..c6fc561
--- /dev/null
@@ -0,0 +1,44 @@
+// Copyright 2015 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.
+
+#ifndef V8_COMPILER_JS_FRAME_SPECIALIZATION_H_
+#define V8_COMPILER_JS_FRAME_SPECIALIZATION_H_
+
+#include "src/compiler/graph-reducer.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+// Forward declarations.
+class JSGraph;
+
+
+class JSFrameSpecialization final : public Reducer {
+ public:
+  JSFrameSpecialization(JavaScriptFrame const* frame, JSGraph* jsgraph)
+      : frame_(frame), jsgraph_(jsgraph) {}
+  ~JSFrameSpecialization() final {}
+
+  Reduction Reduce(Node* node) final;
+
+ private:
+  Reduction ReduceOsrValue(Node* node);
+  Reduction ReduceParameter(Node* node);
+
+  Isolate* isolate() const;
+  JavaScriptFrame const* frame() const { return frame_; }
+  JSGraph* jsgraph() const { return jsgraph_; }
+
+  JavaScriptFrame const* const frame_;
+  JSGraph* const jsgraph_;
+
+  DISALLOW_COPY_AND_ASSIGN(JSFrameSpecialization);
+};
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_COMPILER_JS_FRAME_SPECIALIZATION_H_
index 7ced8e6..63ba407 100644 (file)
@@ -26,6 +26,7 @@
 #include "src/compiler/instruction-selector.h"
 #include "src/compiler/js-builtin-reducer.h"
 #include "src/compiler/js-context-specialization.h"
+#include "src/compiler/js-frame-specialization.h"
 #include "src/compiler/js-generic-lowering.h"
 #include "src/compiler/js-inlining.h"
 #include "src/compiler/js-intrinsic-lowering.h"
@@ -496,12 +497,17 @@ struct InliningPhase {
     CommonOperatorReducer common_reducer(&graph_reducer, data->graph(),
                                          data->common(), data->machine());
     JSContextSpecializer context_specializer(&graph_reducer, data->jsgraph());
+    JSFrameSpecialization frame_specialization(data->info()->osr_frame(),
+                                               data->jsgraph());
     JSInliner inliner(&graph_reducer, data->info()->is_inlining_enabled()
                                           ? JSInliner::kGeneralInlining
                                           : JSInliner::kRestrictedInlining,
                       temp_zone, data->info(), data->jsgraph());
     AddReducer(data, &graph_reducer, &dead_code_elimination);
     AddReducer(data, &graph_reducer, &common_reducer);
+    if (data->info()->is_frame_specializing()) {
+      AddReducer(data, &graph_reducer, &frame_specialization);
+    }
     if (data->info()->is_context_specializing()) {
       AddReducer(data, &graph_reducer, &context_specializer);
     }
index ba92faa..0b6677a 100644 (file)
@@ -219,11 +219,12 @@ RUNTIME_FUNCTION(Runtime_CompileForOnStackReplacement) {
   BailoutId ast_id = caller_code->TranslatePcOffsetToAstId(pc_offset);
   DCHECK(!ast_id.IsNone());
 
-  Compiler::ConcurrencyMode mode =
-      isolate->concurrent_osr_enabled() &&
-              (function->shared()->ast_node_count() > 512)
-          ? Compiler::CONCURRENT
-          : Compiler::NOT_CONCURRENT;
+  // Disable concurrent OSR for asm.js, to enable frame specialization.
+  Compiler::ConcurrencyMode mode = (isolate->concurrent_osr_enabled() &&
+                                    !function->shared()->asm_function() &&
+                                    function->shared()->ast_node_count() > 512)
+                                       ? Compiler::CONCURRENT
+                                       : Compiler::NOT_CONCURRENT;
   Handle<Code> result = Handle<Code>::null();
 
   OptimizedCompileJob* job = NULL;
@@ -258,8 +259,9 @@ RUNTIME_FUNCTION(Runtime_CompileForOnStackReplacement) {
       function->PrintName();
       PrintF(" at AST id %d]\n", ast_id.ToInt());
     }
-    MaybeHandle<Code> maybe_result =
-        Compiler::GetOptimizedCode(function, caller_code, mode, ast_id);
+    MaybeHandle<Code> maybe_result = Compiler::GetOptimizedCode(
+        function, caller_code, mode, ast_id,
+        (mode == Compiler::NOT_CONCURRENT) ? frame : nullptr);
     if (maybe_result.ToHandle(&result) &&
         result.is_identical_to(isolate->builtins()->InOptimizationQueue())) {
       // Optimization is queued.  Return to check later.
index b1a30fd..576c871 100644 (file)
         '../../src/compiler/js-builtin-reducer.h',
         '../../src/compiler/js-context-specialization.cc',
         '../../src/compiler/js-context-specialization.h',
+        '../../src/compiler/js-frame-specialization.cc',
+        '../../src/compiler/js-frame-specialization.h',
         '../../src/compiler/js-generic-lowering.cc',
         '../../src/compiler/js-generic-lowering.h',
         '../../src/compiler/js-graph.cc',