[turbofan] Quickfix for invalid number truncation of typed array loads.
authorBenedikt Meurer <bmeurer@chromium.org>
Fri, 12 Dec 2014 10:45:18 +0000 (11:45 +0100)
committerBenedikt Meurer <bmeurer@chromium.org>
Fri, 12 Dec 2014 10:45:38 +0000 (10:45 +0000)
TEST=mjsunit/compiler/regress-int32array-outofbounds-nan
R=jarin@chromium.org

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

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

src/compiler/simplified-lowering.cc
test/mjsunit/compiler/regress-int32array-outofbounds-nan.js [new file with mode: 0644]

index 3688fc0..b86ffba 100644 (file)
@@ -4,6 +4,8 @@
 
 #include "src/compiler/simplified-lowering.h"
 
+#include <limits>
+
 #include "src/base/bits.h"
 #include "src/code-factory.h"
 #include "src/compiler/common-operator.h"
@@ -764,8 +766,20 @@ class RepresentationSelector {
         ProcessRemainingInputs(node, 3);
         // Tagged overrides everything if we have to do a typed array bounds
         // check, because we may need to return undefined then.
-        MachineType output_type =
-            (use & kRepTagged) ? kMachAnyTagged : access.machine_type();
+        MachineType output_type;
+        if (use & kRepTagged) {
+          output_type = kMachAnyTagged;
+        } else if (use & kRepFloat64) {
+          if (access.machine_type() & kRepFloat32) {
+            output_type = access.machine_type();
+          } else {
+            output_type = kMachFloat64;
+          }
+        } else if (use & kRepFloat32) {
+          output_type = kMachFloat32;
+        } else {
+          output_type = access.machine_type();
+        }
         SetOutput(node, output_type);
         if (lower()) lowering->DoLoadBuffer(node, output_type, changer_);
         break;
@@ -1130,7 +1144,7 @@ void SimplifiedLowering::DoLoadBuffer(Node* node, MachineType output_type,
   DCHECK_EQ(IrOpcode::kLoadBuffer, node->opcode());
   DCHECK_NE(kMachNone, RepresentationOf(output_type));
   MachineType const type = BufferAccessOf(node->op()).machine_type();
-  if (output_type & kRepTagged) {
+  if (output_type != type) {
     Node* const buffer = node->InputAt(0);
     Node* const offset = node->InputAt(1);
     Node* const length = node->InputAt(2);
@@ -1144,11 +1158,22 @@ void SimplifiedLowering::DoLoadBuffer(Node* node, MachineType output_type,
     Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
     Node* etrue = graph()->NewNode(machine()->Load(type), buffer, offset,
                                    effect, if_true);
-    Node* vtrue = changer->GetTaggedRepresentationFor(etrue, type);
+    Node* vtrue = changer->GetRepresentationFor(etrue, type, output_type);
 
     Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
-    Node* vfalse = jsgraph()->UndefinedConstant();
     Node* efalse = effect;
+    Node* vfalse;
+    if (output_type & kRepTagged) {
+      vfalse = jsgraph()->UndefinedConstant();
+    } else if (output_type & kRepFloat64) {
+      vfalse =
+          jsgraph()->Float64Constant(std::numeric_limits<double>::quiet_NaN());
+    } else if (output_type & kRepFloat32) {
+      vfalse =
+          jsgraph()->Float32Constant(std::numeric_limits<float>::quiet_NaN());
+    } else {
+      vfalse = jsgraph()->Int32Constant(0);
+    }
 
     Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
     Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
@@ -1157,7 +1182,7 @@ void SimplifiedLowering::DoLoadBuffer(Node* node, MachineType output_type,
     NodeProperties::ReplaceWithValue(node, node, ephi);
 
     // Turn the {node} into a Phi.
-    node->set_op(common()->Phi(kMachAnyTagged, 2));
+    node->set_op(common()->Phi(output_type, 2));
     node->ReplaceInput(0, vtrue);
     node->ReplaceInput(1, vfalse);
     node->ReplaceInput(2, merge);
diff --git a/test/mjsunit/compiler/regress-int32array-outofbounds-nan.js b/test/mjsunit/compiler/regress-int32array-outofbounds-nan.js
new file mode 100644 (file)
index 0000000..2eba2a4
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2014 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.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM32 = new stdlib.Int32Array(heap);
+  function foo(i) {
+    i = i|0;
+    return +MEM32[i >> 2];
+  }
+  return {foo: foo};
+}
+
+var foo = Module(this, {}, new ArrayBuffer(4)).foo;
+assertEquals(NaN, foo(-4));
+assertEquals(NaN, foo(4));