[turbofan] Add BoundsCheckMode to ElementAccess.
This is currently only used for StoreElement. LoadElement will be updated to make use of that in a follow-up CL (depends on additional control input for loads first). TEST=cctest,mjsunit R=jarin@chromium.org, mstarzinger@chromium.org Review URL: https://codereview.chromium.org/617853002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24347 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
63851465f2
commit
67383fe700
@ -53,7 +53,8 @@ FieldAccess AccessBuilder::ForExternalArrayPointer() {
|
||||
|
||||
// static
|
||||
ElementAccess AccessBuilder::ForFixedArrayElement() {
|
||||
return {kTaggedBase, FixedArray::kHeaderSize, Type::Any(), kMachAnyTagged};
|
||||
return {kNoBoundsCheck, kTaggedBase, FixedArray::kHeaderSize, Type::Any(),
|
||||
kMachAnyTagged};
|
||||
}
|
||||
|
||||
|
||||
@ -64,25 +65,33 @@ ElementAccess AccessBuilder::ForTypedArrayElement(ExternalArrayType type,
|
||||
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
|
||||
|
@ -597,26 +597,12 @@ Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) {
|
||||
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();
|
||||
}
|
||||
|
@ -876,12 +876,41 @@ void SimplifiedLowering::DoLoadElement(Node* node) {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -119,43 +119,44 @@ INSTANTIATE_TEST_CASE_P(SimplifiedOperatorTest, SimplifiedPureOperatorTest,
|
||||
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
|
||||
|
||||
|
@ -4,6 +4,8 @@
|
||||
|
||||
#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"
|
||||
@ -25,6 +27,18 @@ std::ostream& operator<<(std::ostream& os, BaseTaggedness base_taggedness) {
|
||||
}
|
||||
|
||||
|
||||
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 &&
|
||||
@ -40,7 +54,7 @@ bool operator!=(ElementAccess const& lhs, ElementAccess const& rhs) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,8 @@
|
||||
#ifndef V8_COMPILER_SIMPLIFIED_OPERATOR_H_
|
||||
#define V8_COMPILER_SIMPLIFIED_OPERATOR_H_
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
#include "src/compiler/machine-type.h"
|
||||
#include "src/handles.h"
|
||||
|
||||
@ -44,11 +46,17 @@ struct FieldAccess {
|
||||
};
|
||||
|
||||
|
||||
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.
|
||||
|
@ -325,8 +325,8 @@ TEST(RunLoadElementFromUntaggedBase) {
|
||||
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(
|
||||
@ -354,8 +354,8 @@ TEST(RunStoreElementFromUntaggedBase) {
|
||||
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);
|
||||
@ -517,9 +517,9 @@ class AccessTester : public HandleAndZoneScope {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1349,8 +1349,9 @@ TEST(LowerLoadElement_to_load) {
|
||||
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,
|
||||
@ -1372,8 +1373,9 @@ TEST(LowerStoreElement_to_store) {
|
||||
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,
|
||||
@ -1398,7 +1400,8 @@ TEST(InsertChangeForLoadElementIndex) {
|
||||
// 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,
|
||||
@ -1417,7 +1420,8 @@ TEST(InsertChangeForStoreElementIndex) {
|
||||
// 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 =
|
||||
@ -1436,7 +1440,8 @@ TEST(InsertChangeForStoreElementIndex) {
|
||||
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,
|
||||
@ -1468,7 +1473,8 @@ TEST(InsertChangeForLoadField) {
|
||||
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,
|
||||
|
Loading…
Reference in New Issue
Block a user