static WriteBarrierKind ComputeWriteBarrierKind(
- MachineRepresentation representation, Type* type) {
+ BaseTaggedness base_is_tagged, MachineRepresentation representation,
+ Type* type) {
// TODO(turbofan): skip write barriers for Smis, etc.
- if (representation == kMachineTagged) {
+ if (base_is_tagged == kTaggedBase && representation == kMachineTagged) {
+ // Write barriers are only for writes into heap objects (i.e. tagged base).
return kFullWriteBarrier;
}
return kNoWriteBarrier;
void SimplifiedLowering::DoLoadField(Node* node, Node* effect, Node* control) {
const FieldAccess& access = FieldAccessOf(node->op());
node->set_op(machine_.Load(access.representation));
- Node* offset =
- graph()->NewNode(common()->Int32Constant(access.offset - kHeapObjectTag));
+ Node* offset = jsgraph()->Int32Constant(access.offset - access.tag());
node->InsertInput(zone(), 1, offset);
}
void SimplifiedLowering::DoStoreField(Node* node, Node* effect, Node* control) {
const FieldAccess& access = FieldAccessOf(node->op());
- WriteBarrierKind kind =
- ComputeWriteBarrierKind(access.representation, access.type);
+ WriteBarrierKind kind = ComputeWriteBarrierKind(
+ access.base_is_tagged, access.representation, access.type);
node->set_op(machine_.Store(access.representation, kind));
- Node* offset =
- graph()->NewNode(common()->Int32Constant(access.offset - kHeapObjectTag));
+ Node* offset = jsgraph()->Int32Constant(access.offset - access.tag());
node->InsertInput(zone(), 1, offset);
}
break;
}
if (element_size != 1) {
- index = graph()->NewNode(
- machine()->Int32Mul(),
- graph()->NewNode(common()->Int32Constant(element_size)), index);
+ index = graph()->NewNode(machine()->Int32Mul(),
+ jsgraph()->Int32Constant(element_size), index);
}
- int fixed_offset = access.header_size - kHeapObjectTag;
+ int fixed_offset = access.header_size - access.tag();
if (fixed_offset == 0) return index;
- return graph()->NewNode(
- machine()->Int32Add(),
- graph()->NewNode(common()->Int32Constant(fixed_offset)), index);
+ return graph()->NewNode(machine()->Int32Add(),
+ jsgraph()->Int32Constant(fixed_offset), index);
}
void SimplifiedLowering::DoStoreElement(Node* node, Node* effect,
Node* control) {
const ElementAccess& access = ElementAccessOf(node->op());
- WriteBarrierKind kind =
- ComputeWriteBarrierKind(access.representation, access.type);
+ WriteBarrierKind kind = ComputeWriteBarrierKind(
+ access.base_is_tagged, access.representation, access.type);
node->set_op(machine_.Store(access.representation, kind));
node->ReplaceInput(1, ComputeIndex(access, node->InputAt(1)));
}
namespace internal {
namespace compiler {
-// An access descriptor for loads/stores from/to fixed structures
-// like field accesses of heap objects.
+enum BaseTaggedness { kUntaggedBase, kTaggedBase };
+
+// An access descriptor for loads/stores of fixed structures like field
+// accesses of heap objects. Accesses from either tagged or untagged base
+// pointers are supported; untagging is done automatically during lowering.
struct FieldAccess {
- int offset;
- Handle<Name> name; // debug only.
- Type* type;
- MachineRepresentation representation;
+ BaseTaggedness base_is_tagged; // specifies if the base pointer is tagged.
+ int offset; // offset of the field, without tag.
+ Handle<Name> name; // debugging only.
+ Type* type; // type of the field.
+ MachineRepresentation representation; // machine representation of field.
+
+ int tag() const { return base_is_tagged == kTaggedBase ? kHeapObjectTag : 0; }
};
-// An access descriptor for loads/stores of indexed structures
-// like characters in strings or off-heap backing stores.
+// 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 {
- int header_size;
- Type* type;
- MachineRepresentation representation;
+ 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.
+ MachineRepresentation representation; // machine representation of element.
+
+ int tag() const { return base_is_tagged == kTaggedBase ? kHeapObjectTag : 0; }
};
return (val.offset < 16) | (val.representation & 0xffff);
}
static bool Equals(const FieldAccess& a, const FieldAccess& b) {
- return a.offset == b.offset && a.representation == b.representation &&
- a.type->Is(b.type);
+ return a.base_is_tagged == b.base_is_tagged && a.offset == b.offset &&
+ a.representation == b.representation && a.type->Is(b.type);
}
};
return (val.header_size < 16) | (val.representation & 0xffff);
}
static bool Equals(const ElementAccess& a, const ElementAccess& b) {
- return a.header_size == b.header_size &&
+ return a.base_is_tagged == b.base_is_tagged &&
+ a.header_size == b.header_size &&
a.representation == b.representation && a.type->Is(b.type);
}
};
namespace {
FieldAccess ForJSObjectMap() {
- FieldAccess access = {JSObject::kMapOffset, Handle<Name>(), Type::Any(),
- kMachineTagged};
+ FieldAccess access = {kTaggedBase, JSObject::kMapOffset, Handle<Name>(),
+ Type::Any(), kMachineTagged};
return access;
}
FieldAccess ForJSObjectProperties() {
- FieldAccess access = {JSObject::kPropertiesOffset, Handle<Name>(),
- Type::Any(), kMachineTagged};
+ FieldAccess access = {kTaggedBase, JSObject::kPropertiesOffset,
+ Handle<Name>(), Type::Any(), kMachineTagged};
return access;
}
FieldAccess ForArrayBufferBackingStore() {
FieldAccess access = {
- JSArrayBuffer::kBackingStoreOffset, Handle<Name>(), Type::UntaggedPtr(),
+ kTaggedBase, JSArrayBuffer::kBackingStoreOffset,
+ Handle<Name>(), Type::UntaggedPtr(),
MachineOperatorBuilder::pointer_rep(),
};
return access;
ElementAccess ForFixedArrayElement() {
- ElementAccess access = {FixedArray::kHeaderSize, Type::Any(), kMachineTagged};
+ ElementAccess access = {kTaggedBase, FixedArray::kHeaderSize, Type::Any(),
+ kMachineTagged};
return access;
}
ElementAccess ForBackingStoreElement(MachineRepresentation rep) {
- ElementAccess access = {kNonHeapObjectHeaderSize, Type::Any(), rep};
+ ElementAccess access = {kUntaggedBase,
+ kNonHeapObjectHeaderSize - kHeapObjectTag,
+ Type::Any(), rep};
return access;
}
}
CHECK_EQ(src_copy->get(i), dst->get(i));
}
}
+
+
+TEST(RunLoadFieldFromUntaggedBase) {
+ Smi* smis[] = {Smi::FromInt(1), Smi::FromInt(2), Smi::FromInt(3)};
+
+ for (size_t i = 0; i < ARRAY_SIZE(smis); i++) {
+ FieldAccess access = {kUntaggedBase, // untagged base
+ i * sizeof(Smi*), // offset
+ Handle<Name>(), Type::Integral32(), kMachineTagged};
+
+ SimplifiedGraphBuilderTester<Object*> t;
+ Node* load = t.LoadField(access, t.PointerConstant(smis));
+ t.Return(load);
+ t.LowerAllNodes();
+
+ for (int j = -5; j <= 5; j++) {
+ Smi* expected = Smi::FromInt(j);
+ smis[i] = expected;
+ CHECK_EQ(expected, t.Call());
+ }
+ }
+}
+
+
+TEST(RunStoreFieldToUntaggedBase) {
+ Smi* smis[] = {Smi::FromInt(1), Smi::FromInt(2), Smi::FromInt(3)};
+
+ for (size_t i = 0; i < ARRAY_SIZE(smis); i++) {
+ FieldAccess access = {kUntaggedBase, // untagged base
+ i * sizeof(Smi*), // offset
+ Handle<Name>(), Type::Integral32(), kMachineTagged};
+
+ SimplifiedGraphBuilderTester<Object*> t(kMachineTagged);
+ Node* p0 = t.Parameter(0);
+ t.StoreField(access, t.PointerConstant(smis), p0);
+ t.Return(p0);
+ t.LowerAllNodes();
+
+ for (int j = -5; j <= 5; j++) {
+ Smi* expected = Smi::FromInt(j);
+ smis[i] = Smi::FromInt(-100);
+ CHECK_EQ(expected, t.Call(expected));
+ CHECK_EQ(expected, smis[i]);
+ }
+ }
+}
+
+
+TEST(RunLoadElementFromUntaggedBase) {
+ Smi* smis[] = {Smi::FromInt(1), Smi::FromInt(2), Smi::FromInt(3),
+ Smi::FromInt(4), Smi::FromInt(5)};
+
+ for (size_t i = 0; i < ARRAY_SIZE(smis); i++) { // for header sizes
+ for (size_t j = i; j < ARRAY_SIZE(smis); j++) { // for element index
+ ElementAccess access = {kUntaggedBase, // untagged base
+ i * sizeof(Smi*), // header size
+ Type::Integral32(), kMachineTagged};
+
+ SimplifiedGraphBuilderTester<Object*> t;
+ Node* load =
+ t.LoadElement(access, t.PointerConstant(smis), t.Int32Constant(j));
+ t.Return(load);
+ t.LowerAllNodes();
+
+ for (int k = -5; k <= 5; k++) {
+ Smi* expected = Smi::FromInt(k);
+ smis[i + j] = expected;
+ CHECK_EQ(expected, t.Call());
+ }
+ }
+ }
+}
+
+
+TEST(RunStoreElementFromUntaggedBase) {
+ Smi* smis[] = {Smi::FromInt(1), Smi::FromInt(2), Smi::FromInt(3),
+ Smi::FromInt(4), Smi::FromInt(5)};
+
+ for (size_t i = 0; i < ARRAY_SIZE(smis); i++) { // for header sizes
+ for (size_t j = i; j < ARRAY_SIZE(smis); j++) { // for element index
+ ElementAccess access = {kUntaggedBase, // untagged base
+ i * sizeof(Smi*), // header size
+ Type::Integral32(), kMachineTagged};
+
+ SimplifiedGraphBuilderTester<Object*> t(kMachineTagged);
+ Node* p0 = t.Parameter(0);
+ t.StoreElement(access, t.PointerConstant(smis), t.Int32Constant(j), p0);
+ t.Return(p0);
+ t.LowerAllNodes();
+
+ for (int k = -5; k <= 5; k++) {
+ Smi* expected = Smi::FromInt(k);
+ smis[i + j] = Smi::FromInt(-100);
+ CHECK_EQ(expected, t.Call(expected));
+ CHECK_EQ(expected, smis[i + j]);
+ }
+ }
+ }
+}