Index: src/compiler/js-builtin-reducer.cc |
diff --git a/src/compiler/js-builtin-reducer.cc b/src/compiler/js-builtin-reducer.cc |
index 12b0e2f6cc97d38eb8986ec3f8a19b923ba008a3..9fe7d40a33b9c691df198e65492d01bfdc3b691b 100644 |
--- a/src/compiler/js-builtin-reducer.cc |
+++ b/src/compiler/js-builtin-reducer.cc |
@@ -2,6 +2,7 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
+#include "src/compiler/access-builder.h" |
#include "src/compiler/diamond.h" |
#include "src/compiler/js-builtin-reducer.h" |
#include "src/compiler/js-graph.h" |
@@ -152,6 +153,85 @@ Reduction JSBuiltinReducer::ReduceMathFround(Node* node) { |
} |
+Reduction JSBuiltinReducer::ReduceAtomicsLoad(Node* node) { |
+ JSCallReduction r(node); |
+ if (r.GetJSCallArity() == 2) { |
+ // TODO(binji): copy-pasta from JSTypedLowering::ReduceJSLoadProperty |
+ Node* base = r.GetJSCallInput(0); |
+ Node* index = r.GetJSCallInput(1); |
+ Type* index_type = NodeProperties::GetBounds(index).upper; |
+ HeapObjectMatcher<Object> mbase(base); |
+ if (mbase.HasValue() && mbase.Value().handle()->IsJSTypedArray()) { |
+ Handle<JSTypedArray> array = |
+ Handle<JSTypedArray>::cast(mbase.Value().handle()); |
+ if (array->is_shared()) { |
+ bool const is_external = true; |
+ ElementAccess const access = |
+ AccessBuilder::ForTypedArrayElement(array->type(), is_external); |
+ size_t const k = ElementSizeLog2Of(access.machine_type); |
+ double const byte_length = array->byte_length()->Number(); |
+ DCHECK(IsExternalArrayElementsKind(array->map()->elements_kind())); |
+ Handle<ExternalArray> elements = |
+ Handle<ExternalArray>::cast(handle(array->elements())); |
+ Node* buffer = jsgraph()->PointerConstant(elements->external_pointer()); |
+ Node* effect = NodeProperties::GetEffectInput(node); |
+ Node* control = NodeProperties::GetControlInput(node); |
+ |
+ // TODO(binji): reuse from js-typed-lowering.cc? |
+ Type* shifted_int32_range = Type::Range( |
+ kMinInt / (1 << k), kMaxInt / (1 << k), graph()->zone()); |
+ if (index_type->Is(shifted_int32_range) && byte_length <= kMaxInt) { |
+ // Check if we can avoid the bounds check. |
+ if (index_type->Min() >= 0 && |
+ index_type->Max() < array->length()->Number()) { |
+ Node* load = |
+ graph()->NewNode(simplified()->LoadElementAtomic(access), |
+ buffer, index, effect, control); |
+ NodeProperties::ReplaceWithValue(node, load, load); |
+ return Changed(node); |
+ } |
+ } |
+ |
+ // Copy-pasta from SimplifiedLowering::DoLoadBuffer |
+ Node* offset = |
+ graph()->NewNode(machine()->Word32Shl(), index, |
+ jsgraph()->Int32Constant(static_cast<int>(k))); |
+ Node* length = jsgraph()->Constant(byte_length); |
+ Node* check = |
+ graph()->NewNode(machine()->Uint32LessThan(), offset, length); |
+ Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), |
+ check, control); |
+ |
+ Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
+ Node* etrue = graph()->NewNode(simplified()->LoadElementAtomic(access), |
+ buffer, index, effect, if_true); |
+ Node* vtrue = etrue; |
+ |
+ Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
+ Node* efalse = effect; |
+ Node* vfalse = jsgraph()->UndefinedConstant(); |
+ Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false); |
+ Node* ephi = |
+ graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge); |
+ |
+ // Replace effect uses of {node} with the {ephi}. |
+ NodeProperties::ReplaceWithValue(node, node, ephi); |
+ |
+ // Turn the {node} into a Phi. |
+ node->set_op(common()->Phi(kMachAnyTagged, 2)); |
+ node->ReplaceInput(0, vtrue); |
+ node->ReplaceInput(1, vfalse); |
+ node->ReplaceInput(2, merge); |
+ node->TrimInputCount(3); |
+ return Changed(node); |
+ } |
+ } |
+ } |
+ |
+ return NoChange(); |
+} |
+ |
+ |
Reduction JSBuiltinReducer::Reduce(Node* node) { |
JSCallReduction r(node); |
@@ -164,6 +244,8 @@ Reduction JSBuiltinReducer::Reduce(Node* node) { |
return ReplaceWithPureReduction(node, ReduceMathImul(node)); |
case kMathFround: |
return ReplaceWithPureReduction(node, ReduceMathFround(node)); |
+ case kAtomicsLoad: |
+ return ReduceAtomicsLoad(node); |
default: |
break; |
} |