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 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 44 OddballType oddball_type() const { return oddball_type_; } 45 InstanceType instance_type() const { return instance_type_; } 46 Flags flags() const { return flags_; } 47 48 bool is_callable() const { return flags_ & kCallable; } 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; 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 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