// static
ElementAccess AccessBuilder::ForFixedArrayElement() {
- return {kTaggedBase, FixedArray::kHeaderSize, Type::Any(), kMachAnyTagged};
+ return {kNoBoundsCheck, kTaggedBase, FixedArray::kHeaderSize, Type::Any(),
+ kMachAnyTagged};
}
int header_size = is_external ? 0 : FixedTypedArrayBase::kDataOffset;
switch (type) {
case kExternalInt8Array:
- return {taggedness, header_size, Type::Signed32(), kMachInt8};
+ return {kTypedArrayBoundsCheck, taggedness, header_size, Type::Signed32(),
+ kMachInt8};
case kExternalUint8Array:
case kExternalUint8ClampedArray:
- return {taggedness, header_size, Type::Unsigned32(), kMachUint8};
+ return {kTypedArrayBoundsCheck, taggedness, header_size,
+ Type::Unsigned32(), kMachUint8};
case kExternalInt16Array:
- return {taggedness, header_size, Type::Signed32(), kMachInt16};
+ return {kTypedArrayBoundsCheck, taggedness, header_size, Type::Signed32(),
+ kMachInt16};
case kExternalUint16Array:
- return {taggedness, header_size, Type::Unsigned32(), kMachUint16};
+ return {kTypedArrayBoundsCheck, taggedness, header_size,
+ Type::Unsigned32(), kMachUint16};
case kExternalInt32Array:
- return {taggedness, header_size, Type::Signed32(), kMachInt32};
+ return {kTypedArrayBoundsCheck, taggedness, header_size, Type::Signed32(),
+ kMachInt32};
case kExternalUint32Array:
- return {taggedness, header_size, Type::Unsigned32(), kMachUint32};
+ return {kTypedArrayBoundsCheck, taggedness, header_size,
+ Type::Unsigned32(), kMachUint32};
case kExternalFloat32Array:
- return {taggedness, header_size, Type::Number(), kRepFloat32};
+ return {kTypedArrayBoundsCheck, taggedness, header_size, Type::Number(),
+ kRepFloat32};
case kExternalFloat64Array:
- return {taggedness, header_size, Type::Number(), kRepFloat64};
+ return {kTypedArrayBoundsCheck, taggedness, header_size, Type::Number(),
+ kRepFloat64};
}
UNREACHABLE();
- return {kUntaggedBase, 0, Type::None(), kMachNone};
+ return {kTypedArrayBoundsCheck, kUntaggedBase, 0, Type::None(), kMachNone};
}
} // namespace compiler
DCHECK(IsFixedTypedArrayElementsKind(elements_kind));
element_access = AccessBuilder::ForTypedArrayElement(type, false);
}
-
- Node* check = graph()->NewNode(machine()->Uint32LessThan(), key,
- jsgraph()->Uint32Constant(length));
- Node* branch = graph()->NewNode(common()->Branch(), check,
- NodeProperties::GetControlInput(node));
-
- Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
-
Node* store =
graph()->NewNode(simplified()->StoreElement(element_access), elements,
key, jsgraph()->Uint32Constant(length), value,
- NodeProperties::GetEffectInput(node), if_true);
-
- Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
-
- Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
- Node* phi = graph()->NewNode(common()->EffectPhi(2), store,
- NodeProperties::GetEffectInput(node), merge);
-
- return ReplaceWith(phi);
+ NodeProperties::GetEffectInput(node),
+ NodeProperties::GetControlInput(node));
+ return ReplaceEagerly(node, store);
}
return NoChange();
}
void SimplifiedLowering::DoStoreElement(Node* node) {
const ElementAccess& access = ElementAccessOf(node->op());
- WriteBarrierKind kind = ComputeWriteBarrierKind(
- access.base_is_tagged, access.machine_type, access.type);
- node->set_op(
- machine()->Store(StoreRepresentation(access.machine_type, kind)));
- node->ReplaceInput(1, ComputeIndex(access, node->InputAt(1)));
- node->RemoveInput(2);
+ const Operator* op = machine()->Store(StoreRepresentation(
+ access.machine_type,
+ ComputeWriteBarrierKind(access.base_is_tagged, access.machine_type,
+ access.type)));
+ Node* key = node->InputAt(1);
+ Node* index = ComputeIndex(access, key);
+ if (access.bounds_check == kNoBoundsCheck) {
+ node->set_op(op);
+ node->ReplaceInput(1, index);
+ node->RemoveInput(2);
+ } else {
+ DCHECK_EQ(kTypedArrayBoundsCheck, access.bounds_check);
+
+ Node* base = node->InputAt(0);
+ Node* length = node->InputAt(2);
+ Node* value = node->InputAt(3);
+ Node* effect = node->InputAt(4);
+ Node* control = node->InputAt(5);
+
+ Node* check = graph()->NewNode(machine()->Uint32LessThan(), key, length);
+ Node* branch = graph()->NewNode(common()->Branch(), check, control);
+
+ Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+ Node* store = graph()->NewNode(op, base, index, value, effect, if_true);
+
+ Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+
+ Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
+
+ node->set_op(common()->EffectPhi(2));
+ node->ReplaceInput(0, store);
+ node->ReplaceInput(1, effect);
+ node->ReplaceInput(2, merge);
+ node->TrimInputCount(3);
+ }
}
namespace {
const ElementAccess kElementAccesses[] = {
- {kTaggedBase, FixedArray::kHeaderSize, Type::Any(), kMachAnyTagged},
- {kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag, Type::Any(),
- kMachInt8},
- {kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag, Type::Any(),
- kMachInt16},
- {kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag, Type::Any(),
- kMachInt32},
- {kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag, Type::Any(),
- kMachUint8},
- {kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag, Type::Any(),
- kMachUint16},
- {kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag, Type::Any(),
- kMachUint32},
- {kUntaggedBase, 0, Type::Signed32(), kMachInt8},
- {kUntaggedBase, 0, Type::Unsigned32(), kMachUint8},
- {kUntaggedBase, 0, Type::Signed32(), kMachInt16},
- {kUntaggedBase, 0, Type::Unsigned32(), kMachUint16},
- {kUntaggedBase, 0, Type::Signed32(), kMachInt32},
- {kUntaggedBase, 0, Type::Unsigned32(), kMachUint32},
- {kUntaggedBase, 0, Type::Number(), kRepFloat32},
- {kUntaggedBase, 0, Type::Number(), kRepFloat64},
- {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Signed32(),
- kMachInt8},
- {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Unsigned32(),
- kMachUint8},
- {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Signed32(),
- kMachInt16},
- {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Unsigned32(),
- kMachUint16},
- {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Signed32(),
- kMachInt32},
- {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Unsigned32(),
- kMachUint32},
- {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Number(),
- kRepFloat32},
- {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Number(),
- kRepFloat64}};
+ {kNoBoundsCheck, kTaggedBase, FixedArray::kHeaderSize, Type::Any(),
+ kMachAnyTagged},
+ {kNoBoundsCheck, kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag,
+ Type::Any(), kMachInt8},
+ {kNoBoundsCheck, kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag,
+ Type::Any(), kMachInt16},
+ {kNoBoundsCheck, kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag,
+ Type::Any(), kMachInt32},
+ {kNoBoundsCheck, kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag,
+ Type::Any(), kMachUint8},
+ {kNoBoundsCheck, kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag,
+ Type::Any(), kMachUint16},
+ {kNoBoundsCheck, kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag,
+ Type::Any(), kMachUint32},
+ {kTypedArrayBoundsCheck, kUntaggedBase, 0, Type::Signed32(), kMachInt8},
+ {kTypedArrayBoundsCheck, kUntaggedBase, 0, Type::Unsigned32(), kMachUint8},
+ {kTypedArrayBoundsCheck, kUntaggedBase, 0, Type::Signed32(), kMachInt16},
+ {kTypedArrayBoundsCheck, kUntaggedBase, 0, Type::Unsigned32(), kMachUint16},
+ {kTypedArrayBoundsCheck, kUntaggedBase, 0, Type::Signed32(), kMachInt32},
+ {kTypedArrayBoundsCheck, kUntaggedBase, 0, Type::Unsigned32(), kMachUint32},
+ {kTypedArrayBoundsCheck, kUntaggedBase, 0, Type::Number(), kRepFloat32},
+ {kTypedArrayBoundsCheck, kUntaggedBase, 0, Type::Number(), kRepFloat64},
+ {kTypedArrayBoundsCheck, kTaggedBase, FixedTypedArrayBase::kDataOffset,
+ Type::Signed32(), kMachInt8},
+ {kTypedArrayBoundsCheck, kTaggedBase, FixedTypedArrayBase::kDataOffset,
+ Type::Unsigned32(), kMachUint8},
+ {kTypedArrayBoundsCheck, kTaggedBase, FixedTypedArrayBase::kDataOffset,
+ Type::Signed32(), kMachInt16},
+ {kTypedArrayBoundsCheck, kTaggedBase, FixedTypedArrayBase::kDataOffset,
+ Type::Unsigned32(), kMachUint16},
+ {kTypedArrayBoundsCheck, kTaggedBase, FixedTypedArrayBase::kDataOffset,
+ Type::Signed32(), kMachInt32},
+ {kTypedArrayBoundsCheck, kTaggedBase, FixedTypedArrayBase::kDataOffset,
+ Type::Unsigned32(), kMachUint32},
+ {kTypedArrayBoundsCheck, kTaggedBase, FixedTypedArrayBase::kDataOffset,
+ Type::Number(), kRepFloat32},
+ {kTypedArrayBoundsCheck, kTaggedBase, FixedTypedArrayBase::kDataOffset,
+ Type::Number(), kRepFloat64}};
} // namespace
#include "src/compiler/simplified-operator.h"
+#include <ostream> // NOLINT(readability/streams)
+
#include "src/base/lazy-instance.h"
#include "src/compiler/opcodes.h"
#include "src/compiler/operator.h"
}
+std::ostream& operator<<(std::ostream& os, BoundsCheckMode bounds_check_mode) {
+ switch (bounds_check_mode) {
+ case kNoBoundsCheck:
+ return os << "no bounds check";
+ case kTypedArrayBoundsCheck:
+ return os << "ignore out of bounds";
+ }
+ UNREACHABLE();
+ return os;
+}
+
+
bool operator==(ElementAccess const& lhs, ElementAccess const& rhs) {
return lhs.base_is_tagged == rhs.base_is_tagged &&
lhs.header_size == rhs.header_size && lhs.type == rhs.type &&
std::ostream& operator<<(std::ostream& os, ElementAccess const& access) {
os << "[" << access.base_is_tagged << ", " << access.header_size << ", ";
access.type->PrintTo(os);
- os << ", " << access.machine_type << "]";
+ os << ", " << access.machine_type << ", " << access.bounds_check << "]";
return os;
}
#ifndef V8_COMPILER_SIMPLIFIED_OPERATOR_H_
#define V8_COMPILER_SIMPLIFIED_OPERATOR_H_
+#include <iosfwd>
+
#include "src/compiler/machine-type.h"
#include "src/handles.h"
};
+enum BoundsCheckMode { kNoBoundsCheck, kTypedArrayBoundsCheck };
+
+std::ostream& operator<<(std::ostream&, BoundsCheckMode);
+
+
// An access descriptor for loads/stores of indexed structures like characters
// in strings or off-heap backing stores. Accesses from either tagged or
// untagged base pointers are supported; untagging is done automatically during
// lowering.
struct ElementAccess {
+ BoundsCheckMode bounds_check; // specifies the bounds checking mode.
BaseTaggedness base_is_tagged; // specifies if the base pointer is tagged.
int header_size; // size of the header, without tag.
Type* type; // type of the element.
for (size_t i = 0; i < arraysize(smis); i++) { // for header sizes
for (size_t j = 0; (i + j) < arraysize(smis); j++) { // for element index
int offset = static_cast<int>(i * sizeof(Smi*));
- ElementAccess access = {kUntaggedBase, offset, Type::Integral32(),
- kMachAnyTagged};
+ ElementAccess access = {kNoBoundsCheck, kUntaggedBase, offset,
+ Type::Integral32(), kMachAnyTagged};
SimplifiedLoweringTester<Object*> t;
Node* load = t.LoadElement(
for (size_t i = 0; i < arraysize(smis); i++) { // for header sizes
for (size_t j = 0; (i + j) < arraysize(smis); j++) { // for element index
int offset = static_cast<int>(i * sizeof(Smi*));
- ElementAccess access = {kUntaggedBase, offset, Type::Integral32(),
- kMachAnyTagged};
+ ElementAccess access = {kNoBoundsCheck, kUntaggedBase, offset,
+ Type::Integral32(), kMachAnyTagged};
SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
Node* p0 = t.Parameter(0);
private:
ElementAccess GetElementAccess() {
- ElementAccess access = {tagged ? kTaggedBase : kUntaggedBase,
- tagged ? FixedArrayBase::kHeaderSize : 0,
- Type::Any(), rep};
+ ElementAccess access = {
+ kNoBoundsCheck, tagged ? kTaggedBase : kUntaggedBase,
+ tagged ? FixedArrayBase::kHeaderSize : 0, Type::Any(), rep};
return access;
}
TestingGraph t(Type::Any(), Type::Signed32());
for (size_t i = 0; i < arraysize(machine_reps); i++) {
- ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
- Type::Any(), machine_reps[i]};
+ ElementAccess access = {kNoBoundsCheck, kTaggedBase,
+ FixedArrayBase::kHeaderSize, Type::Any(),
+ machine_reps[i]};
Node* load =
t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0, t.p1,
TestingGraph t(Type::Any(), Type::Signed32());
for (size_t i = 0; i < arraysize(machine_reps); i++) {
- ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
- Type::Any(), machine_reps[i]};
+ ElementAccess access = {kNoBoundsCheck, kTaggedBase,
+ FixedArrayBase::kHeaderSize, Type::Any(),
+ machine_reps[i]};
Node* val = t.ExampleWithOutput(machine_reps[i]);
Node* store = t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0,
// LoadElement(obj: Tagged, index: kTypeInt32 | kRepTagged, length) =>
// Load(obj, Int32Add(Int32Mul(ChangeTaggedToInt32(index), #k), #k))
TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
- ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
+ ElementAccess access = {kNoBoundsCheck, kTaggedBase,
+ FixedArrayBase::kHeaderSize, Type::Any(),
kMachAnyTagged};
Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0,
// StoreElement(obj: Tagged, index: kTypeInt32 | kRepTagged, length, val) =>
// Store(obj, Int32Add(Int32Mul(ChangeTaggedToInt32(index), #k), #k), val)
TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
- ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
+ ElementAccess access = {kNoBoundsCheck, kTaggedBase,
+ FixedArrayBase::kHeaderSize, Type::Any(),
kMachAnyTagged};
Node* store =
TEST(InsertChangeForLoadElement) {
// TODO(titzer): test all load/store representation change insertions.
TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
- ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
+ ElementAccess access = {kNoBoundsCheck, kTaggedBase,
+ FixedArrayBase::kHeaderSize, Type::Any(),
kMachFloat64};
Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0,
TEST(InsertChangeForStoreElement) {
// TODO(titzer): test all load/store representation change insertions.
TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
- ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
+ ElementAccess access = {kNoBoundsCheck, kTaggedBase,
+ FixedArrayBase::kHeaderSize, Type::Any(),
kMachFloat64};
Node* store = t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0,