1 // Copyright 2018 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef V8_COMPILER_JS_HEAP_BROKER_H_
6 #define V8_COMPILER_JS_HEAP_BROKER_H_
7
8 #include "src/base/compiler-specific.h"
9 #include "src/base/optional.h"
10 #include "src/globals.h"
11 #include "src/objects.h"
12 #include "src/zone/zone-containers.h"
13
14 namespace v8 {
15 namespace internal {
16 namespace compiler {
17
18 enum class OddballType : uint8_t {
19 kNone, // Not an Oddball.
20 kBoolean, // True or False.
21 kUndefined,
22 kNull,
23 kHole,
24 kUninitialized,
25 kOther // Oddball, but none of the above.
26 };
27
28 // TODO(neis): Get rid of the HeapObjectType class.
29 class HeapObjectType {
30 public:
31 enum Flag : uint8_t { kUndetectable = 1 << 0, kCallable = 1 << 1 };
32
33 typedef base::Flags<Flag> Flags;
34
HeapObjectType(InstanceType instance_type,Flags flags,OddballType oddball_type)35 HeapObjectType(InstanceType instance_type, Flags flags,
36 OddballType oddball_type)
37 : instance_type_(instance_type),
38 oddball_type_(oddball_type),
39 flags_(flags) {
40 DCHECK_EQ(instance_type == ODDBALL_TYPE,
41 oddball_type != OddballType::kNone);
42 }
43
oddball_type()44 OddballType oddball_type() const { return oddball_type_; }
instance_type()45 InstanceType instance_type() const { return instance_type_; }
flags()46 Flags flags() const { return flags_; }
47
is_callable()48 bool is_callable() const { return flags_ & kCallable; }
is_undetectable()49 bool is_undetectable() const { return flags_ & kUndetectable; }
50
51 private:
52 InstanceType const instance_type_;
53 OddballType const oddball_type_;
54 Flags const flags_;
55 };
56
57 // This list is sorted such that subtypes appear before their supertypes.
58 // DO NOT VIOLATE THIS PROPERTY!
59 #define HEAP_BROKER_OBJECT_LIST(V) \
60 /* Subtypes of JSObject */ \
61 V(JSArray) \
62 V(JSFunction) \
63 V(JSGlobalProxy) \
64 V(JSRegExp) \
65 /* Subtypes of Context */ \
66 V(NativeContext) \
67 /* Subtypes of FixedArrayBase */ \
68 V(BytecodeArray) \
69 V(FixedArray) \
70 V(FixedDoubleArray) \
71 /* Subtypes of Name */ \
72 V(InternalizedString) \
73 V(String) \
74 /* Subtypes of HeapObject */ \
75 V(AllocationSite) \
76 V(Cell) \
77 V(Code) \
78 V(FeedbackVector) \
79 V(Map) \
80 V(Module) \
81 V(ScopeInfo) \
82 V(ScriptContextTable) \
83 V(SharedFunctionInfo) \
84 V(Context) \
85 V(FixedArrayBase) \
86 V(HeapNumber) \
87 V(JSObject) \
88 V(MutableHeapNumber) \
89 V(Name) \
90 V(PropertyCell) \
91 /* Subtypes of Object */ \
92 V(HeapObject)
93
94 class CompilationDependencies;
95 class JSHeapBroker;
96 class ObjectData;
97 #define FORWARD_DECL(Name) class Name##Ref;
HEAP_BROKER_OBJECT_LIST(FORWARD_DECL)98 HEAP_BROKER_OBJECT_LIST(FORWARD_DECL)
99 #undef FORWARD_DECL
100
101 class ObjectRef {
102 public:
103 ObjectRef(JSHeapBroker* broker, Handle<Object> object);
104 explicit ObjectRef(ObjectData* data) : data_(data) { CHECK_NOT_NULL(data_); }
105
106 bool equals(const ObjectRef& other) const;
107
108 Handle<Object> object() const;
109 // TODO(neis): Remove eventually.
110 template <typename T>
111 Handle<T> object() const {
112 AllowHandleDereference handle_dereference;
113 return Handle<T>::cast(object());
114 }
115
116 OddballType oddball_type() const;
117
118 bool IsSmi() const;
119 int AsSmi() const;
120
121 #define HEAP_IS_METHOD_DECL(Name) bool Is##Name() const;
122 HEAP_BROKER_OBJECT_LIST(HEAP_IS_METHOD_DECL)
123 #undef HEAP_IS_METHOD_DECL
124
125 #define HEAP_AS_METHOD_DECL(Name) Name##Ref As##Name() const;
126 HEAP_BROKER_OBJECT_LIST(HEAP_AS_METHOD_DECL)
127 #undef HEAP_AS_METHOD_DECL
128
129 StringRef TypeOf() const;
130 bool BooleanValue();
131 double OddballToNumber() const;
132
133 Isolate* isolate() const;
134
135 protected:
136 JSHeapBroker* broker() const;
137 ObjectData* data() const;
138
139 private:
140 ObjectData* data_;
141 };
142
143 class HeapObjectRef : public ObjectRef {
144 public:
145 using ObjectRef::ObjectRef;
146
147 HeapObjectType type() const;
148 MapRef map() const;
149 base::Optional<MapRef> TryGetObjectCreateMap() const;
150 bool IsSeqString() const;
151 bool IsExternalString() const;
152 };
153
154 class PropertyCellRef : public HeapObjectRef {
155 public:
156 using HeapObjectRef::HeapObjectRef;
157
158 ObjectRef value() const;
159 PropertyDetails property_details() const;
160 };
161
162 class JSObjectRef : public HeapObjectRef {
163 public:
164 using HeapObjectRef::HeapObjectRef;
165
166 bool IsUnboxedDoubleField(FieldIndex index) const;
167 double RawFastDoublePropertyAt(FieldIndex index) const;
168 ObjectRef RawFastPropertyAt(FieldIndex index) const;
169
170 FixedArrayBaseRef elements() const;
171 void EnsureElementsTenured();
172 ElementsKind GetElementsKind() const;
173 };
174
175 class JSFunctionRef : public JSObjectRef {
176 public:
177 using JSObjectRef::JSObjectRef;
178
179 bool IsConstructor() const;
180 bool has_initial_map() const;
181 MapRef initial_map() const;
182 bool has_prototype() const;
183 ObjectRef prototype() const;
184 bool PrototypeRequiresRuntimeLookup() const;
185 JSGlobalProxyRef global_proxy() const;
186 int InitialMapInstanceSizeWithMinSlack() const;
187 SharedFunctionInfoRef shared() const;
188 };
189
190 class JSRegExpRef : public JSObjectRef {
191 public:
192 using JSObjectRef::JSObjectRef;
193
194 ObjectRef raw_properties_or_hash() const;
195 ObjectRef data() const;
196 ObjectRef source() const;
197 ObjectRef flags() const;
198 ObjectRef last_index() const;
199 };
200
201 class HeapNumberRef : public HeapObjectRef {
202 public:
203 using HeapObjectRef::HeapObjectRef;
204
205 double value() const;
206 };
207
208 class MutableHeapNumberRef : public HeapObjectRef {
209 public:
210 using HeapObjectRef::HeapObjectRef;
211
212 double value() const;
213 };
214
215 class ContextRef : public HeapObjectRef {
216 public:
217 using HeapObjectRef::HeapObjectRef;
218
219 base::Optional<ContextRef> previous() const;
220 ObjectRef get(int index) const;
221 };
222
223 #define BROKER_NATIVE_CONTEXT_FIELDS(V) \
224 V(JSFunction, array_function) \
225 V(JSFunction, object_function) \
226 V(JSFunction, promise_function) \
227 V(Map, fast_aliased_arguments_map) \
228 V(Map, initial_array_iterator_map) \
229 V(Map, iterator_result_map) \
230 V(Map, js_array_holey_double_elements_map) \
231 V(Map, js_array_holey_elements_map) \
232 V(Map, js_array_holey_smi_elements_map) \
233 V(Map, js_array_packed_double_elements_map) \
234 V(Map, js_array_packed_elements_map) \
235 V(Map, js_array_packed_smi_elements_map) \
236 V(Map, map_key_iterator_map) \
237 V(Map, map_key_value_iterator_map) \
238 V(Map, map_value_iterator_map) \
239 V(Map, set_key_value_iterator_map) \
240 V(Map, set_value_iterator_map) \
241 V(Map, sloppy_arguments_map) \
242 V(Map, strict_arguments_map) \
243 V(Map, string_iterator_map) \
244 V(ScriptContextTable, script_context_table)
245
246 class NativeContextRef : public ContextRef {
247 public:
248 using ContextRef::ContextRef;
249
250 #define DECL_ACCESSOR(type, name) type##Ref name() const;
251 BROKER_NATIVE_CONTEXT_FIELDS(DECL_ACCESSOR)
252 #undef DECL_ACCESSOR
253
254 MapRef GetFunctionMapFromIndex(int index) const;
255 MapRef GetInitialJSArrayMap(ElementsKind kind) const;
256 };
257
258 class NameRef : public HeapObjectRef {
259 public:
260 using HeapObjectRef::HeapObjectRef;
261 };
262
263 class ScriptContextTableRef : public HeapObjectRef {
264 public:
265 using HeapObjectRef::HeapObjectRef;
266
267 struct LookupResult {
268 ContextRef context;
269 bool immutable;
270 int index;
271 };
272
273 base::Optional<LookupResult> lookup(const NameRef& name) const;
274 };
275
276 class FeedbackVectorRef : public HeapObjectRef {
277 public:
278 using HeapObjectRef::HeapObjectRef;
279
280 ObjectRef get(FeedbackSlot slot) const;
281 };
282
283 class AllocationSiteRef : public HeapObjectRef {
284 public:
285 using HeapObjectRef::HeapObjectRef;
286
287 bool PointsToLiteral() const;
288 PretenureFlag GetPretenureMode() const;
289 ObjectRef nested_site() const;
290
291 // {IsFastLiteral} determines whether the given array or object literal
292 // boilerplate satisfies all limits to be considered for fast deep-copying
293 // and computes the total size of all objects that are part of the graph.
294 //
295 // If PointsToLiteral() is false, then IsFastLiteral() is also false.
296 bool IsFastLiteral() const;
297 // We only serialize boilerplate if IsFastLiteral is true.
298 base::Optional<JSObjectRef> boilerplate() const;
299
300 ElementsKind GetElementsKind() const;
301 bool CanInlineCall() const;
302 };
303
304 class MapRef : public HeapObjectRef {
305 public:
306 using HeapObjectRef::HeapObjectRef;
307
308 int instance_size() const;
309 InstanceType instance_type() const;
310 int GetInObjectProperties() const;
311 int GetInObjectPropertiesStartInWords() const;
312 int NumberOfOwnDescriptors() const;
313 int GetInObjectPropertyOffset(int index) const;
314 ElementsKind elements_kind() const;
315 bool is_stable() const;
316 bool has_prototype_slot() const;
317 bool is_deprecated() const;
318 bool CanBeDeprecated() const;
319 bool CanTransition() const;
320 bool IsInobjectSlackTrackingInProgress() const;
321 bool is_dictionary_map() const;
322 bool IsJSArrayMap() const;
323 bool IsFixedCowArrayMap() const;
324
325 ObjectRef constructor_or_backpointer() const;
326
327 base::Optional<MapRef> AsElementsKind(ElementsKind kind) const;
328
329 // Concerning the underlying instance_descriptors:
330 MapRef FindFieldOwner(int descriptor) const;
331 PropertyDetails GetPropertyDetails(int i) const;
332 NameRef GetPropertyKey(int i) const;
333 FieldIndex GetFieldIndexFor(int i) const;
334 ObjectRef GetFieldType(int descriptor) const;
335 };
336
337 class FixedArrayBaseRef : public HeapObjectRef {
338 public:
339 using HeapObjectRef::HeapObjectRef;
340
341 int length() const;
342 };
343
344 class FixedArrayRef : public FixedArrayBaseRef {
345 public:
346 using FixedArrayBaseRef::FixedArrayBaseRef;
347
348 ObjectRef get(int i) const;
349 bool is_the_hole(int i) const;
350 };
351
352 class FixedDoubleArrayRef : public FixedArrayBaseRef {
353 public:
354 using FixedArrayBaseRef::FixedArrayBaseRef;
355
356 double get_scalar(int i) const;
357 bool is_the_hole(int i) const;
358 };
359
360 class BytecodeArrayRef : public FixedArrayBaseRef {
361 public:
362 using FixedArrayBaseRef::FixedArrayBaseRef;
363
364 int register_count() const;
365 };
366
367 class JSArrayRef : public JSObjectRef {
368 public:
369 using JSObjectRef::JSObjectRef;
370
371 ObjectRef length() const;
372 };
373
374 class ScopeInfoRef : public HeapObjectRef {
375 public:
376 using HeapObjectRef::HeapObjectRef;
377
378 int ContextLength() const;
379 };
380
381 #define BROKER_SFI_FIELDS(V) \
382 V(int, internal_formal_parameter_count) \
383 V(bool, has_duplicate_parameters) \
384 V(int, function_map_index) \
385 V(FunctionKind, kind) \
386 V(LanguageMode, language_mode) \
387 V(bool, native) \
388 V(bool, HasBreakInfo) \
389 V(bool, HasBuiltinFunctionId) \
390 V(bool, HasBuiltinId) \
391 V(BuiltinFunctionId, builtin_function_id) \
392 V(bool, construct_as_builtin) \
393 V(bool, HasBytecodeArray)
394
395 class SharedFunctionInfoRef : public HeapObjectRef {
396 public:
397 using HeapObjectRef::HeapObjectRef;
398
399 int builtin_id() const;
400 BytecodeArrayRef GetBytecodeArray() const;
401 #define DECL_ACCESSOR(type, name) type name() const;
402 BROKER_SFI_FIELDS(DECL_ACCESSOR)
403 #undef DECL_ACCSESOR
404 };
405
406 class StringRef : public NameRef {
407 public:
408 using NameRef::NameRef;
409
410 int length() const;
411 uint16_t GetFirstChar();
412 base::Optional<double> ToNumber();
413 };
414
415 class ModuleRef : public HeapObjectRef {
416 public:
417 using HeapObjectRef::HeapObjectRef;
418
419 CellRef GetCell(int cell_index);
420 };
421
422 class CellRef : public HeapObjectRef {
423 public:
424 using HeapObjectRef::HeapObjectRef;
425 };
426
427 class JSGlobalProxyRef : public JSObjectRef {
428 public:
429 using JSObjectRef::JSObjectRef;
430 };
431
432 class CodeRef : public HeapObjectRef {
433 public:
434 using HeapObjectRef::HeapObjectRef;
435 };
436
437 class InternalizedStringRef : public StringRef {
438 public:
439 using StringRef::StringRef;
440 };
441
NON_EXPORTED_BASE(ZoneObject)442 class V8_EXPORT_PRIVATE JSHeapBroker : public NON_EXPORTED_BASE(ZoneObject) {
443 public:
444 JSHeapBroker(Isolate* isolate, Zone* zone);
445 void SerializeStandardObjects();
446
447 HeapObjectType HeapObjectTypeFromMap(Handle<Map> map) const {
448 AllowHandleDereference handle_dereference;
449 return HeapObjectTypeFromMap(*map);
450 }
451
452 Isolate* isolate() const { return isolate_; }
453 Zone* zone() const { return zone_; }
454
455 enum BrokerMode { kDisabled, kSerializing, kSerialized };
456 BrokerMode mode() const { return mode_; }
457 void StopSerializing() {
458 CHECK_EQ(mode_, kSerializing);
459 mode_ = kSerialized;
460 }
461 bool SerializingAllowed() const;
462
463 // Returns nullptr iff handle unknown.
464 ObjectData* GetData(Handle<Object>) const;
465 // Never returns nullptr.
466 ObjectData* GetOrCreateData(Handle<Object>);
467
468 void Trace(const char* format, ...) const;
469
470 private:
471 friend class HeapObjectRef;
472 friend class ObjectRef;
473 friend class ObjectData;
474
475 // TODO(neis): Remove eventually.
476 HeapObjectType HeapObjectTypeFromMap(Map* map) const;
477
478 void AddData(Handle<Object> object, ObjectData* data);
479
480 Isolate* const isolate_;
481 Zone* const zone_;
482 ZoneUnorderedMap<Address, ObjectData*> refs_;
483 BrokerMode mode_;
484 };
485
486 #define ASSIGN_RETURN_NO_CHANGE_IF_DATA_MISSING(something_var, \
487 optionally_something) \
488 auto optionally_something_ = optionally_something; \
489 if (!optionally_something_) \
490 return NoChangeBecauseOfMissingData(js_heap_broker(), __FUNCTION__, \
491 __LINE__); \
492 something_var = *optionally_something_;
493
494 class Reduction;
495 Reduction NoChangeBecauseOfMissingData(JSHeapBroker* broker,
496 const char* function, int line);
497
498 } // namespace compiler
499 } // namespace internal
500 } // namespace v8
501
502 #endif // V8_COMPILER_JS_HEAP_BROKER_H_
503