Index: src/compiler/js-builtin-reducer.cc |
diff --git a/src/compiler/js-builtin-reducer.cc b/src/compiler/js-builtin-reducer.cc |
index fa7f51d6ba2517cd456f509769571259a09ea0e8..ce27281b5d0badb204f4cdaf18a6a795e176d35c 100644 |
--- a/src/compiler/js-builtin-reducer.cc |
+++ b/src/compiler/js-builtin-reducer.cc |
@@ -543,7 +543,7 @@ Reduction JSBuiltinReducer::ReduceStringFromCharCode(Node* node) { |
namespace { |
-Node* GetStringReceiver(Node* node) { |
+Node* GetStringWitness(Node* node) { |
Node* receiver = NodeProperties::GetValueInput(node, 1); |
Type* receiver_type = NodeProperties::GetType(receiver); |
Node* effect = NodeProperties::GetEffectInput(node); |
@@ -576,7 +576,7 @@ Reduction JSBuiltinReducer::ReduceStringCharAt(Node* node) { |
Node* control = NodeProperties::GetControlInput(node); |
if (index_type->Is(Type::Unsigned32())) { |
- if (Node* receiver = GetStringReceiver(node)) { |
+ if (Node* receiver = GetStringWitness(node)) { |
// Determine the {receiver} length. |
Node* receiver_length = effect = graph()->NewNode( |
simplified()->LoadField(AccessBuilder::ForStringLength()), receiver, |
@@ -627,7 +627,7 @@ Reduction JSBuiltinReducer::ReduceStringCharCodeAt(Node* node) { |
Node* control = NodeProperties::GetControlInput(node); |
if (index_type->Is(Type::Unsigned32())) { |
- if (Node* receiver = GetStringReceiver(node)) { |
+ if (Node* receiver = GetStringWitness(node)) { |
// Determine the {receiver} length. |
Node* receiver_length = effect = graph()->NewNode( |
simplified()->LoadField(AccessBuilder::ForStringLength()), receiver, |
@@ -662,6 +662,86 @@ Reduction JSBuiltinReducer::ReduceStringCharCodeAt(Node* node) { |
return NoChange(); |
} |
+namespace { |
+ |
+bool HasInstanceTypeWitness(Node* receiver, Node* effect, |
+ InstanceType instance_type) { |
+ for (Node* dominator = effect;;) { |
+ if (dominator->opcode() == IrOpcode::kCheckMaps && |
+ dominator->InputAt(0) == receiver) { |
+ // Check if all maps have the given {instance_type}. |
+ for (int i = 1; i < dominator->op()->ValueInputCount(); ++i) { |
+ Node* const map = NodeProperties::GetValueInput(dominator, i); |
+ Type* const map_type = NodeProperties::GetType(map); |
+ if (!map_type->IsConstant()) return false; |
+ Handle<Map> const map_value = |
+ Handle<Map>::cast(map_type->AsConstant()->Value()); |
+ if (map_value->instance_type() != instance_type) return false; |
+ } |
+ return true; |
+ } |
+ switch (dominator->opcode()) { |
+ case IrOpcode::kStoreField: { |
+ FieldAccess const& access = FieldAccessOf(dominator->op()); |
+ if (access.base_is_tagged == kTaggedBase && |
+ access.offset == HeapObject::kMapOffset) { |
+ return false; |
+ } |
+ break; |
+ } |
+ case IrOpcode::kStoreElement: |
+ break; |
+ default: { |
+ DCHECK_EQ(1, dominator->op()->EffectOutputCount()); |
+ if (dominator->op()->EffectInputCount() != 1 || |
+ !dominator->op()->HasProperty(Operator::kNoWrite)) { |
+ // Didn't find any appropriate CheckMaps node. |
+ return false; |
+ } |
+ break; |
+ } |
+ } |
+ dominator = NodeProperties::GetEffectInput(dominator); |
+ } |
+} |
+ |
+} // namespace |
+ |
+Reduction JSBuiltinReducer::ReduceArrayBufferViewAccessor( |
+ Node* node, InstanceType instance_type, FieldAccess const& access) { |
+ Node* receiver = NodeProperties::GetValueInput(node, 1); |
+ Node* effect = NodeProperties::GetEffectInput(node); |
+ Node* control = NodeProperties::GetControlInput(node); |
+ if (HasInstanceTypeWitness(receiver, effect, instance_type)) { |
+ // Load the {receiver}s field. |
+ Node* receiver_length = effect = graph()->NewNode( |
+ simplified()->LoadField(access), receiver, effect, control); |
+ |
+ // Check if the {receiver}s buffer was neutered. |
+ Node* receiver_buffer = effect = graph()->NewNode( |
+ simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()), |
+ receiver, effect, control); |
+ Node* receiver_buffer_bitfield = effect = graph()->NewNode( |
+ simplified()->LoadField(AccessBuilder::ForJSArrayBufferBitField()), |
+ receiver_buffer, effect, control); |
+ Node* check = graph()->NewNode( |
+ simplified()->NumberEqual(), |
+ graph()->NewNode( |
+ simplified()->NumberBitwiseAnd(), receiver_buffer_bitfield, |
+ jsgraph()->Constant(JSArrayBuffer::WasNeutered::kMask)), |
+ jsgraph()->ZeroConstant()); |
+ |
+ // Default to zero if the {receiver}s buffer was neutered. |
+ Node* value = |
+ graph()->NewNode(common()->Select(MachineRepresentation::kTagged), |
+ check, receiver_length, jsgraph()->ZeroConstant()); |
+ |
+ ReplaceWithValue(node, value, effect, control); |
+ return Replace(value); |
+ } |
+ return NoChange(); |
+} |
+ |
Reduction JSBuiltinReducer::Reduce(Node* node) { |
Reduction reduction = NoChange(); |
JSCallReduction r(node); |
@@ -778,6 +858,25 @@ Reduction JSBuiltinReducer::Reduce(Node* node) { |
return ReduceStringCharAt(node); |
case kStringCharCodeAt: |
return ReduceStringCharCodeAt(node); |
+ case kDataViewByteLength: |
+ return ReduceArrayBufferViewAccessor( |
+ node, JS_DATA_VIEW_TYPE, |
+ AccessBuilder::ForJSArrayBufferViewByteLength()); |
+ case kDataViewByteOffset: |
+ return ReduceArrayBufferViewAccessor( |
+ node, JS_DATA_VIEW_TYPE, |
+ AccessBuilder::ForJSArrayBufferViewByteOffset()); |
+ case kTypedArrayByteLength: |
+ return ReduceArrayBufferViewAccessor( |
+ node, JS_TYPED_ARRAY_TYPE, |
+ AccessBuilder::ForJSArrayBufferViewByteLength()); |
+ case kTypedArrayByteOffset: |
+ return ReduceArrayBufferViewAccessor( |
+ node, JS_TYPED_ARRAY_TYPE, |
+ AccessBuilder::ForJSArrayBufferViewByteOffset()); |
+ case kTypedArrayLength: |
+ return ReduceArrayBufferViewAccessor( |
+ node, JS_TYPED_ARRAY_TYPE, AccessBuilder::ForJSTypedArrayLength()); |
default: |
break; |
} |