Reviewers: machenbach, danno,

Message:
Michael is reviewing and learning about alloc. site and hydrogen along the way.
Danno, would you offer some drive by malevolence? :)

Description:
Simple 0 argument inlining of array constructor

BUG=

Inline calls to "new Array()". The chief difference between the inlined version and the stub call is that we need to guard against changes to the AllocationSite ElementsKind for the array. If a change occurs, we deopt the method so we can
try again with up-to-date feedback.

Please review this at https://codereview.chromium.org/18689004/

SVN Base: https://v8.googlecode.com/svn/branches/bleeding_edge

Affected files:
  M src/hydrogen-instructions.h
  M src/hydrogen.h
  M src/hydrogen.cc
  M test/mjsunit/allocation-site-info.js


Index: src/hydrogen-instructions.h
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index ed6ab15c6f695019f1313011095a9807371a26d3..fc8361548a08bf69d9dd31a93b2b166f23322ca1 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -5341,6 +5341,10 @@ class HObjectAccess {
     return HObjectAccess(kInobject, AllocationSiteInfo::kPayloadOffset);
   }

+  static HObjectAccess ForPropertyCellValue() {
+    return HObjectAccess(kInobject, PropertyCell::kValueOffset);
+  }
+
   // Create an access to an offset in a fixed array header.
   static HObjectAccess ForFixedArrayHeader(int offset);

Index: src/hydrogen.cc
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 432a6bc5fcd63fe08b81bb60ea30c91747a2218e..7504200072f5e3f58a3da66e19a59712892f7e91 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -8323,6 +8323,48 @@ static bool IsAllocationInlineable(Handle<JSFunction> constructor) {
 }


+void HOptimizedGraphBuilder::BuildInlinedCallNewArray(CallNew* expr) {
+  ASSERT(expr->arguments()->length() == 0);
+  NoObservableSideEffectsScope no_effects(this);
+  VisitForValue(expr->expression());
+  HValue* constructor = Pop();
+  ElementsKind kind = expr->elements_kind();
+ HInstruction* feedback_instruction = AddInstruction(new(zone()) HConstant(
+      kind));
+  HInstruction* cell_instruction = AddInstruction(new(zone()) HConstant(
+      expr->allocation_info_cell()));
+  HInstruction* cell_value =
+      AddInstruction(BuildLoadNamedField(cell_instruction,
+ HObjectAccess::ForPropertyCellValue(),
+                                         Representation::Smi()));
+
+  // Make sure the runtime contents of the cell match feedback. If not,
+ // deopt. The reason is that a version of the array created before crankshaft + // could transition after this was compiled, and that indicates our assumption + // about the ultimate type of arrays from this allocation site is outdated.
+  IfBuilder cell_check(this);
+  cell_check.IfCompare(feedback_instruction, cell_value, Token::EQ);
+  cell_check.Then();
+  HValue* new_object;
+  {
+ // Verify we are still calling the array function for our native context.
+    Handle<JSFunction> array_function(
+        isolate()->global_context()->array_function(), isolate());
+    Add<HCheckFunction>(constructor, array_function);
+
+    // Build the array.
+    JSArrayBuilder array_builder(this,
+                                 kind,
+                                 cell_instruction,
+                                 constructor,
+                                 DISABLE_ALLOCATION_SITES);
+    new_object = array_builder.AllocateEmptyArray();
+  }
+  cell_check.ElseDeopt();
+  ast_context()->ReturnValue(HInstruction::cast(new_object));
+}
+
+
 void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) {
   ASSERT(!HasStackOverflow());
   ASSERT(current_block() != NULL);
@@ -8372,11 +8414,18 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) {
     // argument to the construct call.
     Handle<JSFunction> array_function(
         isolate()->global_context()->array_function(), isolate());
+ bool use_call_new_array = expr->target().is_identical_to(array_function);
+    if (use_call_new_array && argument_count == 1) {
+      BuildInlinedCallNewArray(expr);
+      return;
+    }
+
     CHECK_ALIVE(VisitArgument(expr->expression()));
     HValue* constructor = HPushArgument::cast(Top())->argument();
     CHECK_ALIVE(VisitArgumentList(expr->arguments()));
     HCallNew* call;
-    if (expr->target().is_identical_to(array_function)) {
+
+    if (use_call_new_array) {
       Handle<Cell> cell = expr->allocation_info_cell();
       Add<HCheckFunction>(constructor, array_function);
call = new(zone()) HCallNewArray(context, constructor, argument_count,
Index: src/hydrogen.h
diff --git a/src/hydrogen.h b/src/hydrogen.h
index 3ea326296d719c3607e7a3aa4cf2ae4d8d0382e9..fea7e47ad47199bd235117cf2993eed55774dc03 100644
--- a/src/hydrogen.h
+++ b/src/hydrogen.h
@@ -1939,6 +1939,8 @@ class HOptimizedGraphBuilder: public HGraphBuilder, public AstVisitor {
                         HValue** operand,
                         HValue** shift_amount);

+  void BuildInlinedCallNewArray(CallNew* expr);
+
   // The translation state of the currently-being-translated function.
   FunctionState* function_state_;

Index: test/mjsunit/allocation-site-info.js
diff --git a/test/mjsunit/allocation-site-info.js b/test/mjsunit/allocation-site-info.js index 86c28aac63afed2a8c24da2f1fc30e220266adda..e0ec69e7957c06189abe560faae7c568af2911c6 100644
--- a/test/mjsunit/allocation-site-info.js
+++ b/test/mjsunit/allocation-site-info.js
@@ -207,6 +207,38 @@ if (support_smi_only_arrays) {
   obj = newarraycase_smiobj(2);
   assertKind(elements_kind.fast, obj);

+  // Verify that inlining of zero argument array constructors works for
+  // crankshafted code.
+  function newarraycase_noarg(value) {
+    var a = new Array();
+    a[0] = value;
+    return a;
+  }
+
+  newarraycase_noarg(5);
+  obj = newarraycase_noarg(3.5);
+  assertKind(elements_kind.fast_double, obj);
+  %OptimizeFunctionOnNextCall(newarraycase_noarg);
+  obj = newarraycase_noarg(5);
+  assertKind(elements_kind.fast_double, obj);
+  assertTrue(2 != %GetOptimizationStatus(newarraycase_noarg));
+
+  // We turn off allocation-sites at crankshaft time. But if the
+  // feedback cell changed, we should deopt.
+  %DeoptimizeFunction(newarraycase_noarg);
+  %ClearFunctionTypeFeedback(newarraycase_noarg);
+  newarraycase_noarg(5);
+  obj = newarraycase_noarg(5);  // remember obj
+  %OptimizeFunctionOnNextCall(newarraycase_noarg);
+  obj1 = newarraycase_noarg(5);
+  assertKind(elements_kind.fast_smi_only, obj1);
+  assertTrue(2 != %GetOptimizationStatus(newarraycase_noarg));
+  obj[0] = 3.5;  // The allocation-site feedback should change
+  obj1 = newarraycase_noarg(5);
+  // We should have deopted and fallen back to full codegen.
+  assertTrue(1 != %GetOptimizationStatus(newarraycase_noarg));
+  assertKind(elements_kind.fast_double, obj1);
+
   function newarraycase_length_smidouble(value) {
     var a = new Array(3);
     a[0] = value;


--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to