[vm/compiler] Fix generation of Smi immediates when using compressed pointers
When compiler generates 32-bit instructions with immediate operand
(such as add/sub etc) it expects to find 32-bit immediate value.
In compressed pointers mode Smi occupies 32 bits with unspecified
upper bits. So getting a raw value of a Smi using
static_cast<int64_t>(constant.ptr())
is not correct. For example it may yield 0xfffffffe instead of
0xfffffffffffffffe for -1 value.
This change fixes a few places in code generator to use Smi::RawValue
instead of doing a static_cast.
TEST=runtime/tests/vm/dart/regress_47704_test.dart
Fixes https://github.com/dart-lang/sdk/issues/47704
Change-Id: I1f649c5a22f221c7f4e69a884c88c265973be606
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/220660
Auto-Submit: Alexander Markov <alexmarkov@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
diff --git a/runtime/tests/vm/dart/regress_47704_test.dart b/runtime/tests/vm/dart/regress_47704_test.dart
new file mode 100644
index 0000000..fca9648
--- /dev/null
+++ b/runtime/tests/vm/dart/regress_47704_test.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for https://github.com/dart-lang/sdk/issues/47704.
+// Verifies that compiler doesn't crash with compressed pointers when
+// generating code involving as 32-bit Smi constant which is not
+// sign-extended to 64 bits.
+
+// VMOptions=--deterministic --optimization_counter_threshold=80
+
+import 'dart:typed_data';
+import "package:expect/expect.dart";
+
+const int minLevel = -1;
+
+void foo() {
+ // Make sure this method is compiled.
+ for (int i = 0; i < 100; i++) {}
+
+ bool ok = false;
+ try {
+ for (int loc0 in ((Uint16List(40)).sublist(minLevel, 42))) {
+ print(loc0);
+ }
+ } catch (e) {
+ ok = true;
+ }
+ Expect.isTrue(ok);
+}
+
+void main() {
+ foo();
+ foo();
+}
diff --git a/runtime/tests/vm/dart_2/regress_47704_test.dart b/runtime/tests/vm/dart_2/regress_47704_test.dart
new file mode 100644
index 0000000..a0c2335
--- /dev/null
+++ b/runtime/tests/vm/dart_2/regress_47704_test.dart
@@ -0,0 +1,37 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for https://github.com/dart-lang/sdk/issues/47704.
+// Verifies that compiler doesn't crash with compressed pointers when
+// generating code involving as 32-bit Smi constant which is not
+// sign-extended to 64 bits.
+
+// VMOptions=--deterministic --optimization_counter_threshold=80
+
+// @dart = 2.9
+
+import 'dart:typed_data';
+import "package:expect/expect.dart";
+
+const int minLevel = -1;
+
+void foo() {
+ // Make sure this method is compiled.
+ for (int i = 0; i < 100; i++) {}
+
+ bool ok = false;
+ try {
+ for (int loc0 in ((Uint16List(40)).sublist(minLevel, 42))) {
+ print(loc0);
+ }
+ } catch (e) {
+ ok = true;
+ }
+ Expect.isTrue(ok);
+}
+
+void main() {
+ foo();
+ foo();
+}
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index 85e22b5..ab73a58 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -1071,7 +1071,7 @@
Location right = locs()->in(1);
if (right.IsConstant()) {
ASSERT(right.constant().IsSmi());
- const int64_t imm = static_cast<int64_t>(right.constant().ptr());
+ const int64_t imm = Smi::RawValue(Smi::Cast(right.constant()).Value());
__ TestImmediate(left, imm, compiler::kObjectBytes);
} else {
__ tst(left, compiler::Operand(right.reg()), compiler::kObjectBytes);
@@ -3438,7 +3438,7 @@
if (locs()->in(1).IsConstant()) {
const Object& constant = locs()->in(1).constant();
ASSERT(constant.IsSmi());
- const int64_t imm = static_cast<int64_t>(constant.ptr());
+ const int64_t imm = Smi::RawValue(Smi::Cast(constant).Value());
switch (op_kind()) {
case Token::kADD: {
if (deopt == NULL) {
diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc
index 4ca35a6..2d0a285 100644
--- a/runtime/vm/compiler/backend/il_x64.cc
+++ b/runtime/vm/compiler/backend/il_x64.cc
@@ -1037,7 +1037,7 @@
Location right = locs()->in(1);
if (right.IsConstant()) {
ASSERT(right.constant().IsSmi());
- const int64_t imm = static_cast<int64_t>(right.constant().ptr());
+ const int64_t imm = Smi::RawValue(Smi::Cast(right.constant()).Value());
__ TestImmediate(left_reg, compiler::Immediate(imm),
compiler::kObjectBytes);
} else {
@@ -3487,7 +3487,8 @@
static bool CanBeImmediate(const Object& constant) {
return constant.IsSmi() &&
- compiler::Immediate(static_cast<int64_t>(constant.ptr())).is_int32();
+ compiler::Immediate(Smi::RawValue(Smi::Cast(constant).Value()))
+ .is_int32();
}
static bool IsSmiValue(const Object& constant, intptr_t value) {
@@ -3620,7 +3621,7 @@
if (locs()->in(1).IsConstant()) {
const Object& constant = locs()->in(1).constant();
ASSERT(constant.IsSmi());
- const int64_t imm = static_cast<int64_t>(constant.ptr());
+ const int64_t imm = Smi::RawValue(Smi::Cast(constant).Value());
switch (op_kind()) {
case Token::kADD: {
__ AddImmediate(left, compiler::Immediate(imm), compiler::kObjectBytes);