Revision: 22668
Author:   [email protected]
Date:     Tue Jul 29 11:53:30 2014 UTC
Log: CallIC customization stubs must accept that a vector slot is cleared.

The CallIC Array custom IC stub read from the type vector, expecting
to get an AllocationSite. But there are paths in the system where a
type vector can be re-created with default values, even though we
currently grant an exception to clearing of vector slots with
AllocationSites in them at gc time.

BUG=392114
LOG=N
[email protected]

Review URL: https://codereview.chromium.org/418023002
http://code.google.com/p/v8/source/detail?r=22668

Added:
 /branches/bleeding_edge/test/mjsunit/regress/regress-392114.js
Modified:
 /branches/bleeding_edge/src/arm/code-stubs-arm.cc
 /branches/bleeding_edge/src/arm64/code-stubs-arm64.cc
 /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc
 /branches/bleeding_edge/src/ic.cc
 /branches/bleeding_edge/src/x64/code-stubs-x64.cc

=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/mjsunit/regress/regress-392114.js Tue Jul 29 11:53:30 2014 UTC
@@ -0,0 +1,66 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug --allow-natives-syntax
+
+Debug = debug.Debug;
+
+function dummy(x) {
+  return x + 100;
+}
+
+function create_closure() {
+  var f = function(arg) {
+    if (arg) { %DeoptimizeFunction(f); }
+    var a = Array(10);
+    for (var i = 0; i < a.length; i++) {
+      a[i] = i;
+    }
+  }
+  return f;
+}
+
+var c = create_closure();
+c();
+
+// c CallIC state now has custom Array handler installed.
+
+// Turn on the debugger.
+Debug.setListener(function () {});
+
+var d = create_closure();
+%OptimizeFunctionOnNextCall(d);
+// Thanks to the debugger, we recreate the full code too. We deopt and run
+// it, stomping on the unexpected AllocationSite in the type vector slot.
+d(true);
+
+// CallIC in c misinterprets type vector slot contents as an AllocationSite,
+// corrupting the heap.
+c();
+
+// CallIC MISS - crash due to corruption.
+dummy();
=======================================
--- /branches/bleeding_edge/src/arm/code-stubs-arm.cc Fri Jul 25 17:50:53 2014 UTC +++ /branches/bleeding_edge/src/arm/code-stubs-arm.cc Tue Jul 29 11:53:30 2014 UTC
@@ -2958,9 +2958,14 @@

   __ 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);
+  __ ldr(r4, FieldMemOperand(r4, FixedArray::kHeaderSize));
+
+  // Verify that r4 contains an AllocationSite
+  __ ldr(r5, FieldMemOperand(r4, HeapObject::kMapOffset));
+  __ CompareRoot(r5, Heap::kAllocationSiteMapRootIndex);
+  __ b(ne, &miss);
+
+  __ mov(r2, r4);
   ArrayConstructorStub stub(masm->isolate(), arg_count());
   __ TailCallStub(&stub);

@@ -3027,7 +3032,11 @@
   __ b(eq, &miss);

   if (!FLAG_trace_ic) {
-    // We are going megamorphic, and we don't want to visit the runtime.
+ // We are going megamorphic. If the feedback is a JSFunction, it is fine
+    // to handle it here. More complex cases are dealt with in the runtime.
+    __ AssertNotSmi(r4);
+    __ CompareObjectType(r4, r5, r5, JS_FUNCTION_TYPE);
+    __ b(ne, &miss);
     __ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3));
     __ LoadRoot(ip, Heap::kMegamorphicSymbolRootIndex);
     __ str(ip, FieldMemOperand(r4, FixedArray::kHeaderSize));
=======================================
--- /branches/bleeding_edge/src/arm64/code-stubs-arm64.cc Fri Jul 25 17:50:53 2014 UTC +++ /branches/bleeding_edge/src/arm64/code-stubs-arm64.cc Tue Jul 29 11:53:30 2014 UTC
@@ -3222,15 +3222,19 @@
   __ 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));
+  __ Ldr(scratch, FieldMemOperand(scratch, FixedArray::kHeaderSize));

-  // Verify that x2 contains an AllocationSite
-  __ AssertUndefinedOrAllocationSite(allocation_site, scratch);
+  // Verify that scratch contains an AllocationSite
+  Register map = x5;
+  __ Ldr(map, FieldMemOperand(scratch, HeapObject::kMapOffset));
+  __ JumpIfNotRoot(map, Heap::kAllocationSiteMapRootIndex, &miss);
+
+  Register allocation_site = feedback_vector;
+  __ Mov(allocation_site, scratch);
   ArrayConstructorStub stub(masm->isolate(), arg_count());
   __ TailCallStub(&stub);

@@ -3306,7 +3310,10 @@
   __ JumpIfRoot(x4, Heap::kUninitializedSymbolRootIndex, &miss);

   if (!FLAG_trace_ic) {
-    // We are going megamorphic, and we don't want to visit the runtime.
+ // We are going megamorphic. If the feedback is a JSFunction, it is fine
+    // to handle it here. More complex cases are dealt with in the runtime.
+    __ AssertNotSmi(x4);
+    __ JumpIfNotObjectType(x4, x5, x5, JS_FUNCTION_TYPE, &miss);
     __ Add(x4, feedback_vector,
            Operand::UntagSmiAndScale(index, kPointerSizeLog2));
     __ LoadRoot(x5, Heap::kMegamorphicSymbolRootIndex);
=======================================
--- /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Fri Jul 25 17:50:53 2014 UTC +++ /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Tue Jul 29 11:53:30 2014 UTC
@@ -2367,10 +2367,16 @@
   __ j(not_equal, &miss);

   __ mov(eax, arg_count());
-  __ mov(ebx, FieldOperand(ebx, edx, times_half_pointer_size,
+  __ mov(ecx, FieldOperand(ebx, edx, times_half_pointer_size,
                            FixedArray::kHeaderSize));
+
   // Verify that ecx contains an AllocationSite
-  __ AssertUndefinedOrAllocationSite(ebx);
+  Factory* factory = masm->isolate()->factory();
+  __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
+         factory->allocation_site_map());
+  __ j(not_equal, &miss);
+
+  __ mov(ebx, ecx);
   ArrayConstructorStub stub(masm->isolate(), arg_count());
   __ TailCallStub(&stub);

@@ -2441,7 +2447,11 @@
   __ j(equal, &miss);

   if (!FLAG_trace_ic) {
-    // We are going megamorphic, and we don't want to visit the runtime.
+ // We are going megamorphic. If the feedback is a JSFunction, it is fine
+    // to handle it here. More complex cases are dealt with in the runtime.
+    __ AssertNotSmi(ecx);
+    __ CmpObjectType(ecx, JS_FUNCTION_TYPE, ecx);
+    __ j(not_equal, &miss);
     __ mov(FieldOperand(ebx, edx, times_half_pointer_size,
                         FixedArray::kHeaderSize),
            Immediate(TypeFeedbackInfo::MegamorphicSentinel(isolate)));
=======================================
--- /branches/bleeding_edge/src/ic.cc   Mon Jul 28 10:55:32 2014 UTC
+++ /branches/bleeding_edge/src/ic.cc   Tue Jul 29 11:53:30 2014 UTC
@@ -1835,8 +1835,13 @@
       isolate()->native_context()->array_function());
   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);
+    Object* feedback = vector->get(slot->value());
+    if (!feedback->IsAllocationSite()) {
+      Handle<AllocationSite> new_site =
+          isolate()->factory()->NewAllocationSite();
+      vector->set(slot->value(), *new_site);
+    }
+
     CallIC_ArrayStub stub(isolate(), state);
     set_target(*stub.GetCode());
     Handle<String> name;
@@ -1876,6 +1881,9 @@
   State state(target()->extra_ic_state());
   Object* feedback = vector->get(slot->value());

+  // Hand-coded MISS handling is easier if CallIC slots don't contain smis.
+  ASSERT(!feedback->IsSmi());
+
   if (feedback->IsJSFunction() || !function->IsJSFunction()) {
     // We are going generic.
     vector->set(slot->value(),
@@ -1884,9 +1892,14 @@

     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()));
+    // The feedback is either uninitialized or an allocation site.
+ // It might be an allocation site because if we re-compile the full code
+    // to add deoptimization support, we call with the default call-ic, and
+    // merely need to patch the target to match the feedback.
+    // TODO(mvstanton): the better approach is to dispense with patching
+    // altogether, which is in progress.
+ ASSERT(feedback == *TypeFeedbackInfo::UninitializedSentinel(isolate()) ||
+           feedback->IsAllocationSite());

     // Do we want to install a custom handler?
     if (FLAG_use_ic &&
=======================================
--- /branches/bleeding_edge/src/x64/code-stubs-x64.cc Fri Jul 25 17:50:53 2014 UTC +++ /branches/bleeding_edge/src/x64/code-stubs-x64.cc Tue Jul 29 11:53:30 2014 UTC
@@ -2247,11 +2247,15 @@
   __ j(not_equal, &miss);

   __ movp(rax, Immediate(arg_count()));
-  __ movp(rbx, FieldOperand(rbx, rdx, times_pointer_size,
+  __ movp(rcx, FieldOperand(rbx, rdx, times_pointer_size,
                             FixedArray::kHeaderSize));
-
   // Verify that ecx contains an AllocationSite
-  __ AssertUndefinedOrAllocationSite(rbx);
+  Factory* factory = masm->isolate()->factory();
+  __ Cmp(FieldOperand(rcx, HeapObject::kMapOffset),
+         factory->allocation_site_map());
+  __ j(not_equal, &miss);
+
+  __ movp(rbx, rcx);
   ArrayConstructorStub stub(masm->isolate(), arg_count());
   __ TailCallStub(&stub);

@@ -2325,7 +2329,11 @@
   __ j(equal, &miss);

   if (!FLAG_trace_ic) {
-    // We are going megamorphic, and we don't want to visit the runtime.
+ // We are going megamorphic. If the feedback is a JSFunction, it is fine
+    // to handle it here. More complex cases are dealt with in the runtime.
+    __ AssertNotSmi(rcx);
+    __ CmpObjectType(rcx, JS_FUNCTION_TYPE, rcx);
+    __ j(not_equal, &miss);
     __ Move(FieldOperand(rbx, rdx, times_pointer_size,
                          FixedArray::kHeaderSize),
             TypeFeedbackInfo::MegamorphicSentinel(isolate));

--
--
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/d/optout.

Reply via email to