Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1199)

Unified Diff: src/compiler/js-typed-lowering.cc

Issue 1131263002: [turbofan] Work towards fixing asm.js heap access. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/compiler/js-typed-lowering.h ('k') | src/compiler/opcodes.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/compiler/js-typed-lowering.cc
diff --git a/src/compiler/js-typed-lowering.cc b/src/compiler/js-typed-lowering.cc
index 74ebfa02eefe8a394387388cd47b2fc0c8ed973d..4d66d2fb80a0243a1ab6f27f605e9300ac7463ac 100644
--- a/src/compiler/js-typed-lowering.cc
+++ b/src/compiler/js-typed-lowering.cc
@@ -334,7 +334,13 @@ class JSBinopReduction final {
}
Node* ConvertPrimitiveToNumber(Node* node) {
- return lowering_->ConvertPrimitiveToNumber(node);
+ DCHECK(NodeProperties::GetBounds(node).upper->Is(Type::PlainPrimitive()));
+ // Avoid inserting too many eager ToNumber() operations.
+ Reduction const reduction = lowering_->ReduceJSToNumberInput(node);
+ if (reduction.Changed()) return reduction.replacement();
+ return graph()->NewNode(
+ javascript()->ToNumber(), node, jsgraph()->NoContextConstant(),
+ jsgraph()->EmptyFrameState(), graph()->start(), graph()->start());
}
Node* ConvertToNumber(Node* node, Node* frame_state) {
@@ -680,6 +686,124 @@ Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) {
}
+namespace {
+
+bool CanCover(Node* user, Node* node) {
+ for (auto edge : node->use_edges()) {
+ if (NodeProperties::IsValueEdge(edge) && edge.from() != user) return false;
+ }
+ return true;
+}
+
+} // namespace
+
+
+// TODO(bmeurer): Move this into a dedicated conversion/truncation analysis,
+// which works bottom-up from the uses.
+Reduction JSTypedLowering::ReduceNumberToInt32(Node* node) {
+ Node* const number = node->InputAt(0);
+ if (number->opcode() == IrOpcode::kJSToNumber && CanCover(node, number)) {
+ Node* const input = number->InputAt(0);
+ if (input->opcode() == IrOpcode::kJSLoadProperty &&
+ CanCover(number, input)) {
+ Node* key = NodeProperties::GetValueInput(input, 1);
+ Node* base = NodeProperties::GetValueInput(input, 0);
+ Type* key_type = NodeProperties::GetBounds(key).upper;
+ HeapObjectMatcher<Object> mbase(base);
+ if (mbase.HasValue() && mbase.Value().handle()->IsJSTypedArray()) {
+ Handle<JSTypedArray> const array =
+ Handle<JSTypedArray>::cast(mbase.Value().handle());
+ if (!array->GetBuffer()->was_neutered() &&
+ (array->type() != kExternalFloat32Array &&
+ array->type() != kExternalFloat64Array)) {
+ array->GetBuffer()->set_is_neuterable(false);
+ BufferAccess const access(array->type());
+ size_t const k = ElementSizeLog2Of(access.machine_type());
+ double const byte_length = array->byte_length()->Number();
+ CHECK_LT(k, arraysize(shifted_int32_ranges_));
+ if (IsExternalArrayElementsKind(array->map()->elements_kind()) &&
+ key_type->Is(shifted_int32_ranges_[k]) &&
+ byte_length <= kMaxInt) {
+ // JSLoadProperty(typed-array, int32)
+ Handle<ExternalArray> elements =
+ Handle<ExternalArray>::cast(handle(array->elements()));
+ Node* buffer =
+ jsgraph()->PointerConstant(elements->external_pointer());
+ Node* length = jsgraph()->Constant(byte_length);
+ Node* effect = NodeProperties::GetEffectInput(input);
+ Node* control = NodeProperties::GetControlInput(input);
+ // Compute byte offset.
+ Node* offset = Word32Shl(key, static_cast<int>(k));
+ Node* load =
+ graph()->NewNode(simplified()->LoadBuffer(access), buffer,
+ offset, length, effect, control);
+ NodeProperties::ReplaceWithValue(input, load, load);
+ NodeProperties::ReplaceWithValue(number, load);
+ number->Kill();
+ input->Kill();
+ return Replace(load);
+ }
+ }
+ }
+ }
+ }
+ return NoChange();
+}
+
+
+// TODO(bmeurer): Move this into a dedicated conversion/truncation analysis,
+// which works bottom-up from the uses.
+Reduction JSTypedLowering::ReduceNumberToUint32(Node* node) {
+ Node* const number = node->InputAt(0);
+ if (number->opcode() == IrOpcode::kJSToNumber && CanCover(node, number)) {
+ Node* const input = number->InputAt(0);
+ if (input->opcode() == IrOpcode::kJSLoadProperty &&
+ CanCover(number, input)) {
+ Node* key = NodeProperties::GetValueInput(input, 1);
+ Node* base = NodeProperties::GetValueInput(input, 0);
+ Type* key_type = NodeProperties::GetBounds(key).upper;
+ HeapObjectMatcher<Object> mbase(base);
+ if (mbase.HasValue() && mbase.Value().handle()->IsJSTypedArray()) {
+ Handle<JSTypedArray> const array =
+ Handle<JSTypedArray>::cast(mbase.Value().handle());
+ if (!array->GetBuffer()->was_neutered() &&
+ (array->type() != kExternalFloat32Array &&
+ array->type() != kExternalFloat64Array)) {
+ array->GetBuffer()->set_is_neuterable(false);
+ BufferAccess const access(array->type());
+ size_t const k = ElementSizeLog2Of(access.machine_type());
+ double const byte_length = array->byte_length()->Number();
+ CHECK_LT(k, arraysize(shifted_int32_ranges_));
+ if (IsExternalArrayElementsKind(array->map()->elements_kind()) &&
+ key_type->Is(shifted_int32_ranges_[k]) &&
+ byte_length <= kMaxInt) {
+ // JSLoadProperty(typed-array, int32)
+ Handle<ExternalArray> elements =
+ Handle<ExternalArray>::cast(handle(array->elements()));
+ Node* buffer =
+ jsgraph()->PointerConstant(elements->external_pointer());
+ Node* length = jsgraph()->Constant(byte_length);
+ Node* effect = NodeProperties::GetEffectInput(input);
+ Node* control = NodeProperties::GetControlInput(input);
+ // Compute byte offset.
+ Node* offset = Word32Shl(key, static_cast<int>(k));
+ Node* load =
+ graph()->NewNode(simplified()->LoadBuffer(access), buffer,
+ offset, length, effect, control);
+ NodeProperties::ReplaceWithValue(input, load, load);
+ NodeProperties::ReplaceWithValue(number, load);
+ number->Kill();
+ input->Kill();
+ return Replace(load);
+ }
+ }
+ }
+ }
+ }
+ return NoChange();
+}
+
+
Reduction JSTypedLowering::ReduceJSToNumber(Node* node) {
// Try to reduce the input first.
Node* const input = node->InputAt(0);
@@ -688,6 +812,47 @@ Reduction JSTypedLowering::ReduceJSToNumber(Node* node) {
NodeProperties::ReplaceWithValue(node, reduction.replacement());
return reduction;
}
+ // TODO(bmeurer): Move this into a dedicated conversion/truncation analysis,
+ // which works bottom-up from the uses.
+ if (input->opcode() == IrOpcode::kJSLoadProperty && CanCover(node, input)) {
+ Node* key = NodeProperties::GetValueInput(input, 1);
+ Node* base = NodeProperties::GetValueInput(input, 0);
+ Type* key_type = NodeProperties::GetBounds(key).upper;
+ HeapObjectMatcher<Object> mbase(base);
+ if (mbase.HasValue() && mbase.Value().handle()->IsJSTypedArray()) {
+ Handle<JSTypedArray> const array =
+ Handle<JSTypedArray>::cast(mbase.Value().handle());
+ if (!array->GetBuffer()->was_neutered() &&
+ (array->type() == kExternalFloat32Array ||
+ array->type() == kExternalFloat64Array)) {
+ array->GetBuffer()->set_is_neuterable(false);
+ BufferAccess const access(array->type());
+ size_t const k = ElementSizeLog2Of(access.machine_type());
+ double const byte_length = array->byte_length()->Number();
+ CHECK_LT(k, arraysize(shifted_int32_ranges_));
+ if (IsExternalArrayElementsKind(array->map()->elements_kind()) &&
+ key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) {
+ // JSLoadProperty(typed-array, int32)
+ Handle<ExternalArray> elements =
+ Handle<ExternalArray>::cast(handle(array->elements()));
+ Node* buffer =
+ jsgraph()->PointerConstant(elements->external_pointer());
+ Node* length = jsgraph()->Constant(byte_length);
+ Node* effect = NodeProperties::GetEffectInput(input);
+ Node* control = NodeProperties::GetControlInput(input);
+ // Compute byte offset.
+ Node* offset = Word32Shl(key, static_cast<int>(k));
+ Node* load =
+ graph()->NewNode(simplified()->LoadBuffer(access), buffer, offset,
+ length, effect, control);
+ NodeProperties::ReplaceWithValue(input, load, load);
+ NodeProperties::ReplaceWithValue(node, load);
+ input->Kill();
+ return Changed(load);
+ }
+ }
+ }
+ }
Type* const input_type = NodeProperties::GetBounds(input).upper;
if (input_type->Is(Type::PlainPrimitive())) {
if (NodeProperties::GetContextInput(node) !=
@@ -773,31 +938,19 @@ Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) {
if (!array->GetBuffer()->was_neutered()) {
array->GetBuffer()->set_is_neuterable(false);
BufferAccess const access(array->type());
- size_t const k = ElementSizeLog2Of(access.machine_type());
- double const byte_length = array->byte_length()->Number();
- CHECK_LT(k, arraysize(shifted_int32_ranges_));
- if (IsExternalArrayElementsKind(array->map()->elements_kind()) &&
- key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) {
- // JSLoadProperty(typed-array, int32)
+ if (array->byte_length()->Number() <= kMaxInt &&
+ key_type->Is(Type::Unsigned32()) &&
+ key_type->Max() < array->length()->Number()) {
+ // JSLoadProperty(typed-array, unsigned32)
Handle<ExternalArray> elements =
Handle<ExternalArray>::cast(handle(array->elements()));
Node* buffer = jsgraph()->PointerConstant(elements->external_pointer());
- Node* length = jsgraph()->Constant(byte_length);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
- // Check if we can avoid the bounds check.
- if (key_type->Min() >= 0 &&
- key_type->Max() < array->length()->Number()) {
- Node* load = graph()->NewNode(
- simplified()->LoadElement(
- AccessBuilder::ForTypedArrayElement(array->type(), true)),
- buffer, key, effect, control);
- return ReplaceEagerly(node, load);
- }
- // Compute byte offset.
- Node* offset = Word32Shl(key, static_cast<int>(k));
- Node* load = graph()->NewNode(simplified()->LoadBuffer(access), buffer,
- offset, length, effect, control);
+ Node* load = graph()->NewNode(
+ simplified()->LoadElement(
+ AccessBuilder::ForTypedArrayElement(array->type(), true)),
+ buffer, key, effect, control);
return ReplaceEagerly(node, load);
}
}
@@ -822,8 +975,7 @@ Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) {
size_t const k = ElementSizeLog2Of(access.machine_type());
double const byte_length = array->byte_length()->Number();
CHECK_LT(k, arraysize(shifted_int32_ranges_));
- if (IsExternalArrayElementsKind(array->map()->elements_kind()) &&
- access.external_array_type() != kExternalUint8ClampedArray &&
+ if (access.external_array_type() != kExternalUint8ClampedArray &&
key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) {
// JSLoadProperty(typed-array, int32)
Handle<ExternalArray> elements =
@@ -1182,6 +1334,10 @@ Reduction JSTypedLowering::Reduce(Node* node) {
return ReduceJSCreateWithContext(node);
case IrOpcode::kJSCreateBlockContext:
return ReduceJSCreateBlockContext(node);
+ case IrOpcode::kNumberToInt32:
+ return ReduceNumberToInt32(node);
+ case IrOpcode::kNumberToUint32:
+ return ReduceNumberToUint32(node);
default:
break;
}
@@ -1189,18 +1345,6 @@ Reduction JSTypedLowering::Reduce(Node* node) {
}
-Node* JSTypedLowering::ConvertPrimitiveToNumber(Node* input) {
- DCHECK(NodeProperties::GetBounds(input).upper->Is(Type::PlainPrimitive()));
- // Avoid inserting too many eager ToNumber() operations.
- Reduction const reduction = ReduceJSToNumberInput(input);
- if (reduction.Changed()) return reduction.replacement();
- // TODO(jarin) Use PlainPrimitiveToNumber once we have it.
- return graph()->NewNode(
- javascript()->ToNumber(), input, jsgraph()->NoContextConstant(),
- jsgraph()->EmptyFrameState(), graph()->start(), graph()->start());
-}
-
-
Node* JSTypedLowering::Word32Shl(Node* const lhs, int32_t const rhs) {
if (rhs == 0) return lhs;
return graph()->NewNode(machine()->Word32Shl(), lhs,
« no previous file with comments | « src/compiler/js-typed-lowering.h ('k') | src/compiler/opcodes.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698