Consider out-of-bounds accesses as escaping uses.
authormstarzinger@chromium.org <mstarzinger@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 9 Sep 2013 09:53:58 +0000 (09:53 +0000)
committermstarzinger@chromium.org <mstarzinger@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 9 Sep 2013 09:53:58 +0000 (09:53 +0000)
R=titzer@chromium.org
TEST=mjsunit/compiler/escape-analysis

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

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

src/hydrogen-escape-analysis.cc
src/hydrogen-escape-analysis.h
src/hydrogen-instructions.h
test/mjsunit/compiler/escape-analysis.js

index 00cfe27..997e4f9 100644 (file)
@@ -31,7 +31,7 @@ namespace v8 {
 namespace internal {
 
 
-bool HEscapeAnalysisPhase::HasNoEscapingUses(HValue* value) {
+bool HEscapeAnalysisPhase::HasNoEscapingUses(HValue* value, int size) {
   for (HUseIterator it(value->uses()); !it.Done(); it.Advance()) {
     HValue* use = it.value();
     if (use->HasEscapingOperandAt(it.index())) {
@@ -41,7 +41,15 @@ bool HEscapeAnalysisPhase::HasNoEscapingUses(HValue* value) {
       }
       return false;
     }
-    if (use->RedefinedOperandIndex() == it.index() && !HasNoEscapingUses(use)) {
+    if (use->HasOutOfBoundsAccess(size)) {
+      if (FLAG_trace_escape_analysis) {
+        PrintF("#%d (%s) out of bounds at #%d (%s) @%d\n", value->id(),
+               value->Mnemonic(), use->id(), use->Mnemonic(), it.index());
+      }
+      return false;
+    }
+    int redefined_index = use->RedefinedOperandIndex();
+    if (redefined_index == it.index() && !HasNoEscapingUses(use, size)) {
       if (FLAG_trace_escape_analysis) {
         PrintF("#%d (%s) escapes redefinition #%d (%s) @%d\n", value->id(),
                value->Mnemonic(), use->id(), use->Mnemonic(), it.index());
@@ -59,7 +67,11 @@ void HEscapeAnalysisPhase::CollectCapturedValues() {
     HBasicBlock* block = graph()->blocks()->at(i);
     for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
       HInstruction* instr = it.Current();
-      if (instr->IsAllocate() && HasNoEscapingUses(instr)) {
+      if (!instr->IsAllocate()) continue;
+      HAllocate* allocate = HAllocate::cast(instr);
+      if (!allocate->size()->IsInteger32Constant()) continue;
+      int size_in_bytes = allocate->size()->GetInteger32Constant();
+      if (HasNoEscapingUses(instr, size_in_bytes)) {
         if (FLAG_trace_escape_analysis) {
           PrintF("#%d (%s) is being captured\n", instr->id(),
                  instr->Mnemonic());
@@ -290,7 +302,6 @@ void HEscapeAnalysisPhase::PerformScalarReplacement() {
     HAllocate* allocate = HAllocate::cast(captured_.at(i));
 
     // Compute number of scalar values and start with clean slate.
-    if (!allocate->size()->IsInteger32Constant()) continue;
     int size_in_bytes = allocate->size()->GetInteger32Constant();
     number_of_values_ = size_in_bytes / kPointerSize;
     number_of_objects_++;
index 311a653..3e27cc1 100644 (file)
@@ -49,7 +49,7 @@ class HEscapeAnalysisPhase : public HPhase {
 
  private:
   void CollectCapturedValues();
-  bool HasNoEscapingUses(HValue* value);
+  bool HasNoEscapingUses(HValue* value, int size);
   void PerformScalarReplacement();
   void AnalyzeDataFlow(HInstruction* instr);
 
index 6ef9bb7..2bfb284 100644 (file)
@@ -867,6 +867,7 @@ class HValue : public ZoneObject {
 
   // Escape analysis helpers.
   virtual bool HasEscapingOperandAt(int index) { return true; }
+  virtual bool HasOutOfBoundsAccess(int size) { return false; }
 
   // Representation helpers.
   virtual Representation observed_input_representation(int index) {
@@ -5755,6 +5756,9 @@ class HLoadNamedField V8_FINAL : public HTemplateInstruction<1> {
   }
 
   virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE { return false; }
+  virtual bool HasOutOfBoundsAccess(int size) V8_OVERRIDE {
+    return !access().IsInobject() || access().offset() >= size;
+  }
   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
     if (index == 0 && access().IsExternalMemory()) {
       // object must be external in case of external memory access
@@ -6070,6 +6074,9 @@ class HStoreNamedField V8_FINAL : public HTemplateInstruction<3> {
   virtual bool HasEscapingOperandAt(int index) V8_OVERRIDE {
     return index == 1;
   }
+  virtual bool HasOutOfBoundsAccess(int size) V8_OVERRIDE {
+    return !access().IsInobject() || access().offset() >= size;
+  }
   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
     if (index == 0 && access().IsExternalMemory()) {
       // object must be external in case of external memory access
index 7452e3b..74e638a 100644 (file)
@@ -25,7 +25,7 @@
 // (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: --allow-natives-syntax --use-escape-analysis
+// Flags: --allow-natives-syntax --use-escape-analysis --expose-gc
 
 
 // Test stores on a join path.
   test(osr2);
   test(osr3);
 })();
+
+
+// Test out-of-bounds access on captured objects.
+(function testOOB() {
+  function cons1() {
+    this.x = 1;
+    this.y = 2;
+    this.z = 3;
+  }
+  function cons2() {
+    this.a = 7;
+  }
+  function oob(constructor, branch) {
+    var o = new constructor();
+    if (branch) {
+      return o.a;
+    } else {
+      return o.z;
+    }
+  }
+  assertEquals(3, oob(cons1, false));
+  assertEquals(3, oob(cons1, false));
+  assertEquals(7, oob(cons2, true));
+  assertEquals(7, oob(cons2, true));
+  gc();  // Clears type feedback of constructor call.
+  assertEquals(7, oob(cons2, true));
+  assertEquals(7, oob(cons2, true));
+  %OptimizeFunctionOnNextCall(oob);
+  assertEquals(7, oob(cons2, true));
+})();