5 #include "src/compiler/property-access-builder.h" 7 #include "src/compiler/access-builder.h" 8 #include "src/compiler/access-info.h" 9 #include "src/compiler/compilation-dependencies.h" 10 #include "src/compiler/js-graph.h" 11 #include "src/compiler/node-matchers.h" 12 #include "src/compiler/simplified-operator.h" 13 #include "src/lookup.h" 15 #include "src/field-index-inl.h" 16 #include "src/isolate-inl.h" 22 Graph* PropertyAccessBuilder::graph()
const {
return jsgraph()->graph(); }
24 Isolate* PropertyAccessBuilder::isolate()
const {
return jsgraph()->isolate(); }
26 CommonOperatorBuilder* PropertyAccessBuilder::common()
const {
27 return jsgraph()->common();
30 SimplifiedOperatorBuilder* PropertyAccessBuilder::simplified()
const {
31 return jsgraph()->simplified();
34 bool HasOnlyStringMaps(MapHandles
const& maps) {
35 for (
auto map : maps) {
36 if (!map->IsStringMap())
return false;
43 bool HasOnlyNumberMaps(MapHandles
const& maps) {
44 for (
auto map : maps) {
45 if (map->instance_type() != HEAP_NUMBER_TYPE)
return false;
52 bool PropertyAccessBuilder::TryBuildStringCheck(MapHandles
const& maps,
53 Node** receiver, Node** effect,
55 if (HasOnlyStringMaps(maps)) {
59 graph()->NewNode(simplified()->CheckString(VectorSlotPair()), *receiver,
66 bool PropertyAccessBuilder::TryBuildNumberCheck(MapHandles
const& maps,
67 Node** receiver, Node** effect,
69 if (HasOnlyNumberMaps(maps)) {
72 graph()->NewNode(simplified()->CheckNumber(VectorSlotPair()), *receiver,
81 bool NeedsCheckHeapObject(Node* receiver) {
82 switch (receiver->opcode()) {
83 case IrOpcode::kConvertReceiver:
84 case IrOpcode::kHeapConstant:
85 case IrOpcode::kJSCreate:
86 case IrOpcode::kJSCreateArguments:
87 case IrOpcode::kJSCreateArray:
88 case IrOpcode::kJSCreateClosure:
89 case IrOpcode::kJSCreateIterResultObject:
90 case IrOpcode::kJSCreateLiteralArray:
91 case IrOpcode::kJSCreateEmptyLiteralArray:
92 case IrOpcode::kJSCreateArrayFromIterable:
93 case IrOpcode::kJSCreateLiteralObject:
94 case IrOpcode::kJSCreateEmptyLiteralObject:
95 case IrOpcode::kJSCreateLiteralRegExp:
96 case IrOpcode::kJSCreateGeneratorObject:
97 case IrOpcode::kJSConstructForwardVarargs:
98 case IrOpcode::kJSConstruct:
99 case IrOpcode::kJSConstructWithArrayLike:
100 case IrOpcode::kJSConstructWithSpread:
101 case IrOpcode::kJSToName:
102 case IrOpcode::kJSToString:
103 case IrOpcode::kJSToObject:
104 case IrOpcode::kTypeOf:
105 case IrOpcode::kJSGetSuperConstructor:
107 case IrOpcode::kPhi: {
108 Node* control = NodeProperties::GetControlInput(receiver);
109 if (control->opcode() != IrOpcode::kMerge)
return true;
110 for (
int i = 0;
i < receiver->InputCount() - 1; ++
i) {
111 if (NeedsCheckHeapObject(receiver->InputAt(
i)))
return true;
122 Node* PropertyAccessBuilder::BuildCheckHeapObject(Node* receiver, Node** effect,
124 if (NeedsCheckHeapObject(receiver)) {
125 receiver = *effect = graph()->NewNode(simplified()->CheckHeapObject(),
126 receiver, *effect, control);
131 void PropertyAccessBuilder::BuildCheckMaps(
132 Node* receiver, Node** effect, Node* control,
133 std::vector<Handle<Map>>
const& receiver_maps) {
134 HeapObjectMatcher m(receiver);
136 Handle<Map> receiver_map(m.Value()->map(), isolate());
137 if (receiver_map->is_stable()) {
138 for (Handle<Map> map : receiver_maps) {
139 if (map.is_identical_to(receiver_map)) {
140 dependencies()->DependOnStableMap(MapRef(broker(), receiver_map));
146 ZoneHandleSet<Map> maps;
147 CheckMapsFlags flags = CheckMapsFlag::kNone;
148 for (Handle<Map> map : receiver_maps) {
149 maps.insert(map, graph()->zone());
150 if (map->is_migration_target()) {
151 flags |= CheckMapsFlag::kTryMigrateInstance;
154 *effect = graph()->NewNode(simplified()->CheckMaps(flags, maps), receiver,
158 Node* PropertyAccessBuilder::BuildCheckValue(Node* receiver, Node** effect,
160 Handle<HeapObject> value) {
161 HeapObjectMatcher m(receiver);
162 if (m.Is(value))
return receiver;
163 Node* expected = jsgraph()->HeapConstant(value);
165 graph()->NewNode(simplified()->ReferenceEqual(), receiver, expected);
167 graph()->NewNode(simplified()->CheckIf(DeoptimizeReason::kWrongValue),
168 check, *effect, control);
172 Node* PropertyAccessBuilder::ResolveHolder(
173 PropertyAccessInfo
const& access_info, Node* receiver) {
174 Handle<JSObject> holder;
175 if (access_info.holder().ToHandle(&holder)) {
176 return jsgraph()->Constant(holder);
181 Node* PropertyAccessBuilder::TryBuildLoadConstantDataField(
182 Handle<Name> name, PropertyAccessInfo
const& access_info, Node* receiver) {
184 HeapObjectMatcher m(receiver);
185 if (m.HasValue() && m.Value()->IsJSObject()) {
196 LookupIterator it(isolate(), m.Value(), name,
197 LookupIterator::OWN_SKIP_INTERCEPTOR);
198 if (it.state() == LookupIterator::DATA) {
199 bool is_readonly_non_configurable =
200 it.IsReadOnly() && !it.IsConfigurable();
201 if (is_readonly_non_configurable ||
202 (FLAG_track_constant_fields && access_info.IsDataConstantField())) {
203 Node* value = jsgraph()->Constant(JSReceiver::GetDataProperty(&it));
204 if (!is_readonly_non_configurable) {
207 DCHECK(access_info.IsDataConstantField());
208 DCHECK(!it.is_dictionary_holder());
210 handle(it.GetHolder<HeapObject>()->map(), isolate()));
211 map.SerializeOwnDescriptors();
212 dependencies()->DependOnFieldType(map, it.GetFieldDescriptorIndex());
221 Node* PropertyAccessBuilder::BuildLoadDataField(
222 Handle<Name> name, PropertyAccessInfo
const& access_info, Node* receiver,
223 Node** effect, Node** control) {
224 DCHECK(access_info.IsDataField() || access_info.IsDataConstantField());
225 receiver = ResolveHolder(access_info, receiver);
227 TryBuildLoadConstantDataField(name, access_info, receiver)) {
231 FieldIndex
const field_index = access_info.field_index();
232 Type const field_type = access_info.field_type();
233 MachineRepresentation
const field_representation =
234 access_info.field_representation();
235 Node* storage = receiver;
236 if (!field_index.is_inobject()) {
237 storage = *effect = graph()->NewNode(
238 simplified()->LoadField(AccessBuilder::ForJSObjectPropertiesOrHash()),
239 storage, *effect, *control);
241 FieldAccess field_access = {
243 field_index.offset(),
247 MachineType::TypeForRepresentation(field_representation),
249 LoadSensitivity::kCritical};
250 if (field_representation == MachineRepresentation::kFloat64) {
251 if (!field_index.is_inobject() || field_index.is_hidden_field() ||
252 !FLAG_unbox_double_fields) {
253 FieldAccess
const storage_access = {kTaggedBase,
254 field_index.offset(),
257 Type::OtherInternal(),
258 MachineType::TaggedPointer(),
259 kPointerWriteBarrier,
260 LoadSensitivity::kCritical};
261 storage = *effect = graph()->NewNode(
262 simplified()->LoadField(storage_access), storage, *effect, *control);
263 field_access.offset = HeapNumber::kValueOffset;
264 field_access.name = MaybeHandle<Name>();
266 }
else if (field_representation == MachineRepresentation::kTaggedPointer) {
269 Handle<Map> field_map;
270 if (access_info.field_map().ToHandle(&field_map)) {
271 if (field_map->is_stable()) {
272 dependencies()->DependOnStableMap(MapRef(broker(), field_map));
273 field_access.map = field_map;
277 Node* value = *effect = graph()->NewNode(
278 simplified()->LoadField(field_access), storage, *effect, *control);