[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:
bmeurer@chromium.org 2014-10-01 07:42:54 +00:00
parent 63851465f2
commit 67383fe700
7 changed files with 139 additions and 86 deletions

View File

@ -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

View File

@ -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();
}

View File

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

View File

@ -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

View File

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

View File

@ -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.

View File

@ -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,