| 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;
|
| }
|
|
|