Commit a085b8a2 authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Inline bunch of ArrayBuffer view accessors.

This adds initial support to inline a couple of the ArrayBuffer view
accessors like %TypeArray%.prototype.length and.
DataView.prototype.byteLength.

R=epertoso@chromium.org

Review-Url: https://codereview.chromium.org/2199753002
Cr-Commit-Position: refs/heads/master@{#38200}
parent f4f06c50
...@@ -216,16 +216,14 @@ FieldAccess AccessBuilder::ForJSArrayBufferBackingStore() { ...@@ -216,16 +216,14 @@ FieldAccess AccessBuilder::ForJSArrayBufferBackingStore() {
return access; return access;
} }
// static // static
FieldAccess AccessBuilder::ForJSArrayBufferBitField() { FieldAccess AccessBuilder::ForJSArrayBufferBitField() {
FieldAccess access = {kTaggedBase, JSArrayBuffer::kBitFieldOffset, FieldAccess access = {kTaggedBase, JSArrayBuffer::kBitFieldOffset,
MaybeHandle<Name>(), TypeCache::Get().kInt8, MaybeHandle<Name>(), TypeCache::Get().kUint8,
MachineType::Int8(), kNoWriteBarrier}; MachineType::Uint32(), kNoWriteBarrier};
return access; return access;
} }
// static // static
FieldAccess AccessBuilder::ForJSArrayBufferViewBuffer() { FieldAccess AccessBuilder::ForJSArrayBufferViewBuffer() {
FieldAccess access = {kTaggedBase, FieldAccess access = {kTaggedBase,
...@@ -237,6 +235,38 @@ FieldAccess AccessBuilder::ForJSArrayBufferViewBuffer() { ...@@ -237,6 +235,38 @@ FieldAccess AccessBuilder::ForJSArrayBufferViewBuffer() {
return access; return access;
} }
// static
FieldAccess AccessBuilder::ForJSArrayBufferViewByteLength() {
FieldAccess access = {kTaggedBase,
JSArrayBufferView::kByteLengthOffset,
MaybeHandle<Name>(),
TypeCache::Get().kPositiveInteger,
MachineType::AnyTagged(),
kFullWriteBarrier};
return access;
}
// static
FieldAccess AccessBuilder::ForJSArrayBufferViewByteOffset() {
FieldAccess access = {kTaggedBase,
JSArrayBufferView::kByteOffsetOffset,
MaybeHandle<Name>(),
TypeCache::Get().kPositiveInteger,
MachineType::AnyTagged(),
kFullWriteBarrier};
return access;
}
// static
FieldAccess AccessBuilder::ForJSTypedArrayLength() {
FieldAccess access = {kTaggedBase,
JSTypedArray::kLengthOffset,
MaybeHandle<Name>(),
TypeCache::Get().kJSTypedArrayLengthType,
MachineType::AnyTagged(),
kNoWriteBarrier};
return access;
}
// static // static
FieldAccess AccessBuilder::ForJSDateField(JSDate::FieldIndex index) { FieldAccess AccessBuilder::ForJSDateField(JSDate::FieldIndex index) {
......
...@@ -79,6 +79,15 @@ class AccessBuilder final : public AllStatic { ...@@ -79,6 +79,15 @@ class AccessBuilder final : public AllStatic {
// Provides access to JSArrayBufferView::buffer() field. // Provides access to JSArrayBufferView::buffer() field.
static FieldAccess ForJSArrayBufferViewBuffer(); static FieldAccess ForJSArrayBufferViewBuffer();
// Provides access to JSArrayBufferView::byteLength() field.
static FieldAccess ForJSArrayBufferViewByteLength();
// Provides access to JSArrayBufferView::byteOffset() field.
static FieldAccess ForJSArrayBufferViewByteOffset();
// Provides access to JSTypedArray::length() field.
static FieldAccess ForJSTypedArrayLength();
// Provides access to JSDate fields. // Provides access to JSDate fields.
static FieldAccess ForJSDateField(JSDate::FieldIndex index); static FieldAccess ForJSDateField(JSDate::FieldIndex index);
......
...@@ -543,7 +543,7 @@ Reduction JSBuiltinReducer::ReduceStringFromCharCode(Node* node) { ...@@ -543,7 +543,7 @@ Reduction JSBuiltinReducer::ReduceStringFromCharCode(Node* node) {
namespace { namespace {
Node* GetStringReceiver(Node* node) { Node* GetStringWitness(Node* node) {
Node* receiver = NodeProperties::GetValueInput(node, 1); Node* receiver = NodeProperties::GetValueInput(node, 1);
Type* receiver_type = NodeProperties::GetType(receiver); Type* receiver_type = NodeProperties::GetType(receiver);
Node* effect = NodeProperties::GetEffectInput(node); Node* effect = NodeProperties::GetEffectInput(node);
...@@ -576,7 +576,7 @@ Reduction JSBuiltinReducer::ReduceStringCharAt(Node* node) { ...@@ -576,7 +576,7 @@ Reduction JSBuiltinReducer::ReduceStringCharAt(Node* node) {
Node* control = NodeProperties::GetControlInput(node); Node* control = NodeProperties::GetControlInput(node);
if (index_type->Is(Type::Unsigned32())) { if (index_type->Is(Type::Unsigned32())) {
if (Node* receiver = GetStringReceiver(node)) { if (Node* receiver = GetStringWitness(node)) {
// Determine the {receiver} length. // Determine the {receiver} length.
Node* receiver_length = effect = graph()->NewNode( Node* receiver_length = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForStringLength()), receiver, simplified()->LoadField(AccessBuilder::ForStringLength()), receiver,
...@@ -627,7 +627,7 @@ Reduction JSBuiltinReducer::ReduceStringCharCodeAt(Node* node) { ...@@ -627,7 +627,7 @@ Reduction JSBuiltinReducer::ReduceStringCharCodeAt(Node* node) {
Node* control = NodeProperties::GetControlInput(node); Node* control = NodeProperties::GetControlInput(node);
if (index_type->Is(Type::Unsigned32())) { if (index_type->Is(Type::Unsigned32())) {
if (Node* receiver = GetStringReceiver(node)) { if (Node* receiver = GetStringWitness(node)) {
// Determine the {receiver} length. // Determine the {receiver} length.
Node* receiver_length = effect = graph()->NewNode( Node* receiver_length = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForStringLength()), receiver, simplified()->LoadField(AccessBuilder::ForStringLength()), receiver,
...@@ -662,6 +662,86 @@ Reduction JSBuiltinReducer::ReduceStringCharCodeAt(Node* node) { ...@@ -662,6 +662,86 @@ Reduction JSBuiltinReducer::ReduceStringCharCodeAt(Node* node) {
return NoChange(); 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 JSBuiltinReducer::Reduce(Node* node) {
Reduction reduction = NoChange(); Reduction reduction = NoChange();
JSCallReduction r(node); JSCallReduction r(node);
...@@ -778,6 +858,25 @@ Reduction JSBuiltinReducer::Reduce(Node* node) { ...@@ -778,6 +858,25 @@ Reduction JSBuiltinReducer::Reduce(Node* node) {
return ReduceStringCharAt(node); return ReduceStringCharAt(node);
case kStringCharCodeAt: case kStringCharCodeAt:
return ReduceStringCharCodeAt(node); 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: default:
break; break;
} }
......
...@@ -17,6 +17,7 @@ namespace compiler { ...@@ -17,6 +17,7 @@ namespace compiler {
// Forward declarations. // Forward declarations.
class CommonOperatorBuilder; class CommonOperatorBuilder;
struct FieldAccess;
class JSGraph; class JSGraph;
class SimplifiedOperatorBuilder; class SimplifiedOperatorBuilder;
...@@ -66,6 +67,9 @@ class JSBuiltinReducer final : public AdvancedReducer { ...@@ -66,6 +67,9 @@ class JSBuiltinReducer final : public AdvancedReducer {
Reduction ReduceStringCharAt(Node* node); Reduction ReduceStringCharAt(Node* node);
Reduction ReduceStringCharCodeAt(Node* node); Reduction ReduceStringCharCodeAt(Node* node);
Reduction ReduceStringFromCharCode(Node* node); Reduction ReduceStringFromCharCode(Node* node);
Reduction ReduceArrayBufferViewAccessor(Node* node,
InstanceType instance_type,
FieldAccess const& access);
Node* ToNumber(Node* value); Node* ToNumber(Node* value);
Node* ToUint32(Node* value); Node* ToUint32(Node* value);
......
...@@ -150,6 +150,11 @@ Node* JSGraph::Constant(int32_t value) { ...@@ -150,6 +150,11 @@ Node* JSGraph::Constant(int32_t value) {
return NumberConstant(value); return NumberConstant(value);
} }
Node* JSGraph::Constant(uint32_t value) {
if (value == 0) return ZeroConstant();
if (value == 1) return OneConstant();
return NumberConstant(value);
}
Node* JSGraph::Int32Constant(int32_t value) { Node* JSGraph::Int32Constant(int32_t value) {
Node** loc = cache_.FindInt32Constant(value); Node** loc = cache_.FindInt32Constant(value);
......
...@@ -73,6 +73,9 @@ class JSGraph : public ZoneObject { ...@@ -73,6 +73,9 @@ class JSGraph : public ZoneObject {
// Creates a NumberConstant node, usually canonicalized. // Creates a NumberConstant node, usually canonicalized.
Node* Constant(int32_t value); Node* Constant(int32_t value);
// Creates a NumberConstant node, usually canonicalized.
Node* Constant(uint32_t value);
// Creates a Int32Constant node, usually canonicalized. // Creates a Int32Constant node, usually canonicalized.
Node* Int32Constant(int32_t value); Node* Int32Constant(int32_t value);
Node* Uint32Constant(uint32_t value) { Node* Uint32Constant(uint32_t value) {
......
...@@ -125,6 +125,11 @@ class TypeCache final { ...@@ -125,6 +125,11 @@ class TypeCache final {
Type* const kJSArrayLengthType = Type* const kJSArrayLengthType =
CreateNative(Type::Unsigned32(), Type::Tagged()); CreateNative(Type::Unsigned32(), Type::Tagged());
// The JSTyped::length property always contains a tagged number in the range
// [0, kMaxSmiValue].
Type* const kJSTypedArrayLengthType =
CreateNative(Type::UnsignedSmall(), Type::TaggedSigned());
// The String::length property always contains a smi in the range // The String::length property always contains a smi in the range
// [0, String::kMaxLength]. // [0, String::kMaxLength].
Type* const kStringLengthType = Type* const kStringLengthType =
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment