| 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,
|
|
|