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() {
return access;
}
// static
FieldAccess AccessBuilder::ForJSArrayBufferBitField() {
FieldAccess access = {kTaggedBase, JSArrayBuffer::kBitFieldOffset,
MaybeHandle<Name>(), TypeCache::Get().kInt8,
MachineType::Int8(), kNoWriteBarrier};
FieldAccess access = {kTaggedBase, JSArrayBuffer::kBitFieldOffset,
MaybeHandle<Name>(), TypeCache::Get().kUint8,
MachineType::Uint32(), kNoWriteBarrier};
return access;
}
// static
FieldAccess AccessBuilder::ForJSArrayBufferViewBuffer() {
FieldAccess access = {kTaggedBase,
......@@ -237,6 +235,38 @@ FieldAccess AccessBuilder::ForJSArrayBufferViewBuffer() {
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
FieldAccess AccessBuilder::ForJSDateField(JSDate::FieldIndex index) {
......
......@@ -79,6 +79,15 @@ class AccessBuilder final : public AllStatic {
// Provides access to JSArrayBufferView::buffer() field.
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.
static FieldAccess ForJSDateField(JSDate::FieldIndex index);
......
......@@ -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;
}
......
......@@ -17,6 +17,7 @@ namespace compiler {
// Forward declarations.
class CommonOperatorBuilder;
struct FieldAccess;
class JSGraph;
class SimplifiedOperatorBuilder;
......@@ -66,6 +67,9 @@ class JSBuiltinReducer final : public AdvancedReducer {
Reduction ReduceStringCharAt(Node* node);
Reduction ReduceStringCharCodeAt(Node* node);
Reduction ReduceStringFromCharCode(Node* node);
Reduction ReduceArrayBufferViewAccessor(Node* node,
InstanceType instance_type,
FieldAccess const& access);
Node* ToNumber(Node* value);
Node* ToUint32(Node* value);
......
......@@ -150,6 +150,11 @@ Node* JSGraph::Constant(int32_t 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** loc = cache_.FindInt32Constant(value);
......
......@@ -73,6 +73,9 @@ class JSGraph : public ZoneObject {
// Creates a NumberConstant node, usually canonicalized.
Node* Constant(int32_t value);
// Creates a NumberConstant node, usually canonicalized.
Node* Constant(uint32_t value);
// Creates a Int32Constant node, usually canonicalized.
Node* Int32Constant(int32_t value);
Node* Uint32Constant(uint32_t value) {
......
......@@ -125,6 +125,11 @@ class TypeCache final {
Type* const kJSArrayLengthType =
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
// [0, String::kMaxLength].
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