Revert "Customized support for feedback on calls to Array." and follow-up fixes.
authorjkummerow@chromium.org <jkummerow@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 26 May 2014 09:04:00 +0000 (09:04 +0000)
committerjkummerow@chromium.org <jkummerow@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 26 May 2014 09:04:00 +0000 (09:04 +0000)
This reverts r21429, r21434, r21435, r21440, r21445.

BUG=chromium:377198
LOG=y
R=mvstanton@chromium.org

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

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

17 files changed:
src/arm/code-stubs-arm.cc
src/arm64/code-stubs-arm64.cc
src/ast.h
src/code-stubs.h
src/hydrogen.cc
src/hydrogen.h
src/ia32/code-stubs-ia32.cc
src/ic.cc
src/ic.h
src/mips/code-stubs-mips.cc
src/objects.cc
src/type-info.cc
src/type-info.h
src/typing.cc
src/x64/code-stubs-x64.cc
test/mjsunit/array-constructor-feedback.js
test/mjsunit/array-feedback.js

index 585108b2bddf9bf60d3662d0627e642f57dd4545..afea875e9e9a4da5b5f290fc57ad46189466c481 100644 (file)
@@ -2934,13 +2934,11 @@ static void EmitWrapCase(MacroAssembler* masm, int argc, Label* cont) {
 }
 
 
-static void CallFunctionNoFeedback(MacroAssembler* masm,
-                                   int argc, bool needs_checks,
-                                   bool call_as_method) {
+void CallFunctionStub::Generate(MacroAssembler* masm) {
   // r1 : the function to call
   Label slow, non_function, wrap, cont;
 
-  if (needs_checks) {
+  if (NeedsChecks()) {
     // Check that the function is really a JavaScript function.
     // r1: pushed function (to be verified)
     __ JumpIfSmi(r1, &non_function);
@@ -2952,17 +2950,18 @@ static void CallFunctionNoFeedback(MacroAssembler* masm,
 
   // Fast-case: Invoke the function now.
   // r1: pushed function
+  int argc = argc_;
   ParameterCount actual(argc);
 
-  if (call_as_method) {
-    if (needs_checks) {
+  if (CallAsMethod()) {
+    if (NeedsChecks()) {
       EmitContinueIfStrictOrNative(masm, &cont);
     }
 
     // Compute the receiver in sloppy mode.
     __ ldr(r3, MemOperand(sp, argc * kPointerSize));
 
-    if (needs_checks) {
+    if (NeedsChecks()) {
       __ JumpIfSmi(r3, &wrap);
       __ CompareObjectType(r3, r4, r4, FIRST_SPEC_OBJECT_TYPE);
       __ b(lt, &wrap);
@@ -2975,24 +2974,19 @@ static void CallFunctionNoFeedback(MacroAssembler* masm,
 
   __ InvokeFunction(r1, actual, JUMP_FUNCTION, NullCallWrapper());
 
-  if (needs_checks) {
+  if (NeedsChecks()) {
     // Slow-case: Non-function called.
     __ bind(&slow);
     EmitSlowCase(masm, argc, &non_function);
   }
 
-  if (call_as_method) {
+  if (CallAsMethod()) {
     __ bind(&wrap);
     EmitWrapCase(masm, argc, &cont);
   }
 }
 
 
-void CallFunctionStub::Generate(MacroAssembler* masm) {
-  CallFunctionNoFeedback(masm, argc_, NeedsChecks(), CallAsMethod());
-}
-
-
 void CallConstructStub::Generate(MacroAssembler* masm) {
   // r0 : number of arguments
   // r1 : the function to call
@@ -3052,7 +3046,7 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
   __ bind(&do_call);
   // Set expected number of arguments to zero (not changing r0).
   __ mov(r2, Operand::Zero());
-  __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
+  __ Jump(isolate()->builtins()->ArgumentsAdaptorTrampoline(),
           RelocInfo::CODE_TARGET);
 }
 
@@ -3066,51 +3060,6 @@ static void EmitLoadTypeFeedbackVector(MacroAssembler* masm, Register vector) {
 }
 
 
-void CallICStub::Generate_MonomorphicArray(MacroAssembler* masm, Label* miss) {
-  // r1 - function
-  // r2 - feedback vector
-  // r3 - slot id
-  __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, r4);
-  __ cmp(r1, r4);
-  __ b(ne, miss);
-
-  __ mov(r0, Operand(arg_count()));
-  __ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3));
-  __ ldr(r2, FieldMemOperand(r4, FixedArray::kHeaderSize));
-  // Verify that r2 contains an AllocationSite
-  __ AssertUndefinedOrAllocationSite(r2, r4);
-  ArrayConstructorStub stub(masm->isolate(), arg_count());
-  __ TailCallStub(&stub);
-}
-
-
-void CallICStub::Generate_CustomFeedbackCall(MacroAssembler* masm) {
-  // r1 - function
-  // r2 - feedback vector
-  // r3 - slot id
-  Label miss;
-
-  if (state_.stub_type() == CallIC::MONOMORPHIC_ARRAY) {
-    Generate_MonomorphicArray(masm, &miss);
-  } else {
-    // So far there is only one customer for our custom feedback scheme.
-    UNREACHABLE();
-  }
-
-  __ bind(&miss);
-  GenerateMiss(masm);
-
-  // The slow case, we need this no matter what to complete a call after a miss.
-  CallFunctionNoFeedback(masm,
-                         arg_count(),
-                         true,
-                         CallAsMethod());
-
-  // Unreachable.
-  __ stop("Unexpected code address");
-}
-
-
 void CallICStub::Generate(MacroAssembler* masm) {
   // r1 - function
   // r3 - slot id (Smi)
@@ -3122,11 +3071,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
 
   EmitLoadTypeFeedbackVector(masm, r2);
 
-  if (state_.stub_type() != CallIC::DEFAULT) {
-    Generate_CustomFeedbackCall(masm);
-    return;
-  }
-
   // The checks. First, does r1 match the recorded monomorphic target?
   __ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3));
   __ ldr(r4, FieldMemOperand(r4, FixedArray::kHeaderSize));
index d1185b23e131e0a1ed6565f4530a37d3750dff8b..0bf89d89019b36ddb610a402c466f1e48dc6e921 100644 (file)
@@ -3217,10 +3217,10 @@ static void EmitWrapCase(MacroAssembler* masm, int argc, Label* cont) {
 }
 
 
-static void CallFunctionNoFeedback(MacroAssembler* masm,
-                                   int argc, bool needs_checks,
-                                   bool call_as_method) {
+void CallFunctionStub::Generate(MacroAssembler* masm) {
+  ASM_LOCATION("CallFunctionStub::Generate");
   // x1  function    the function to call
+
   Register function = x1;
   Register type = x4;
   Label slow, non_function, wrap, cont;
@@ -3228,7 +3228,7 @@ static void CallFunctionNoFeedback(MacroAssembler* masm,
   // TODO(jbramley): This function has a lot of unnamed registers. Name them,
   // and tidy things up a bit.
 
-  if (needs_checks) {
+  if (NeedsChecks()) {
     // Check that the function is really a JavaScript function.
     __ JumpIfSmi(function, &non_function);
 
@@ -3238,17 +3238,18 @@ static void CallFunctionNoFeedback(MacroAssembler* masm,
 
   // Fast-case: Invoke the function now.
   // x1  function  pushed function
+  int argc = argc_;
   ParameterCount actual(argc);
 
-  if (call_as_method) {
-    if (needs_checks) {
+  if (CallAsMethod()) {
+    if (NeedsChecks()) {
       EmitContinueIfStrictOrNative(masm, &cont);
     }
 
     // Compute the receiver in sloppy mode.
     __ Peek(x3, argc * kPointerSize);
 
-    if (needs_checks) {
+    if (NeedsChecks()) {
       __ JumpIfSmi(x3, &wrap);
       __ JumpIfObjectType(x3, x10, type, FIRST_SPEC_OBJECT_TYPE, &wrap, lt);
     } else {
@@ -3262,25 +3263,20 @@ static void CallFunctionNoFeedback(MacroAssembler* masm,
                     actual,
                     JUMP_FUNCTION,
                     NullCallWrapper());
-  if (needs_checks) {
+
+  if (NeedsChecks()) {
     // Slow-case: Non-function called.
     __ Bind(&slow);
     EmitSlowCase(masm, argc, function, type, &non_function);
   }
 
-  if (call_as_method) {
+  if (CallAsMethod()) {
     __ Bind(&wrap);
     EmitWrapCase(masm, argc, &cont);
   }
 }
 
 
-void CallFunctionStub::Generate(MacroAssembler* masm) {
-  ASM_LOCATION("CallFunctionStub::Generate");
-  CallFunctionNoFeedback(masm, argc_, NeedsChecks(), CallAsMethod());
-}
-
-
 void CallConstructStub::Generate(MacroAssembler* masm) {
   ASM_LOCATION("CallConstructStub::Generate");
   // x0 : number of arguments
@@ -3360,59 +3356,6 @@ static void EmitLoadTypeFeedbackVector(MacroAssembler* masm, Register vector) {
 }
 
 
-void CallICStub::Generate_MonomorphicArray(MacroAssembler* masm, Label* miss) {
-  // x1 - function
-  // x2 - feedback vector
-  // x3 - slot id
-  Register function = x1;
-  Register feedback_vector = x2;
-  Register index = x3;
-  Register scratch = x4;
-
-  __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, scratch);
-  __ Cmp(function, scratch);
-  __ B(ne, miss);
-
-  Register allocation_site = feedback_vector;
-  __ Mov(x0, Operand(arg_count()));
-
-  __ Add(scratch, feedback_vector,
-         Operand::UntagSmiAndScale(index, kPointerSizeLog2));
-  __ Ldr(allocation_site, FieldMemOperand(scratch, FixedArray::kHeaderSize));
-
-  // Verify that x2 contains an AllocationSite
-  __ AssertUndefinedOrAllocationSite(allocation_site, scratch);
-  ArrayConstructorStub stub(masm->isolate(), arg_count());
-  __ TailCallStub(&stub);
-}
-
-
-void CallICStub::Generate_CustomFeedbackCall(MacroAssembler* masm) {
-  // x1 - function
-  // x2 - feedback vector
-  // x3 - slot id
-  Label miss;
-
-  if (state_.stub_type() == CallIC::MONOMORPHIC_ARRAY) {
-    Generate_MonomorphicArray(masm, &miss);
-  } else {
-    // So far there is only one customer for our custom feedback scheme.
-    UNREACHABLE();
-  }
-
-  __ bind(&miss);
-  GenerateMiss(masm);
-
-  // The slow case, we need this no matter what to complete a call after a miss.
-  CallFunctionNoFeedback(masm,
-                         arg_count(),
-                         true,
-                         CallAsMethod());
-
-  __ Unreachable();
-}
-
-
 void CallICStub::Generate(MacroAssembler* masm) {
   ASM_LOCATION("CallICStub");
 
@@ -3431,11 +3374,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
 
   EmitLoadTypeFeedbackVector(masm, feedback_vector);
 
-  if (state_.stub_type() != CallIC::DEFAULT) {
-    Generate_CustomFeedbackCall(masm);
-    return;
-  }
-
   // The checks. First, does x1 match the recorded monomorphic target?
   __ Add(x4, feedback_vector,
          Operand::UntagSmiAndScale(index, kPointerSizeLog2));
index e2ea93354688c3fd82a379cf91321995f50918f4..0115d988272c44e64f326d6f7377619824f2ea41 100644 (file)
--- a/src/ast.h
+++ b/src/ast.h
@@ -1762,25 +1762,11 @@ class Call V8_FINAL : public Expression, public FeedbackSlotInterface {
     return !target_.is_null();
   }
 
-  bool global_call() const {
-    VariableProxy* proxy = expression_->AsVariableProxy();
-    return proxy != NULL && proxy->var()->IsUnallocated();
-  }
-
-  bool known_global_function() const {
-    return global_call() && !target_.is_null();
-  }
-
   Handle<JSFunction> target() { return target_; }
 
   Handle<Cell> cell() { return cell_; }
 
-  Handle<AllocationSite> allocation_site() { return allocation_site_; }
-
   void set_target(Handle<JSFunction> target) { target_ = target; }
-  void set_allocation_site(Handle<AllocationSite> site) {
-    allocation_site_ = site;
-  }
   bool ComputeGlobalTarget(Handle<GlobalObject> global, LookupResult* lookup);
 
   BailoutId ReturnId() const { return return_id_; }
@@ -1823,7 +1809,6 @@ class Call V8_FINAL : public Expression, public FeedbackSlotInterface {
 
   Handle<JSFunction> target_;
   Handle<Cell> cell_;
-  Handle<AllocationSite> allocation_site_;
   int call_feedback_slot_;
 
   const BailoutId return_id_;
index 454029a69d4d7660f2bc39c99bae02a8adcff2cb..41f8fa1b1385c6815cad092f59f973918fc032c7 100644 (file)
@@ -824,8 +824,6 @@ class CallICStub: public PlatformCodeStub {
 
   // Code generation helpers.
   void GenerateMiss(MacroAssembler* masm);
-  void Generate_CustomFeedbackCall(MacroAssembler* masm);
-  void Generate_MonomorphicArray(MacroAssembler* masm, Label* miss);
 
   CallIC::State state_;
 };
index 8e0858dca7ea91be64f320d0f83392c592cbf8d9..6059a2a65317b2d9dfba4505ad2ca835e339523e 100644 (file)
@@ -2474,14 +2474,14 @@ void HGraphBuilder::BuildFillElementsWithHole(HValue* elements,
   }
 
   // Special loop unfolding case
-  STATIC_ASSERT(JSArray::kPreallocatedArrayElements <=
-                kElementLoopUnrollThreshold);
+  static const int kLoopUnfoldLimit = 8;
+  STATIC_ASSERT(JSArray::kPreallocatedArrayElements <= kLoopUnfoldLimit);
   int initial_capacity = -1;
   if (from->IsInteger32Constant() && to->IsInteger32Constant()) {
     int constant_from = from->GetInteger32Constant();
     int constant_to = to->GetInteger32Constant();
 
-    if (constant_from == 0 && constant_to <= kElementLoopUnrollThreshold) {
+    if (constant_from == 0 && constant_to <= kLoopUnfoldLimit) {
       initial_capacity = constant_to;
     }
   }
@@ -8234,56 +8234,6 @@ HValue* HOptimizedGraphBuilder::ImplicitReceiverFor(HValue* function,
 }
 
 
-void HOptimizedGraphBuilder::BuildArrayCall(Expression* expression,
-                                            int arguments_count,
-                                            HValue* function,
-                                            Handle<AllocationSite> site) {
-  Add<HCheckValue>(function, array_function());
-
-  if (IsCallArrayInlineable(arguments_count, site)) {
-    BuildInlinedCallArray(expression, arguments_count, site);
-    return;
-  }
-
-  HInstruction* call = PreProcessCall(New<HCallNewArray>(
-      function, arguments_count + 1, site->GetElementsKind()));
-  if (expression->IsCall()) {
-    Drop(1);
-  }
-  ast_context()->ReturnInstruction(call, expression->id());
-}
-
-
-bool HOptimizedGraphBuilder::TryHandleArrayCall(Call* expr, HValue* function) {
-  if (!array_function().is_identical_to(expr->target())) {
-    return false;
-  }
-
-  Handle<AllocationSite> site = expr->allocation_site();
-  if (site.is_null()) return false;
-
-  BuildArrayCall(expr,
-                 expr->arguments()->length(),
-                 function,
-                 site);
-  return true;
-}
-
-
-bool HOptimizedGraphBuilder::TryHandleArrayCallNew(CallNew* expr,
-                                                   HValue* function) {
-  if (!array_function().is_identical_to(expr->target())) {
-    return false;
-  }
-
-  BuildArrayCall(expr,
-                 expr->arguments()->length(),
-                 function,
-                 expr->allocation_site());
-  return true;
-}
-
-
 void HOptimizedGraphBuilder::VisitCall(Call* expr) {
   ASSERT(!HasStackOverflow());
   ASSERT(current_block() != NULL);
@@ -8378,7 +8328,8 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
     // evaluation of the arguments.
     CHECK_ALIVE(VisitForValue(expr->expression()));
     HValue* function = Top();
-    if (expr->global_call()) {
+    bool global_call = proxy != NULL && proxy->var()->IsUnallocated();
+    if (global_call) {
       Variable* var = proxy->var();
       bool known_global_function = false;
       // If there is a global property cell for the name at compile time and
@@ -8412,7 +8363,6 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
           return;
         }
         if (TryInlineApiFunctionCall(expr, receiver)) return;
-        if (TryHandleArrayCall(expr, function)) return;
         if (TryInlineCall(expr)) return;
 
         PushArgumentsFromEnvironment(argument_count);
@@ -8462,21 +8412,20 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
 }
 
 
-void HOptimizedGraphBuilder::BuildInlinedCallArray(
-    Expression* expression,
-    int argument_count,
-    Handle<AllocationSite> site) {
-  ASSERT(!site.is_null());
-  ASSERT(argument_count >= 0 && argument_count <= 1);
+void HOptimizedGraphBuilder::BuildInlinedCallNewArray(CallNew* expr) {
   NoObservableSideEffectsScope no_effects(this);
 
+  int argument_count = expr->arguments()->length();
   // We should at least have the constructor on the expression stack.
   HValue* constructor = environment()->ExpressionStackAt(argument_count);
 
+  ElementsKind kind = expr->elements_kind();
+  Handle<AllocationSite> site = expr->allocation_site();
+  ASSERT(!site.is_null());
+
   // Register on the site for deoptimization if the transition feedback changes.
   AllocationSite::AddDependentCompilationInfo(
       site, AllocationSite::TRANSITIONS, top_info());
-  ElementsKind kind = site->GetElementsKind();
   HInstruction* site_instruction = Add<HConstant>(site);
 
   // In the single constant argument case, we may have to adjust elements kind
@@ -8499,12 +8448,32 @@ void HOptimizedGraphBuilder::BuildInlinedCallArray(
                                site_instruction,
                                constructor,
                                DISABLE_ALLOCATION_SITES);
-  HValue* new_object = argument_count == 0
-      ? array_builder.AllocateEmptyArray()
-      : BuildAllocateArrayFromLength(&array_builder, Top());
-
-  int args_to_drop = argument_count + (expression->IsCall() ? 2 : 1);
-  Drop(args_to_drop);
+  HValue* new_object;
+  if (argument_count == 0) {
+    new_object = array_builder.AllocateEmptyArray();
+  } else if (argument_count == 1) {
+    HValue* argument = environment()->Top();
+    new_object = BuildAllocateArrayFromLength(&array_builder, argument);
+  } else {
+    HValue* length = Add<HConstant>(argument_count);
+    // Smi arrays need to initialize array elements with the hole because
+    // bailout could occur if the arguments don't fit in a smi.
+    //
+    // TODO(mvstanton): If all the arguments are constants in smi range, then
+    // we could set fill_with_hole to false and save a few instructions.
+    JSArrayBuilder::FillMode fill_mode = IsFastSmiElementsKind(kind)
+        ? JSArrayBuilder::FILL_WITH_HOLE
+        : JSArrayBuilder::DONT_FILL_WITH_HOLE;
+    new_object = array_builder.AllocateArray(length, length, fill_mode);
+    HValue* elements = array_builder.GetElementsLocation();
+    for (int i = 0; i < argument_count; i++) {
+      HValue* value = environment()->ExpressionStackAt(argument_count - i - 1);
+      HValue* constant_i = Add<HConstant>(i);
+      Add<HStoreKeyed>(elements, constant_i, value, kind);
+    }
+  }
+
+  Drop(argument_count + 1);  // drop constructor and args.
   ast_context()->ReturnValue(new_object);
 }
 
@@ -8518,13 +8487,14 @@ static bool IsAllocationInlineable(Handle<JSFunction> constructor) {
 }
 
 
-bool HOptimizedGraphBuilder::IsCallArrayInlineable(
-    int argument_count,
-    Handle<AllocationSite> site) {
+bool HOptimizedGraphBuilder::IsCallNewArrayInlineable(CallNew* expr) {
   Handle<JSFunction> caller = current_info()->closure();
-  Handle<JSFunction> target = array_function();
+  Handle<JSFunction> target(isolate()->native_context()->array_function(),
+                            isolate());
+  int argument_count = expr->arguments()->length();
   // We should have the function plus array arguments on the environment stack.
   ASSERT(environment()->length() >= (argument_count + 1));
+  Handle<AllocationSite> site = expr->allocation_site();
   ASSERT(!site.is_null());
 
   bool inline_ok = false;
@@ -8534,24 +8504,22 @@ bool HOptimizedGraphBuilder::IsCallArrayInlineable(
       HValue* argument = Top();
       if (argument->IsConstant()) {
         // Do not inline if the constant length argument is not a smi or
-        // outside the valid range for unrolled loop initialization.
+        // outside the valid range for a fast array.
         HConstant* constant_argument = HConstant::cast(argument);
         if (constant_argument->HasSmiValue()) {
           int value = constant_argument->Integer32Value();
-          inline_ok = value >= 0 && value <= kElementLoopUnrollThreshold;
+          inline_ok = value >= 0 &&
+              value < JSObject::kInitialMaxFastElementArray;
           if (!inline_ok) {
             TraceInline(target, caller,
-                        "Constant length outside of valid inlining range.");
+                        "Length outside of valid array range");
           }
         }
       } else {
-        TraceInline(target, caller,
-                    "Dont inline [new] Array(n) where n isn't constant.");
+        inline_ok = true;
       }
-    } else if (argument_count == 0) {
-      inline_ok = true;
     } else {
-      TraceInline(target, caller, "Too many arguments to inline.");
+      inline_ok = true;
     }
   } else {
     TraceInline(target, caller, "AllocationSite requested no inlining.");
@@ -8676,10 +8644,25 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) {
   } else {
     // The constructor function is both an operand to the instruction and an
     // argument to the construct call.
-    if (TryHandleArrayCallNew(expr, function)) return;
+    Handle<JSFunction> array_function(
+        isolate()->native_context()->array_function(), isolate());
+    bool use_call_new_array = expr->target().is_identical_to(array_function);
+    if (use_call_new_array && IsCallNewArrayInlineable(expr)) {
+      // Verify we are still calling the array function for our native context.
+      Add<HCheckValue>(function, array_function);
+      BuildInlinedCallNewArray(expr);
+      return;
+    }
 
-    HInstruction* call =
-        PreProcessCall(New<HCallNew>(function, argument_count));
+    HBinaryCall* call;
+    if (use_call_new_array) {
+      Add<HCheckValue>(function, array_function);
+      call = New<HCallNewArray>(function, argument_count,
+                                expr->elements_kind());
+    } else {
+      call = New<HCallNew>(function, argument_count);
+    }
+    PreProcessCall(call);
     return ast_context()->ReturnInstruction(call, expr->id());
   }
 }
index bb05ebbfb4c9043412166980131463c1391fd68e..17cb7d1aa156edfc660f1e0ce1236d054d536d35 100644 (file)
@@ -1295,10 +1295,6 @@ class HGraphBuilder {
 
   void AddSimulate(BailoutId id, RemovableSimulate removable = FIXED_SIMULATE);
 
-  // When initializing arrays, we'll unfold the loop if the number of elements
-  // is known at compile time and is <= kElementLoopUnrollThreshold.
-  static const int kElementLoopUnrollThreshold = 8;
-
  protected:
   virtual bool BuildGraph() = 0;
 
@@ -2246,11 +2242,6 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
   // Try to optimize fun.apply(receiver, arguments) pattern.
   bool TryCallApply(Call* expr);
 
-  bool TryHandleArrayCall(Call* expr, HValue* function);
-  bool TryHandleArrayCallNew(CallNew* expr, HValue* function);
-  void BuildArrayCall(Expression* expr, int arguments_count, HValue* function,
-                      Handle<AllocationSite> cell);
-
   HValue* ImplicitReceiverFor(HValue* function,
                               Handle<JSFunction> target);
 
@@ -2334,13 +2325,8 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
       ElementsKind fixed_elements_kind,
       HValue* byte_length, HValue* length);
 
-  Handle<JSFunction> array_function() {
-    return handle(isolate()->native_context()->array_function());
-  }
-
-  bool IsCallArrayInlineable(int argument_count, Handle<AllocationSite> site);
-  void BuildInlinedCallArray(Expression* expression, int argument_count,
-                             Handle<AllocationSite> site);
+  bool IsCallNewArrayInlineable(CallNew* expr);
+  void BuildInlinedCallNewArray(CallNew* expr);
 
   class PropertyAccessInfo {
    public:
index 5547ba25e86294c7838a7885f0374535f4afb76c..8f9928efb823616902cccfd30cdf0439e78673a4 100644 (file)
@@ -2335,13 +2335,11 @@ static void EmitWrapCase(MacroAssembler* masm, int argc, Label* cont) {
 }
 
 
-static void CallFunctionNoFeedback(MacroAssembler* masm,
-                                   int argc, bool needs_checks,
-                                   bool call_as_method) {
+void CallFunctionStub::Generate(MacroAssembler* masm) {
   // edi : the function to call
   Label slow, non_function, wrap, cont;
 
-  if (needs_checks) {
+  if (NeedsChecks()) {
     // Check that the function really is a JavaScript function.
     __ JumpIfSmi(edi, &non_function);
 
@@ -2351,17 +2349,17 @@ static void CallFunctionNoFeedback(MacroAssembler* masm,
   }
 
   // Fast-case: Just invoke the function.
-  ParameterCount actual(argc);
+  ParameterCount actual(argc_);
 
-  if (call_as_method) {
-    if (needs_checks) {
+  if (CallAsMethod()) {
+    if (NeedsChecks()) {
       EmitContinueIfStrictOrNative(masm, &cont);
     }
 
     // Load the receiver from the stack.
-    __ mov(eax, Operand(esp, (argc + 1) * kPointerSize));
+    __ mov(eax, Operand(esp, (argc_ + 1) * kPointerSize));
 
-    if (call_as_method) {
+    if (NeedsChecks()) {
       __ JumpIfSmi(eax, &wrap);
 
       __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
@@ -2375,25 +2373,20 @@ static void CallFunctionNoFeedback(MacroAssembler* masm,
 
   __ InvokeFunction(edi, actual, JUMP_FUNCTION, NullCallWrapper());
 
-  if (needs_checks) {
+  if (NeedsChecks()) {
     // Slow-case: Non-function called.
     __ bind(&slow);
     // (non_function is bound in EmitSlowCase)
-    EmitSlowCase(masm->isolate(), masm, argc, &non_function);
+    EmitSlowCase(isolate(), masm, argc_, &non_function);
   }
 
-  if (call_as_method) {
+  if (CallAsMethod()) {
     __ bind(&wrap);
-    EmitWrapCase(masm, argc, &cont);
+    EmitWrapCase(masm, argc_, &cont);
   }
 }
 
 
-void CallFunctionStub::Generate(MacroAssembler* masm) {
-  CallFunctionNoFeedback(masm, argc_, NeedsChecks(), CallAsMethod());
-}
-
-
 void CallConstructStub::Generate(MacroAssembler* masm) {
   // eax : number of arguments
   // ebx : feedback vector
@@ -2470,51 +2463,6 @@ static void EmitLoadTypeFeedbackVector(MacroAssembler* masm, Register vector) {
 }
 
 
-void CallICStub::Generate_MonomorphicArray(MacroAssembler* masm, Label* miss) {
-  // edi - function
-  // ebx - feedback vector
-  // edx - slot id
-  __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, ecx);
-  __ cmp(edi, ecx);
-  __ j(not_equal, miss);
-
-  __ mov(eax, arg_count());
-  __ mov(ebx, FieldOperand(ebx, edx, times_half_pointer_size,
-                           FixedArray::kHeaderSize));
-  // Verify that ecx contains an AllocationSite
-  __ AssertUndefinedOrAllocationSite(ebx);
-  ArrayConstructorStub stub(masm->isolate(), arg_count());
-  __ TailCallStub(&stub);
-}
-
-
-void CallICStub::Generate_CustomFeedbackCall(MacroAssembler* masm) {
-  // edi - function
-  // ebx - feedback vector
-  // edx - slot id
-  Label miss;
-
-  if (state_.stub_type() == CallIC::MONOMORPHIC_ARRAY) {
-    Generate_MonomorphicArray(masm, &miss);
-  } else {
-    // So far there is only one customer for our custom feedback scheme.
-    UNREACHABLE();
-  }
-
-  __ bind(&miss);
-  GenerateMiss(masm);
-
-  // The slow case, we need this no matter what to complete a call after a miss.
-  CallFunctionNoFeedback(masm,
-                         arg_count(),
-                         true,
-                         CallAsMethod());
-
-  // Unreachable.
-  __ int3();
-}
-
-
 void CallICStub::Generate(MacroAssembler* masm) {
   // edi - function
   // edx - slot id
@@ -2527,11 +2475,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
 
   EmitLoadTypeFeedbackVector(masm, ebx);
 
-  if (state_.stub_type() != CallIC::DEFAULT) {
-    Generate_CustomFeedbackCall(masm);
-    return;
-  }
-
   // The checks. First, does edi match the recorded monomorphic target?
   __ cmp(edi, FieldOperand(ebx, edx, times_half_pointer_size,
                            FixedArray::kHeaderSize));
index 463429e41787c803b0b2cebbd48010641ef0a715..28bbd94e82837600a808d4a56e58514fd26db918 100644 (file)
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -501,14 +501,7 @@ void CallIC::Clear(Isolate* isolate,
                    Code* target,
                    ConstantPoolArray* constant_pool) {
   // Currently, CallIC doesn't have state changes.
-  if (target->ic_state() != v8::internal::MONOMORPHIC) return;
-  CallIC::State existing_state(target->extra_ic_state());
-
-  // Monomorphic array stubs don't need to be cleared because
-  // 1) the stub doesn't store information that should be cleared, and
-  // 2) the AllocationSite stored in the type feedback vector is immune
-  //    from gc type feedback clearing.
-  ASSERT(existing_state.stub_type() == MONOMORPHIC_ARRAY);
+  ASSERT(target->ic_state() == v8::internal::GENERIC);
 }
 
 
@@ -1825,49 +1818,18 @@ MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
 
 CallIC::State::State(ExtraICState extra_ic_state)
     : argc_(ArgcBits::decode(extra_ic_state)),
-      call_type_(CallTypeBits::decode(extra_ic_state)),
-      stub_type_(StubTypeBits::decode(extra_ic_state)) {
+      call_type_(CallTypeBits::decode(extra_ic_state)) {
 }
 
 
 ExtraICState CallIC::State::GetExtraICState() const {
   ExtraICState extra_ic_state =
       ArgcBits::encode(argc_) |
-      CallTypeBits::encode(call_type_) |
-      StubTypeBits::encode(stub_type_);
+      CallTypeBits::encode(call_type_);
   return extra_ic_state;
 }
 
 
-bool CallIC::DoCustomHandler(Handle<Object> receiver,
-                             Handle<Object> function,
-                             Handle<FixedArray> vector,
-                             Handle<Smi> slot,
-                             const State& state) {
-  ASSERT(function->IsJSFunction());
-  // Are we the array function?
-  Handle<JSFunction> array_function = Handle<JSFunction>(
-      isolate()->context()->native_context()->array_function(), isolate());
-  if (array_function.is_identical_to(Handle<JSFunction>::cast(function))) {
-    // Alter the slot.
-    Handle<AllocationSite> new_site = isolate()->factory()->NewAllocationSite();
-    vector->set(slot->value(), *new_site);
-    State new_state = state.ToMonomorphicArrayCallState();
-    CallICStub stub(isolate(), new_state);
-    set_target(*stub.GetCode());
-    Handle<String> name;
-    if (array_function->shared()->name()->IsString()) {
-      name = Handle<String>(String::cast(array_function->shared()->name()),
-                            isolate());
-    }
-
-    TRACE_IC("CallIC (Array call)", name);
-    return true;
-  }
-  return false;
-}
-
-
 void CallIC::HandleMiss(Handle<Object> receiver,
                         Handle<Object> function,
                         Handle<FixedArray> vector,
@@ -1875,33 +1837,18 @@ void CallIC::HandleMiss(Handle<Object> receiver,
   State state(target()->extra_ic_state());
   Object* feedback = vector->get(slot->value());
 
-  if (feedback->IsJSFunction() || !function->IsJSFunction() ||
-      state.stub_type() != DEFAULT) {
+  if (feedback->IsJSFunction() || !function->IsJSFunction()) {
     // We are going generic.
+    ASSERT(!function->IsJSFunction() || *function != feedback);
+
     vector->set(slot->value(),
                 *TypeFeedbackInfo::MegamorphicSentinel(isolate()),
                 SKIP_WRITE_BARRIER);
-
-    State new_state = state.ToGenericState();
-    if (new_state != state) {
-      // Only happens when the array ic goes generic.
-      ASSERT(state.stub_type() == MONOMORPHIC_ARRAY);
-      CallICStub stub(isolate(), new_state);
-      Handle<Code> code = stub.GetCode();
-      set_target(*code);
-    }
-
     TRACE_GENERIC_IC(isolate(), "CallIC", "megamorphic");
   } else {
     // If we came here feedback must be the uninitialized sentinel,
     // and we are going monomorphic.
     ASSERT(feedback == *TypeFeedbackInfo::UninitializedSentinel(isolate()));
-
-    // Do we want to install a custom handler?
-    if (DoCustomHandler(receiver, function, vector, slot, state)) {
-      return;
-    }
-
     Handle<JSFunction> js_function = Handle<JSFunction>::cast(function);
     Handle<Object> name(js_function->shared()->name(), isolate());
     TRACE_IC("CallIC", name);
index 20b9b73d583cc1ecc7f7158cd6257010e9347e1b..197c32e6a55515c787628bab1ac5c91bc5df1cd1 100644 (file)
--- a/src/ic.h
+++ b/src/ic.h
@@ -333,34 +333,20 @@ class IC_Utility {
 class CallIC: public IC {
  public:
   enum CallType { METHOD, FUNCTION };
-  enum StubType { DEFAULT, MONOMORPHIC_ARRAY };
 
   class State V8_FINAL BASE_EMBEDDED {
    public:
     explicit State(ExtraICState extra_ic_state);
 
-    static State MonomorphicArrayCallState(int argc, CallType call_type) {
-      return State(argc, call_type, MONOMORPHIC_ARRAY);
-    }
-
     static State DefaultCallState(int argc, CallType call_type) {
-      return State(argc, call_type, DEFAULT);
+      return State(argc, call_type);
     }
 
-    // Transition from the current state to another.
-    State ToGenericState() const {
-      return DefaultCallState(arg_count(), call_type());
+    static State MegamorphicCallState(int argc, CallType call_type) {
+      return State(argc, call_type);
     }
 
-    State ToMonomorphicArrayCallState() const {
-      return MonomorphicArrayCallState(arg_count(), call_type());
-    }
-
-    InlineCacheState GetICState() const {
-      return stub_type_ == CallIC::DEFAULT
-          ? ::v8::internal::GENERIC
-          : ::v8::internal::MONOMORPHIC;
-    }
+    InlineCacheState GetICState() const { return ::v8::internal::GENERIC; }
 
     ExtraICState GetExtraICState() const;
 
@@ -369,7 +355,6 @@ class CallIC: public IC {
 
     int arg_count() const { return argc_; }
     CallType call_type() const { return call_type_; }
-    StubType stub_type() const { return stub_type_; }
 
     bool CallAsMethod() const { return call_type_ == METHOD; }
 
@@ -385,20 +370,17 @@ class CallIC: public IC {
     }
 
    private:
-    State(int argc, CallType call_type, StubType stub_type)
+    State(int argc,
+          CallType call_type)
         : argc_(argc),
-        call_type_(call_type),
-        stub_type_(stub_type) {
+        call_type_(call_type) {
     }
 
     class ArgcBits: public BitField<int, 0, Code::kArgumentsBits> {};
     class CallTypeBits: public BitField<CallType, Code::kArgumentsBits, 1> {};
-    class StubTypeBits:
-        public BitField<StubType, Code::kArgumentsBits + 1, 1> {};  // NOLINT
 
     const int argc_;
     const CallType call_type_;
-    const StubType stub_type_;
   };
 
   explicit CallIC(Isolate* isolate)
@@ -410,13 +392,6 @@ class CallIC: public IC {
                   Handle<FixedArray> vector,
                   Handle<Smi> slot);
 
-  // Returns true if a custom handler was installed.
-  bool DoCustomHandler(Handle<Object> receiver,
-                       Handle<Object> function,
-                       Handle<FixedArray> vector,
-                       Handle<Smi> slot,
-                       const State& new_state);
-
   // Code generator routines.
   static Handle<Code> initialize_stub(Isolate* isolate,
                                       int argc,
index f47ab381fd7222363dd0fb71671e8663be1bbf9e..6e033b9468a59d83a4b97ee0e27677c68adef7c0 100644 (file)
@@ -3094,13 +3094,11 @@ static void EmitWrapCase(MacroAssembler* masm, int argc, Label* cont) {
 }
 
 
-static void CallFunctionNoFeedback(MacroAssembler* masm,
-                                   int argc, bool needs_checks,
-                                   bool call_as_method) {
+void CallFunctionStub::Generate(MacroAssembler* masm) {
   // a1 : the function to call
   Label slow, non_function, wrap, cont;
 
-  if (needs_checks) {
+  if (NeedsChecks()) {
     // Check that the function is really a JavaScript function.
     // a1: pushed function (to be verified)
     __ JumpIfSmi(a1, &non_function);
@@ -3112,17 +3110,18 @@ static void CallFunctionNoFeedback(MacroAssembler* masm,
 
   // Fast-case: Invoke the function now.
   // a1: pushed function
+  int argc = argc_;
   ParameterCount actual(argc);
 
-  if (call_as_method) {
-    if (needs_checks) {
+  if (CallAsMethod()) {
+    if (NeedsChecks()) {
       EmitContinueIfStrictOrNative(masm, &cont);
     }
 
     // Compute the receiver in sloppy mode.
     __ lw(a3, MemOperand(sp, argc * kPointerSize));
 
-    if (needs_checks) {
+    if (NeedsChecks()) {
       __ JumpIfSmi(a3, &wrap);
       __ GetObjectType(a3, t0, t0);
       __ Branch(&wrap, lt, t0, Operand(FIRST_SPEC_OBJECT_TYPE));
@@ -3135,13 +3134,13 @@ static void CallFunctionNoFeedback(MacroAssembler* masm,
 
   __ InvokeFunction(a1, actual, JUMP_FUNCTION, NullCallWrapper());
 
-  if (needs_checks) {
+  if (NeedsChecks()) {
     // Slow-case: Non-function called.
     __ bind(&slow);
     EmitSlowCase(masm, argc, &non_function);
   }
 
-  if (call_as_method) {
+  if (CallAsMethod()) {
     __ bind(&wrap);
     // Wrap the receiver and patch it back onto the stack.
     EmitWrapCase(masm, argc, &cont);
@@ -3149,11 +3148,6 @@ static void CallFunctionNoFeedback(MacroAssembler* masm,
 }
 
 
-void CallFunctionStub::Generate(MacroAssembler* masm) {
-  CallFunctionNoFeedback(masm, argc_, NeedsChecks(), CallAsMethod());
-}
-
-
 void CallConstructStub::Generate(MacroAssembler* masm) {
   // a0 : number of arguments
   // a1 : the function to call
@@ -3213,8 +3207,8 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
   __ bind(&do_call);
   // Set expected number of arguments to zero (not changing r0).
   __ li(a2, Operand(0, RelocInfo::NONE32));
-  __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
-           RelocInfo::CODE_TARGET);
+  __ Jump(isolate()->builtins()->ArgumentsAdaptorTrampoline(),
+          RelocInfo::CODE_TARGET);
 }
 
 
@@ -3227,51 +3221,6 @@ static void EmitLoadTypeFeedbackVector(MacroAssembler* masm, Register vector) {
 }
 
 
-void CallICStub::Generate_MonomorphicArray(MacroAssembler* masm, Label* miss) {
-  // a1 - function
-  // a2 - feedback vector
-  // a3 - slot id
-  __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, at);
-  __ Branch(miss, ne, a1, Operand(at));
-
-  __ li(a0, Operand(arg_count()));
-  __ sll(at, a3, kPointerSizeLog2 - kSmiTagSize);
-  __ Addu(at, a2, Operand(at));
-  __ lw(a2, FieldMemOperand(at, FixedArray::kHeaderSize));
-  // Verify that a2 contains an AllocationSite
-  __ AssertUndefinedOrAllocationSite(a2, at);
-  ArrayConstructorStub stub(masm->isolate(), arg_count());
-  __ TailCallStub(&stub);
-}
-
-
-void CallICStub::Generate_CustomFeedbackCall(MacroAssembler* masm) {
-  // a1 - function
-  // a2 - feedback vector
-  // a3 - slot id
-  Label miss;
-
-  if (state_.stub_type() == CallIC::MONOMORPHIC_ARRAY) {
-    Generate_MonomorphicArray(masm, &miss);
-  } else {
-    // So far there is only one customer for our custom feedback scheme.
-    UNREACHABLE();
-  }
-
-  __ bind(&miss);
-  GenerateMiss(masm);
-
-  // The slow case, we need this no matter what to complete a call after a miss.
-  CallFunctionNoFeedback(masm,
-                         arg_count(),
-                         true,
-                         CallAsMethod());
-
-  // Unreachable.
-  __ stop("Unexpected code address");
-}
-
-
 void CallICStub::Generate(MacroAssembler* masm) {
   // r1 - function
   // r3 - slot id (Smi)
@@ -3283,11 +3232,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
 
   EmitLoadTypeFeedbackVector(masm, a2);
 
-  if (state_.stub_type() != CallIC::DEFAULT) {
-    Generate_CustomFeedbackCall(masm);
-    return;
-  }
-
   // The checks. First, does r1 match the recorded monomorphic target?
   __ sll(t0, a3, kPointerSizeLog2 - kSmiTagSize);
   __ Addu(t0, a2, Operand(t0));
index b09e1a0530c5c4c9077ae4e01c0ea5c2db6b9135..d523d77856b098ef848ae4668ec389a1366c44c7 100644 (file)
@@ -11205,30 +11205,13 @@ void Code::ClearInlineCaches(Code::Kind* kind) {
 void SharedFunctionInfo::ClearTypeFeedbackInfo() {
   FixedArray* vector = feedback_vector();
   Heap* heap = GetHeap();
-  int length = vector->length();
-
-  for (int i = 0; i < length; i++) {
+  for (int i = 0; i < vector->length(); i++) {
     Object* obj = vector->get(i);
-    if (obj->IsHeapObject()) {
-      InstanceType instance_type =
-          HeapObject::cast(obj)->map()->instance_type();
-      switch (instance_type) {
-        case ALLOCATION_SITE_TYPE:
-          // AllocationSites are not cleared because they do not store
-          // information that leaks.
-          break;
-        case JS_FUNCTION_TYPE:
-          // No need to clear the native context array function.
-          if (obj == JSFunction::cast(obj)->context()->native_context()->
-              get(Context::ARRAY_FUNCTION_INDEX)) {
-            break;
-          }
-          // Fall through...
-
-        default:
-          vector->set(i, TypeFeedbackInfo::RawUninitializedSentinel(heap),
-                      SKIP_WRITE_BARRIER);
-      }
+    if (!obj->IsAllocationSite()) {
+      vector->set(
+          i,
+          TypeFeedbackInfo::RawUninitializedSentinel(heap),
+          SKIP_WRITE_BARRIER);
     }
   }
 }
index ca3baa1215ff29afba9e3a11b7c628c3040e4b22..83fcd0f25e79f030a6593b5984ab1ea25235806e 100644 (file)
@@ -97,7 +97,9 @@ bool TypeFeedbackOracle::StoreIsKeyedPolymorphic(TypeFeedbackId ast_id) {
 
 bool TypeFeedbackOracle::CallIsMonomorphic(int slot) {
   Handle<Object> value = GetInfo(slot);
-  return value->IsAllocationSite() || value->IsJSFunction();
+  return FLAG_pretenuring_call_new
+      ? value->IsJSFunction()
+      : value->IsAllocationSite() || value->IsJSFunction();
 }
 
 
@@ -132,10 +134,7 @@ KeyedAccessStoreMode TypeFeedbackOracle::GetStoreMode(
 
 Handle<JSFunction> TypeFeedbackOracle::GetCallTarget(int slot) {
   Handle<Object> info = GetInfo(slot);
-  if (info->IsAllocationSite()) {
-    ASSERT(!FLAG_pretenuring_call_new);
-    return Handle<JSFunction>(isolate()->native_context()->array_function());
-  } else {
+  if (FLAG_pretenuring_call_new || info->IsJSFunction()) {
     return Handle<JSFunction>::cast(info);
   }
 
@@ -155,15 +154,6 @@ Handle<JSFunction> TypeFeedbackOracle::GetCallNewTarget(int slot) {
 }
 
 
-Handle<AllocationSite> TypeFeedbackOracle::GetCallAllocationSite(int slot) {
-  Handle<Object> info = GetInfo(slot);
-  if (info->IsAllocationSite()) {
-    return Handle<AllocationSite>::cast(info);
-  }
-  return Handle<AllocationSite>::null();
-}
-
-
 Handle<AllocationSite> TypeFeedbackOracle::GetCallNewAllocationSite(int slot) {
   Handle<Object> info = GetInfo(slot);
   if (FLAG_pretenuring_call_new || info->IsAllocationSite()) {
index 6b9982670681c76a5cc01109f29ffeb89b57b05b..24a9edbd33698965efc3c4a8df0c23f8ce907eb6 100644 (file)
@@ -65,7 +65,6 @@ class TypeFeedbackOracle: public ZoneObject {
                                     Context* native_context);
 
   Handle<JSFunction> GetCallTarget(int slot);
-  Handle<AllocationSite> GetCallAllocationSite(int slot);
   Handle<JSFunction> GetCallNewTarget(int slot);
   Handle<AllocationSite> GetCallNewAllocationSite(int slot);
 
index f32f0eb393d7c6943146371aee5e2f5eca35391e..434aff349055d179256a501d2b18b6a137afaade 100644 (file)
@@ -511,9 +511,6 @@ void AstTyper::VisitCall(Call* expr) {
       expr->IsUsingCallFeedbackSlot(isolate()) &&
       oracle()->CallIsMonomorphic(expr->CallFeedbackSlot())) {
     expr->set_target(oracle()->GetCallTarget(expr->CallFeedbackSlot()));
-    Handle<AllocationSite> site =
-        oracle()->GetCallAllocationSite(expr->CallFeedbackSlot());
-    expr->set_allocation_site(site);
   }
 
   ZoneList<Expression*>* args = expr->arguments();
index a63288f2cb59ee4df39109fff6e69e3384ebbfb2..0e53eb390ed1bafc32a948c663c84e7b528f4650 100644 (file)
@@ -2228,17 +2228,16 @@ static void EmitWrapCase(MacroAssembler* masm,
 }
 
 
-static void CallFunctionNoFeedback(MacroAssembler* masm,
-                                   int argc, bool needs_checks,
-                                   bool call_as_method) {
+void CallFunctionStub::Generate(MacroAssembler* masm) {
   // rdi : the function to call
 
   // wrap_and_call can only be true if we are compiling a monomorphic method.
   Isolate* isolate = masm->isolate();
   Label slow, non_function, wrap, cont;
+  int argc = argc_;
   StackArgumentsAccessor args(rsp, argc);
 
-  if (needs_checks) {
+  if (NeedsChecks()) {
     // Check that the function really is a JavaScript function.
     __ JumpIfSmi(rdi, &non_function);
 
@@ -2250,15 +2249,15 @@ static void CallFunctionNoFeedback(MacroAssembler* masm,
   // Fast-case: Just invoke the function.
   ParameterCount actual(argc);
 
-  if (call_as_method) {
-    if (needs_checks) {
+  if (CallAsMethod()) {
+    if (NeedsChecks()) {
       EmitContinueIfStrictOrNative(masm, &cont);
     }
 
     // Load the receiver from the stack.
     __ movp(rax, args.GetReceiverOperand());
 
-    if (needs_checks) {
+    if (NeedsChecks()) {
       __ JumpIfSmi(rax, &wrap);
 
       __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx);
@@ -2272,24 +2271,19 @@ static void CallFunctionNoFeedback(MacroAssembler* masm,
 
   __ InvokeFunction(rdi, actual, JUMP_FUNCTION, NullCallWrapper());
 
-  if (needs_checks) {
+  if (NeedsChecks()) {
     // Slow-case: Non-function called.
     __ bind(&slow);
     EmitSlowCase(isolate, masm, &args, argc, &non_function);
   }
 
-  if (call_as_method) {
+  if (CallAsMethod()) {
     __ bind(&wrap);
     EmitWrapCase(masm, &args, &cont);
   }
 }
 
 
-void CallFunctionStub::Generate(MacroAssembler* masm) {
-  CallFunctionNoFeedback(masm, argc_, NeedsChecks(), CallAsMethod());
-}
-
-
 void CallConstructStub::Generate(MacroAssembler* masm) {
   // rax : number of arguments
   // rbx : feedback vector
@@ -2364,54 +2358,6 @@ static void EmitLoadTypeFeedbackVector(MacroAssembler* masm, Register vector) {
 }
 
 
-void CallICStub::Generate_MonomorphicArray(MacroAssembler* masm, Label* miss) {
-  // rdi - function
-  // rbx - feedback vector
-  // rdx - slot id (as integer)
-  __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, rcx);
-  __ cmpq(rdi, rcx);
-  __ j(not_equal, miss);
-
-  __ movq(rax, Immediate(arg_count()));
-  __ movp(rbx, FieldOperand(rbx, rdx, times_pointer_size,
-                            FixedArray::kHeaderSize));
-
-  // Verify that ecx contains an AllocationSite
-  __ AssertUndefinedOrAllocationSite(rbx);
-  ArrayConstructorStub stub(masm->isolate(), arg_count());
-  __ TailCallStub(&stub);
-}
-
-
-void CallICStub::Generate_CustomFeedbackCall(MacroAssembler* masm) {
-  // rdi - function
-  // rbx - feedback vector
-  // rdx - slot id
-  Label miss;
-
-  __ SmiToInteger32(rdx, rdx);
-
-  if (state_.stub_type() == CallIC::MONOMORPHIC_ARRAY) {
-    Generate_MonomorphicArray(masm, &miss);
-  } else {
-    // So far there is only one customer for our custom feedback scheme.
-    UNREACHABLE();
-  }
-
-  __ bind(&miss);
-  GenerateMiss(masm);
-
-  // The slow case, we need this no matter what to complete a call after a miss.
-  CallFunctionNoFeedback(masm,
-                         arg_count(),
-                         true,
-                         CallAsMethod());
-
-  // Unreachable.
-  __ int3();
-}
-
-
 void CallICStub::Generate(MacroAssembler* masm) {
   // rdi - function
   // rbx - vector
@@ -2426,11 +2372,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
 
   EmitLoadTypeFeedbackVector(masm, rbx);
 
-  if (state_.stub_type() != CallIC::DEFAULT) {
-    Generate_CustomFeedbackCall(masm);
-    return;
-  }
-
   // The checks. First, does rdi match the recorded monomorphic target?
   __ SmiToInteger32(rdx, rdx);
   __ cmpq(rdi, FieldOperand(rbx, rdx, times_pointer_size,
index 9bc62e447a79a86f78fdff3455ec8efb0f59a0ea..45d5c58c7726630982795ec598d547c3551b3143 100644 (file)
@@ -150,11 +150,18 @@ if (support_smi_only_arrays) {
     a = bar(10);
     assertKind(elements_kind.fast, a);
     assertOptimized(bar);
+    // bar should deopt because the length is too large.
+    a = bar(100000);
+    assertUnoptimized(bar);
+    assertKind(elements_kind.dictionary, a);
+    // The allocation site now has feedback that means the array constructor
+    // will not be inlined.
+    %OptimizeFunctionOnNextCall(bar);
     a = bar(100000);
     assertKind(elements_kind.dictionary, a);
     assertOptimized(bar);
 
-    // If the argument isn't a smi, things should still work.
+    // If the argument isn't a smi, it bails out as well
     a = bar("oops");
     assertOptimized(bar);
     assertKind(elements_kind.fast, a);
@@ -169,6 +176,12 @@ if (support_smi_only_arrays) {
     barn(1, 2, 3);
     assertOptimized(barn);
     a = barn(1, "oops", 3);
+    // The method should deopt, but learn from the failure to avoid inlining
+    // the array.
+    assertKind(elements_kind.fast, a);
+    assertUnoptimized(barn);
+    %OptimizeFunctionOnNextCall(barn);
+    a = barn(1, "oops", 3);
     assertOptimized(barn);
   })();
 
@@ -215,8 +228,10 @@ if (support_smi_only_arrays) {
     assertTrue(Realm.eval(contextB, "bar2() instanceof Array"));
   })();
 
-  // Test: create array with packed feedback, then optimize function, which
-  // should deal with arguments that create holey arrays.
+  // Test: create array with packed feedback, then optimize/inline
+  // function. Verify that if we ask for a holey array then we deopt.
+  // Reoptimization will proceed with the correct feedback and we
+  // won't deopt anymore.
   (function() {
     function bar(len) { return new Array(len); }
     bar(0);
@@ -226,16 +241,15 @@ if (support_smi_only_arrays) {
     assertOptimized(bar);
     assertFalse(isHoley(a));
     a = bar(1);  // ouch!
-    assertOptimized(bar);
+    assertUnoptimized(bar);
     assertTrue(isHoley(a));
+    // Try again
+    %OptimizeFunctionOnNextCall(bar);
     a = bar(100);
+    assertOptimized(bar);
     assertTrue(isHoley(a));
     a = bar(0);
     assertOptimized(bar);
-    // Crankshafted functions don't use mementos, so feedback still
-    // indicates a packed array is desired. (unless --nocrankshaft is in use).
-    if (4 != %GetOptimizationStatus(bar)) {
-      assertFalse(isHoley(a));
-    }
+    assertTrue(isHoley(a));
   })();
 }
index cb91995230215f291c96437886c4d182969d084e..4129be1f880cb7974ec15d784707b1e2412fea0f 100644 (file)
@@ -85,69 +85,69 @@ if (support_smi_only_arrays) {
   // Verify that basic elements kind feedback works for non-constructor
   // array calls (as long as the call is made through an IC, and not
   // a CallStub).
-  (function (){
-    function create0() {
-      return Array();
-    }
-
-    // Calls through ICs need warm up through uninitialized, then
-    // premonomorphic first.
-    create0();
-    a = create0();
-    assertKind(elements_kind.fast_smi_only, a);
-    a[0] = 3.5;
-    b = create0();
-    assertKind(elements_kind.fast_double, b);
-
-    function create1(arg) {
-      return Array(arg);
-    }
-
-    create1(0);
-    create1(0);
-    a = create1(0);
-    assertFalse(isHoley(a));
-    assertKind(elements_kind.fast_smi_only, a);
-    a[0] = "hello";
-    b = create1(10);
-    assertTrue(isHoley(b));
-    assertKind(elements_kind.fast, b);
-
-    a = create1(100000);
-    assertKind(elements_kind.dictionary, a);
-
-    function create3(arg1, arg2, arg3) {
-      return Array(arg1, arg2, arg3);
-    }
-
-    create3(1,2,3);
-    create3(1,2,3);
-    a = create3(1,2,3);
-    a[0] = 3.035;
-    assertKind(elements_kind.fast_double, a);
-    b = create3(1,2,3);
-    assertKind(elements_kind.fast_double, b);
-    assertFalse(isHoley(b));
-  })();
+  // (function (){
+  //   function create0() {
+  //     return Array();
+  //   }
+
+  //   // Calls through ICs need warm up through uninitialized, then
+  //   // premonomorphic first.
+  //   create0();
+  //   create0();
+  //   a = create0();
+  //   assertKind(elements_kind.fast_smi_only, a);
+  //   a[0] = 3.5;
+  //   b = create0();
+  //   assertKind(elements_kind.fast_double, b);
+
+  //   function create1(arg) {
+  //     return Array(arg);
+  //   }
+
+  //   create1(0);
+  //   create1(0);
+  //   a = create1(0);
+  //   assertFalse(isHoley(a));
+  //   assertKind(elements_kind.fast_smi_only, a);
+  //   a[0] = "hello";
+  //   b = create1(10);
+  //   assertTrue(isHoley(b));
+  //   assertKind(elements_kind.fast, b);
+
+  //   a = create1(100000);
+  //   assertKind(elements_kind.dictionary, a);
+
+  //   function create3(arg1, arg2, arg3) {
+  //     return Array(arg1, arg2, arg3);
+  //   }
+
+  //   create3();
+  //   create3();
+  //   a = create3(1,2,3);
+  //   a[0] = 3.5;
+  //   b = create3(1,2,3);
+  //   assertKind(elements_kind.fast_double, b);
+  //   assertFalse(isHoley(b));
+  // })();
 
 
   // Verify that keyed calls work
-  (function (){
-    function create0(name) {
-      return this[name]();
-    }
-
-    name = "Array";
-    create0(name);
-    create0(name);
-    a = create0(name);
-    a[0] = 3.5;
-    b = create0(name);
-    assertKind(elements_kind.fast_double, b);
-  })();
-
-
-  // Verify that crankshaft consumes type feedback.
+  // (function (){
+  //   function create0(name) {
+  //     return this[name]();
+  //   }
+
+  //   name = "Array";
+  //   create0(name);
+  //   create0(name);
+  //   a = create0(name);
+  //   a[0] = 3.5;
+  //   b = create0(name);
+  //   assertKind(elements_kind.fast_double, b);
+  // })();
+
+
+  // Verify that the IC can't be spoofed by patching
   (function (){
     function create0() {
       return Array();
@@ -156,40 +156,41 @@ if (support_smi_only_arrays) {
     create0();
     create0();
     a = create0();
-    a[0] = 3.5;
-    %OptimizeFunctionOnNextCall(create0);
-    create0();
-    create0();
+    assertKind(elements_kind.fast_smi_only, a);
+    var oldArray = this.Array;
+    this.Array = function() { return ["hi"]; };
     b = create0();
-    assertKind(elements_kind.fast_double, b);
-    assertOptimized(create0);
-
-    function create1(arg) {
-      return Array(arg);
-    }
+    assertEquals(["hi"], b);
+    this.Array = oldArray;
+  })();
 
-    create1(8);
-    create1(8);
-    a = create1(8);
-    a[0] = 3.5;
-    %OptimizeFunctionOnNextCall(create1);
-    b = create1(8);
-    assertKind(elements_kind.fast_double, b);
-    assertOptimized(create1);
-
-    function createN(arg1, arg2, arg3) {
-      return Array(arg1, arg2, arg3);
-    }
+  // Verify that calls are still made through an IC after crankshaft,
+  // though the type information is reset.
+  // TODO(mvstanton): instead, consume the type feedback gathered up
+  // until crankshaft time.
+  // (function (){
+  //   function create0() {
+  //     return Array();
+  //   }
+
+  //   create0();
+  //   create0();
+  //   a = create0();
+  //   a[0] = 3.5;
+  //   %OptimizeFunctionOnNextCall(create0);
+  //   create0();
+  //   // This test only makes sense if crankshaft is allowed
+  //   if (4 != %GetOptimizationStatus(create0)) {
+  //     create0();
+  //     b = create0();
+  //     assertKind(elements_kind.fast_smi_only, b);
+  //     b[0] = 3.5;
+  //     c = create0();
+  //     assertKind(elements_kind.fast_double, c);
+  //     assertOptimized(create0);
+  //   }
+  // })();
 
-    createN(1, 2, 3);
-    createN(1, 2, 3);
-    a = createN(1, 2, 3);
-    a[0] = 3.5;
-    %OptimizeFunctionOnNextCall(createN);
-    b = createN(1, 2, 3);
-    assertKind(elements_kind.fast_double, b);
-    assertOptimized(createN);
-  })();
 
   // Verify that cross context calls work
   (function (){