Line data Source code
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 : #include "src/compiler/js-heap-broker.h"
6 :
7 : #ifdef ENABLE_SLOW_DCHECKS
8 : #include <algorithm>
9 : #endif
10 :
11 : #include "src/ast/modules.h"
12 : #include "src/bootstrapper.h"
13 : #include "src/boxed-float.h"
14 : #include "src/code-factory.h"
15 : #include "src/compiler/graph-reducer.h"
16 : #include "src/compiler/per-isolate-compiler-cache.h"
17 : #include "src/objects-inl.h"
18 : #include "src/objects/allocation-site-inl.h"
19 : #include "src/objects/cell-inl.h"
20 : #include "src/objects/heap-number-inl.h"
21 : #include "src/objects/instance-type-inl.h"
22 : #include "src/objects/js-array-buffer-inl.h"
23 : #include "src/objects/js-array-inl.h"
24 : #include "src/objects/js-regexp-inl.h"
25 : #include "src/objects/module-inl.h"
26 : #include "src/utils.h"
27 : #include "src/vector-slot-pair.h"
28 :
29 : namespace v8 {
30 : namespace internal {
31 : namespace compiler {
32 :
33 : #define TRACE(broker, x) TRACE_BROKER(broker, x)
34 :
35 : #define FORWARD_DECL(Name) class Name##Data;
36 : HEAP_BROKER_OBJECT_LIST(FORWARD_DECL)
37 : #undef FORWARD_DECL
38 :
39 : // There are three kinds of ObjectData values.
40 : //
41 : // kSmi: The underlying V8 object is a Smi and the data is an instance of the
42 : // base class (ObjectData), i.e. it's basically just the handle. Because the
43 : // object is a Smi, it's safe to access the handle in order to extract the
44 : // number value, and AsSmi() does exactly that.
45 : //
46 : // kSerializedHeapObject: The underlying V8 object is a HeapObject and the
47 : // data is an instance of the corresponding (most-specific) subclass, e.g.
48 : // JSFunctionData, which provides serialized information about the object.
49 : //
50 : // kUnserializedHeapObject: The underlying V8 object is a HeapObject and the
51 : // data is an instance of the base class (ObjectData), i.e. it basically
52 : // carries no information other than the handle.
53 : //
54 : enum ObjectDataKind { kSmi, kSerializedHeapObject, kUnserializedHeapObject };
55 :
56 : class ObjectData : public ZoneObject {
57 : public:
58 93469348 : ObjectData(JSHeapBroker* broker, ObjectData** storage, Handle<Object> object,
59 : ObjectDataKind kind)
60 93469348 : : object_(object), kind_(kind) {
61 : // This assignment ensures we don't end up inserting the same object
62 : // in an endless recursion.
63 93469348 : *storage = this;
64 :
65 93469348 : TRACE(broker, "Creating data " << this << " for handle " << object.address()
66 : << " (" << Brief(*object) << ")");
67 :
68 93469348 : CHECK_NOT_NULL(broker->isolate()->handle_scope_data()->canonical_scope);
69 93469348 : }
70 :
71 : #define DECLARE_IS_AND_AS(Name) \
72 : bool Is##Name() const; \
73 : Name##Data* As##Name();
74 : HEAP_BROKER_OBJECT_LIST(DECLARE_IS_AND_AS)
75 : #undef DECLARE_IS_AND_AS
76 :
77 : Handle<Object> object() const { return object_; }
78 : ObjectDataKind kind() const { return kind_; }
79 12048702 : bool is_smi() const { return kind_ == kSmi; }
80 :
81 : private:
82 : Handle<Object> const object_;
83 : ObjectDataKind const kind_;
84 : };
85 :
86 : class HeapObjectData : public ObjectData {
87 : public:
88 : HeapObjectData(JSHeapBroker* broker, ObjectData** storage,
89 : Handle<HeapObject> object);
90 :
91 : bool boolean_value() const { return boolean_value_; }
92 : MapData* map() const { return map_; }
93 :
94 : static HeapObjectData* Serialize(JSHeapBroker* broker,
95 : Handle<HeapObject> object);
96 :
97 : private:
98 : bool const boolean_value_;
99 : MapData* const map_;
100 : };
101 :
102 : class PropertyCellData : public HeapObjectData {
103 : public:
104 : PropertyCellData(JSHeapBroker* broker, ObjectData** storage,
105 : Handle<PropertyCell> object);
106 :
107 : PropertyDetails property_details() const { return property_details_; }
108 :
109 : void Serialize(JSHeapBroker* broker);
110 : ObjectData* value() { return value_; }
111 :
112 : private:
113 : PropertyDetails const property_details_;
114 :
115 : bool serialized_ = false;
116 : ObjectData* value_ = nullptr;
117 : };
118 :
119 29178764 : void JSHeapBroker::IncrementTracingIndentation() { ++trace_indentation_; }
120 :
121 29179008 : void JSHeapBroker::DecrementTracingIndentation() { --trace_indentation_; }
122 :
123 : class TraceScope {
124 : public:
125 : TraceScope(JSHeapBroker* broker, const char* label)
126 478555 : : TraceScope(broker, static_cast<void*>(broker), label) {}
127 :
128 : TraceScope(JSHeapBroker* broker, ObjectData* data, const char* label)
129 28700454 : : TraceScope(broker, static_cast<void*>(data), label) {}
130 :
131 58356781 : ~TraceScope() { broker_->DecrementTracingIndentation(); }
132 :
133 : private:
134 : JSHeapBroker* const broker_;
135 :
136 29178764 : TraceScope(JSHeapBroker* broker, void* self, const char* label)
137 29178764 : : broker_(broker) {
138 29178764 : TRACE(broker_, "Running " << label << " on " << self << ".");
139 29178764 : broker_->IncrementTracingIndentation();
140 29178764 : }
141 : };
142 :
143 3257607 : PropertyCellData::PropertyCellData(JSHeapBroker* broker, ObjectData** storage,
144 : Handle<PropertyCell> object)
145 : : HeapObjectData(broker, storage, object),
146 6515214 : property_details_(object->property_details()) {}
147 :
148 3247126 : void PropertyCellData::Serialize(JSHeapBroker* broker) {
149 3247126 : if (serialized_) return;
150 3247126 : serialized_ = true;
151 :
152 3247126 : TraceScope tracer(broker, this, "PropertyCellData::Serialize");
153 : auto cell = Handle<PropertyCell>::cast(object());
154 : DCHECK_NULL(value_);
155 3247134 : value_ = broker->GetOrCreateData(cell->value());
156 : }
157 :
158 : class JSObjectField {
159 : public:
160 : bool IsDouble() const { return object_ == nullptr; }
161 : double AsDouble() const {
162 0 : CHECK(IsDouble());
163 0 : return number_;
164 : }
165 :
166 : bool IsObject() const { return object_ != nullptr; }
167 : ObjectData* AsObject() const {
168 3274 : CHECK(IsObject());
169 : return object_;
170 : }
171 :
172 : explicit JSObjectField(double value) : number_(value) {}
173 2810 : explicit JSObjectField(ObjectData* value) : object_(value) {}
174 :
175 : private:
176 : ObjectData* object_ = nullptr;
177 : double number_ = 0;
178 : };
179 :
180 : class JSObjectData : public HeapObjectData {
181 : public:
182 : JSObjectData(JSHeapBroker* broker, ObjectData** storage,
183 : Handle<JSObject> object);
184 :
185 : // Recursively serializes all reachable JSObjects.
186 : void SerializeAsBoilerplate(JSHeapBroker* broker);
187 : // Shallow serialization of {elements}.
188 : void SerializeElements(JSHeapBroker* broker);
189 :
190 : const JSObjectField& GetInobjectField(int property_index) const;
191 : FixedArrayBaseData* elements() const;
192 :
193 : // This method is only used to assert our invariants.
194 : bool cow_or_empty_elements_tenured() const;
195 :
196 : void SerializeObjectCreateMap(JSHeapBroker* broker);
197 : MapData* object_create_map() const { // Can be nullptr.
198 16 : CHECK(serialized_object_create_map_);
199 16 : return object_create_map_;
200 : }
201 :
202 : private:
203 : void SerializeRecursive(JSHeapBroker* broker, int max_depths);
204 :
205 : FixedArrayBaseData* elements_ = nullptr;
206 : bool cow_or_empty_elements_tenured_ = false;
207 : // The {serialized_as_boilerplate} flag is set when all recursively
208 : // reachable JSObjects are serialized.
209 : bool serialized_as_boilerplate_ = false;
210 : bool serialized_elements_ = false;
211 :
212 : ZoneVector<JSObjectField> inobject_fields_;
213 :
214 : bool serialized_object_create_map_ = false;
215 : MapData* object_create_map_ = nullptr;
216 : };
217 :
218 1138302 : void JSObjectData::SerializeObjectCreateMap(JSHeapBroker* broker) {
219 1652956 : if (serialized_object_create_map_) return;
220 623648 : serialized_object_create_map_ = true;
221 :
222 623648 : TraceScope tracer(broker, this, "JSObjectData::SerializeObjectCreateMap");
223 : Handle<JSObject> jsobject = Handle<JSObject>::cast(object());
224 :
225 623647 : if (jsobject->map()->is_prototype_map()) {
226 : Handle<Object> maybe_proto_info(jsobject->map()->prototype_info(),
227 : broker->isolate());
228 20900 : if (maybe_proto_info->IsPrototypeInfo()) {
229 : auto proto_info = Handle<PrototypeInfo>::cast(maybe_proto_info);
230 14611 : if (proto_info->HasObjectCreateMap()) {
231 : DCHECK_NULL(object_create_map_);
232 : object_create_map_ =
233 50 : broker->GetOrCreateData(proto_info->ObjectCreateMap())->AsMap();
234 : }
235 : }
236 : }
237 : }
238 :
239 : class JSTypedArrayData : public JSObjectData {
240 : public:
241 : JSTypedArrayData(JSHeapBroker* broker, ObjectData** storage,
242 : Handle<JSTypedArray> object);
243 :
244 : bool is_on_heap() const { return is_on_heap_; }
245 : size_t length_value() const { return length_value_; }
246 : void* elements_external_pointer() const { return elements_external_pointer_; }
247 :
248 : void Serialize(JSHeapBroker* broker);
249 : bool serialized() const { return serialized_; }
250 :
251 : HeapObjectData* buffer() const { return buffer_; }
252 :
253 : private:
254 : bool const is_on_heap_;
255 : size_t const length_value_;
256 : void* const elements_external_pointer_;
257 :
258 : bool serialized_ = false;
259 : HeapObjectData* buffer_ = nullptr;
260 : };
261 :
262 787 : JSTypedArrayData::JSTypedArrayData(JSHeapBroker* broker, ObjectData** storage,
263 : Handle<JSTypedArray> object)
264 : : JSObjectData(broker, storage, object),
265 1574 : is_on_heap_(object->is_on_heap()),
266 : length_value_(object->length_value()),
267 : elements_external_pointer_(
268 2361 : FixedTypedArrayBase::cast(object->elements())->external_pointer()) {}
269 :
270 0 : void JSTypedArrayData::Serialize(JSHeapBroker* broker) {
271 0 : if (serialized_) return;
272 0 : serialized_ = true;
273 :
274 0 : TraceScope tracer(broker, this, "JSTypedArrayData::Serialize");
275 : Handle<JSTypedArray> typed_array = Handle<JSTypedArray>::cast(object());
276 :
277 0 : if (!is_on_heap()) {
278 : DCHECK_NULL(buffer_);
279 0 : buffer_ = broker->GetOrCreateData(typed_array->buffer())->AsHeapObject();
280 : }
281 : }
282 :
283 : class JSDataViewData : public JSObjectData {
284 : public:
285 : JSDataViewData(JSHeapBroker* broker, ObjectData** storage,
286 : Handle<JSDataView> object);
287 :
288 : size_t byte_length() const { return byte_length_; }
289 : size_t byte_offset() const { return byte_offset_; }
290 :
291 : private:
292 : size_t const byte_length_;
293 : size_t const byte_offset_;
294 : };
295 :
296 : class JSBoundFunctionData : public JSObjectData {
297 : public:
298 : JSBoundFunctionData(JSHeapBroker* broker, ObjectData** storage,
299 : Handle<JSBoundFunction> object);
300 :
301 : void Serialize(JSHeapBroker* broker);
302 :
303 : ObjectData* bound_target_function() const { return bound_target_function_; }
304 : ObjectData* bound_this() const { return bound_this_; }
305 : FixedArrayData* bound_arguments() const { return bound_arguments_; }
306 :
307 : private:
308 : bool serialized_ = false;
309 :
310 : ObjectData* bound_target_function_ = nullptr;
311 : ObjectData* bound_this_ = nullptr;
312 : FixedArrayData* bound_arguments_ = nullptr;
313 : };
314 :
315 : class JSFunctionData : public JSObjectData {
316 : public:
317 : JSFunctionData(JSHeapBroker* broker, ObjectData** storage,
318 : Handle<JSFunction> object);
319 :
320 : bool has_feedback_vector() const { return has_feedback_vector_; }
321 : bool has_initial_map() const { return has_initial_map_; }
322 : bool has_prototype() const { return has_prototype_; }
323 : bool PrototypeRequiresRuntimeLookup() const {
324 : return PrototypeRequiresRuntimeLookup_;
325 : }
326 :
327 : void Serialize(JSHeapBroker* broker);
328 :
329 : ContextData* context() const { return context_; }
330 : NativeContextData* native_context() const { return native_context_; }
331 : MapData* initial_map() const { return initial_map_; }
332 : ObjectData* prototype() const { return prototype_; }
333 : SharedFunctionInfoData* shared() const { return shared_; }
334 : FeedbackVectorData* feedback_vector() const { return feedback_vector_; }
335 : int initial_map_instance_size_with_min_slack() const {
336 5057 : CHECK(serialized_);
337 5057 : return initial_map_instance_size_with_min_slack_;
338 : }
339 :
340 : private:
341 : bool has_feedback_vector_;
342 : bool has_initial_map_;
343 : bool has_prototype_;
344 : bool PrototypeRequiresRuntimeLookup_;
345 :
346 : bool serialized_ = false;
347 :
348 : ContextData* context_ = nullptr;
349 : NativeContextData* native_context_ = nullptr;
350 : MapData* initial_map_ = nullptr;
351 : ObjectData* prototype_ = nullptr;
352 : SharedFunctionInfoData* shared_ = nullptr;
353 : FeedbackVectorData* feedback_vector_ = nullptr;
354 : int initial_map_instance_size_with_min_slack_;
355 : };
356 :
357 : class JSRegExpData : public JSObjectData {
358 : public:
359 647 : JSRegExpData(JSHeapBroker* broker, ObjectData** storage,
360 : Handle<JSRegExp> object)
361 647 : : JSObjectData(broker, storage, object) {}
362 :
363 : void SerializeAsRegExpBoilerplate(JSHeapBroker* broker);
364 :
365 : ObjectData* raw_properties_or_hash() const { return raw_properties_or_hash_; }
366 : ObjectData* data() const { return data_; }
367 : ObjectData* source() const { return source_; }
368 : ObjectData* flags() const { return flags_; }
369 : ObjectData* last_index() const { return last_index_; }
370 :
371 : private:
372 : bool serialized_as_reg_exp_boilerplate_ = false;
373 :
374 : ObjectData* raw_properties_or_hash_ = nullptr;
375 : ObjectData* data_ = nullptr;
376 : ObjectData* source_ = nullptr;
377 : ObjectData* flags_ = nullptr;
378 : ObjectData* last_index_ = nullptr;
379 : };
380 :
381 : class HeapNumberData : public HeapObjectData {
382 : public:
383 464003 : HeapNumberData(JSHeapBroker* broker, ObjectData** storage,
384 : Handle<HeapNumber> object)
385 928004 : : HeapObjectData(broker, storage, object), value_(object->value()) {}
386 :
387 : double value() const { return value_; }
388 :
389 : private:
390 : double const value_;
391 : };
392 :
393 : class MutableHeapNumberData : public HeapObjectData {
394 : public:
395 128 : MutableHeapNumberData(JSHeapBroker* broker, ObjectData** storage,
396 : Handle<MutableHeapNumber> object)
397 256 : : HeapObjectData(broker, storage, object), value_(object->value()) {}
398 :
399 : double value() const { return value_; }
400 :
401 : private:
402 : double const value_;
403 : };
404 :
405 : class ContextData : public HeapObjectData {
406 : public:
407 : ContextData(JSHeapBroker* broker, ObjectData** storage,
408 : Handle<Context> object);
409 : void SerializeContextChain(JSHeapBroker* broker);
410 :
411 : ContextData* previous() const {
412 0 : CHECK(serialized_context_chain_);
413 0 : return previous_;
414 : }
415 :
416 : void SerializeSlot(JSHeapBroker* broker, int index);
417 :
418 16 : ObjectData* GetSlot(int index) {
419 : auto search = slots_.find(index);
420 16 : CHECK(search != slots_.end());
421 16 : return search->second;
422 : }
423 :
424 : private:
425 : ZoneMap<int, ObjectData*> slots_;
426 : bool serialized_context_chain_ = false;
427 : ContextData* previous_ = nullptr;
428 : };
429 :
430 191622 : ContextData::ContextData(JSHeapBroker* broker, ObjectData** storage,
431 : Handle<Context> object)
432 1310999 : : HeapObjectData(broker, storage, object), slots_(broker->zone()) {}
433 :
434 1174840 : void ContextData::SerializeContextChain(JSHeapBroker* broker) {
435 1792516 : if (serialized_context_chain_) return;
436 557164 : serialized_context_chain_ = true;
437 :
438 557164 : TraceScope tracer(broker, this, "ContextData::SerializeContextChain");
439 : Handle<Context> context = Handle<Context>::cast(object());
440 :
441 : DCHECK_NULL(previous_);
442 : // Context::previous DCHECK-fails when called on the native context.
443 557170 : if (!context->IsNativeContext()) {
444 93296 : previous_ = broker->GetOrCreateData(context->previous())->AsContext();
445 93296 : previous_->SerializeContextChain(broker);
446 : }
447 : }
448 :
449 16 : void ContextData::SerializeSlot(JSHeapBroker* broker, int index) {
450 16 : TraceScope tracer(broker, this, "ContextData::SerializeSlot");
451 16 : TRACE(broker, "Serializing script context slot " << index << ".");
452 : Handle<Context> context = Handle<Context>::cast(object());
453 32 : CHECK(index >= 0 && index < context->length());
454 16 : ObjectData* odata = broker->GetOrCreateData(context->get(index));
455 32 : slots_.insert(std::make_pair(index, odata));
456 16 : }
457 :
458 : class NativeContextData : public ContextData {
459 : public:
460 : #define DECL_ACCESSOR(type, name) \
461 : type##Data* name() const { return name##_; }
462 : BROKER_NATIVE_CONTEXT_FIELDS(DECL_ACCESSOR)
463 : #undef DECL_ACCESSOR
464 :
465 : const ZoneVector<MapData*>& function_maps() const {
466 31995 : CHECK(serialized_);
467 : return function_maps_;
468 : }
469 :
470 : NativeContextData(JSHeapBroker* broker, ObjectData** storage,
471 : Handle<NativeContext> object);
472 : void Serialize(JSHeapBroker* broker);
473 :
474 : private:
475 : bool serialized_ = false;
476 : #define DECL_MEMBER(type, name) type##Data* name##_ = nullptr;
477 : BROKER_NATIVE_CONTEXT_FIELDS(DECL_MEMBER)
478 : #undef DECL_MEMBER
479 : ZoneVector<MapData*> function_maps_;
480 : };
481 :
482 : class NameData : public HeapObjectData {
483 : public:
484 0 : NameData(JSHeapBroker* broker, ObjectData** storage, Handle<Name> object)
485 7654305 : : HeapObjectData(broker, storage, object) {}
486 : };
487 :
488 : class StringData : public NameData {
489 : public:
490 : StringData(JSHeapBroker* broker, ObjectData** storage, Handle<String> object);
491 :
492 : int length() const { return length_; }
493 : uint16_t first_char() const { return first_char_; }
494 841 : base::Optional<double> to_number() const { return to_number_; }
495 : bool is_external_string() const { return is_external_string_; }
496 : bool is_seq_string() const { return is_seq_string_; }
497 :
498 : private:
499 : int const length_;
500 : uint16_t const first_char_;
501 : base::Optional<double> to_number_;
502 : bool const is_external_string_;
503 : bool const is_seq_string_;
504 :
505 : static constexpr int kMaxLengthForDoubleConversion = 23;
506 : };
507 :
508 : class SymbolData : public NameData {
509 : public:
510 36558 : SymbolData(JSHeapBroker* broker, ObjectData** storage, Handle<Symbol> object)
511 36558 : : NameData(broker, storage, object) {}
512 : };
513 :
514 7617747 : StringData::StringData(JSHeapBroker* broker, ObjectData** storage,
515 : Handle<String> object)
516 : : NameData(broker, storage, object),
517 : length_(object->length()),
518 : first_char_(length_ > 0 ? object->Get(0) : 0),
519 : is_external_string_(object->IsExternalString()),
520 30470933 : is_seq_string_(object->IsSeqString()) {
521 : int flags = ALLOW_HEX | ALLOW_OCTAL | ALLOW_BINARY;
522 7617732 : if (length_ <= kMaxLengthForDoubleConversion) {
523 7570080 : to_number_ = StringToDouble(broker->isolate(), object, flags);
524 : }
525 7617773 : }
526 :
527 : class InternalizedStringData : public StringData {
528 : public:
529 : InternalizedStringData(JSHeapBroker* broker, ObjectData** storage,
530 : Handle<InternalizedString> object);
531 :
532 : uint32_t array_index() const { return array_index_; }
533 :
534 : private:
535 : uint32_t array_index_;
536 : };
537 :
538 7617413 : InternalizedStringData::InternalizedStringData(
539 : JSHeapBroker* broker, ObjectData** storage,
540 : Handle<InternalizedString> object)
541 7617413 : : StringData(broker, storage, object) {
542 15234838 : if (!object->AsArrayIndex(&array_index_)) {
543 7150885 : array_index_ = InternalizedStringRef::kNotAnArrayIndex;
544 : }
545 7617419 : }
546 :
547 : namespace {
548 :
549 6672 : bool IsFastLiteralHelper(Handle<JSObject> boilerplate, int max_depth,
550 : int* max_properties) {
551 : DCHECK_GE(max_depth, 0);
552 : DCHECK_GE(*max_properties, 0);
553 :
554 : // Make sure the boilerplate map is not deprecated.
555 6672 : if (!JSObject::TryMigrateInstance(boilerplate)) return false;
556 :
557 : // Check for too deep nesting.
558 6672 : if (max_depth == 0) return false;
559 :
560 : // Check the elements.
561 : Isolate* const isolate = boilerplate->GetIsolate();
562 : Handle<FixedArrayBase> elements(boilerplate->elements(), isolate);
563 10943 : if (elements->length() > 0 &&
564 : elements->map() != ReadOnlyRoots(isolate).fixed_cow_array_map()) {
565 4430 : if (boilerplate->HasSmiOrObjectElements()) {
566 : Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
567 : int length = elements->length();
568 22319 : for (int i = 0; i < length; i++) {
569 10364 : if ((*max_properties)-- == 0) return false;
570 : Handle<Object> value(fast_elements->get(i), isolate);
571 10350 : if (value->IsJSObject()) {
572 465 : Handle<JSObject> value_object = Handle<JSObject>::cast(value);
573 465 : if (!IsFastLiteralHelper(value_object, max_depth - 1,
574 : max_properties)) {
575 0 : return false;
576 : }
577 : }
578 : }
579 1192 : } else if (boilerplate->HasDoubleElements()) {
580 560 : if (elements->Size() > kMaxRegularHeapObjectSize) return false;
581 : } else {
582 : return false;
583 : }
584 : }
585 :
586 : // TODO(turbofan): Do we want to support out-of-object properties?
587 13230 : if (!(boilerplate->HasFastProperties() &&
588 19681 : boilerplate->property_array()->length() == 0)) {
589 : return false;
590 : }
591 :
592 : // Check the in-object properties.
593 : Handle<DescriptorArray> descriptors(
594 : boilerplate->map()->instance_descriptors(), isolate);
595 : int limit = boilerplate->map()->NumberOfOwnDescriptors();
596 20637 : for (int i = 0; i < limit; i++) {
597 7059 : PropertyDetails details = descriptors->GetDetails(i);
598 11301 : if (details.location() != kField) continue;
599 : DCHECK_EQ(kData, details.kind());
600 2824 : if ((*max_properties)-- == 0) return false;
601 2817 : FieldIndex field_index = FieldIndex::ForDescriptor(boilerplate->map(), i);
602 : if (boilerplate->IsUnboxedDoubleField(field_index)) continue;
603 5634 : Handle<Object> value(boilerplate->RawFastPropertyAt(field_index), isolate);
604 2817 : if (value->IsJSObject()) {
605 293 : Handle<JSObject> value_object = Handle<JSObject>::cast(value);
606 293 : if (!IsFastLiteralHelper(value_object, max_depth - 1, max_properties)) {
607 7 : return false;
608 : }
609 : }
610 : }
611 : return true;
612 : }
613 :
614 : // Maximum depth and total number of elements and properties for literal
615 : // graphs to be considered for fast deep-copying. The limit is chosen to
616 : // match the maximum number of inobject properties, to ensure that the
617 : // performance of using object literals is not worse than using constructor
618 : // functions, see crbug.com/v8/6211 for details.
619 : const int kMaxFastLiteralDepth = 3;
620 : const int kMaxFastLiteralProperties = JSObject::kMaxInObjectProperties;
621 :
622 : // Determines whether the given array or object literal boilerplate satisfies
623 : // all limits to be considered for fast deep-copying and computes the total
624 : // size of all objects that are part of the graph.
625 : bool IsInlinableFastLiteral(Handle<JSObject> boilerplate) {
626 5914 : int max_properties = kMaxFastLiteralProperties;
627 : return IsFastLiteralHelper(boilerplate, kMaxFastLiteralDepth,
628 5914 : &max_properties);
629 : }
630 :
631 : } // namespace
632 :
633 : class AllocationSiteData : public HeapObjectData {
634 : public:
635 : AllocationSiteData(JSHeapBroker* broker, ObjectData** storage,
636 : Handle<AllocationSite> object);
637 : void SerializeBoilerplate(JSHeapBroker* broker);
638 :
639 : bool PointsToLiteral() const { return PointsToLiteral_; }
640 : AllocationType GetAllocationType() const { return GetAllocationType_; }
641 : ObjectData* nested_site() const { return nested_site_; }
642 : bool IsFastLiteral() const { return IsFastLiteral_; }
643 : JSObjectData* boilerplate() const { return boilerplate_; }
644 :
645 : // These are only valid if PointsToLiteral is false.
646 : ElementsKind GetElementsKind() const { return GetElementsKind_; }
647 : bool CanInlineCall() const { return CanInlineCall_; }
648 :
649 : private:
650 : bool const PointsToLiteral_;
651 : AllocationType const GetAllocationType_;
652 : ObjectData* nested_site_ = nullptr;
653 : bool IsFastLiteral_ = false;
654 : JSObjectData* boilerplate_ = nullptr;
655 : ElementsKind GetElementsKind_ = NO_ELEMENTS;
656 : bool CanInlineCall_ = false;
657 : bool serialized_boilerplate_ = false;
658 : };
659 :
660 : // Only used in JSNativeContextSpecialization.
661 : class ScriptContextTableData : public HeapObjectData {
662 : public:
663 463875 : ScriptContextTableData(JSHeapBroker* broker, ObjectData** storage,
664 : Handle<ScriptContextTable> object)
665 463875 : : HeapObjectData(broker, storage, object) {}
666 : };
667 :
668 8190 : struct PropertyDescriptor {
669 : NameData* key = nullptr;
670 : PropertyDetails details = PropertyDetails::Empty();
671 : FieldIndex field_index;
672 : MapData* field_owner = nullptr;
673 : ObjectData* field_type = nullptr;
674 : bool is_unboxed_double_field = false;
675 : };
676 :
677 : class MapData : public HeapObjectData {
678 : public:
679 : MapData(JSHeapBroker* broker, ObjectData** storage, Handle<Map> object);
680 :
681 : InstanceType instance_type() const { return instance_type_; }
682 : int instance_size() const { return instance_size_; }
683 : byte bit_field() const { return bit_field_; }
684 : byte bit_field2() const { return bit_field2_; }
685 : uint32_t bit_field3() const { return bit_field3_; }
686 : bool can_be_deprecated() const { return can_be_deprecated_; }
687 : bool can_transition() const { return can_transition_; }
688 : int in_object_properties_start_in_words() const {
689 38821 : CHECK(InstanceTypeChecker::IsJSObject(instance_type()));
690 38821 : return in_object_properties_start_in_words_;
691 : }
692 : int in_object_properties() const {
693 74892 : CHECK(InstanceTypeChecker::IsJSObject(instance_type()));
694 74892 : return in_object_properties_;
695 : }
696 : int constructor_function_index() const { return constructor_function_index_; }
697 : int NextFreePropertyIndex() const { return next_free_property_index_; }
698 : int UnusedPropertyFields() const { return unused_property_fields_; }
699 : bool supports_fast_array_iteration() const {
700 : return supports_fast_array_iteration_;
701 : }
702 : bool supports_fast_array_resize() const {
703 : return supports_fast_array_resize_;
704 : }
705 :
706 : // Extra information.
707 :
708 : void SerializeElementsKindGeneralizations(JSHeapBroker* broker);
709 : const ZoneVector<MapData*>& elements_kind_generalizations() const {
710 846 : CHECK(serialized_elements_kind_generalizations_);
711 : return elements_kind_generalizations_;
712 : }
713 :
714 : // Serialize the own part of the descriptor array and, recursively, that of
715 : // any field owner.
716 : void SerializeOwnDescriptors(JSHeapBroker* broker);
717 : DescriptorArrayData* instance_descriptors() const {
718 17147 : CHECK(serialized_own_descriptors_);
719 17147 : return instance_descriptors_;
720 : }
721 :
722 : void SerializeConstructor(JSHeapBroker* broker);
723 : ObjectData* GetConstructor() const {
724 4542 : CHECK(serialized_constructor_);
725 4542 : return constructor_;
726 : }
727 :
728 : void SerializePrototype(JSHeapBroker* broker);
729 : ObjectData* prototype() const {
730 40 : CHECK(serialized_prototype_);
731 40 : return prototype_;
732 : }
733 :
734 : void SerializeForElementLoad(JSHeapBroker* broker);
735 :
736 : void SerializeForElementStore(JSHeapBroker* broker);
737 :
738 : private:
739 : InstanceType const instance_type_;
740 : int const instance_size_;
741 : byte const bit_field_;
742 : byte const bit_field2_;
743 : uint32_t const bit_field3_;
744 : bool const can_be_deprecated_;
745 : bool const can_transition_;
746 : int const in_object_properties_start_in_words_;
747 : int const in_object_properties_;
748 : int const constructor_function_index_;
749 : int const next_free_property_index_;
750 : int const unused_property_fields_;
751 : bool const supports_fast_array_iteration_;
752 : bool const supports_fast_array_resize_;
753 :
754 : bool serialized_elements_kind_generalizations_ = false;
755 : ZoneVector<MapData*> elements_kind_generalizations_;
756 :
757 : bool serialized_own_descriptors_ = false;
758 : DescriptorArrayData* instance_descriptors_ = nullptr;
759 :
760 : bool serialized_constructor_ = false;
761 : ObjectData* constructor_ = nullptr;
762 :
763 : bool serialized_prototype_ = false;
764 : ObjectData* prototype_ = nullptr;
765 :
766 : bool serialized_for_element_load_ = false;
767 :
768 : bool serialized_for_element_store_ = false;
769 : };
770 :
771 7363 : AllocationSiteData::AllocationSiteData(JSHeapBroker* broker,
772 : ObjectData** storage,
773 : Handle<AllocationSite> object)
774 : : HeapObjectData(broker, storage, object),
775 : PointsToLiteral_(object->PointsToLiteral()),
776 22089 : GetAllocationType_(object->GetAllocationType()) {
777 7363 : if (PointsToLiteral_) {
778 : IsFastLiteral_ = IsInlinableFastLiteral(
779 5914 : handle(object->boilerplate(), broker->isolate()));
780 : } else {
781 1449 : GetElementsKind_ = object->GetElementsKind();
782 1449 : CanInlineCall_ = object->CanInlineCall();
783 : }
784 7363 : }
785 :
786 5775 : void AllocationSiteData::SerializeBoilerplate(JSHeapBroker* broker) {
787 5775 : if (serialized_boilerplate_) return;
788 5775 : serialized_boilerplate_ = true;
789 :
790 5775 : TraceScope tracer(broker, this, "AllocationSiteData::SerializeBoilerplate");
791 : Handle<AllocationSite> site = Handle<AllocationSite>::cast(object());
792 :
793 5775 : CHECK(IsFastLiteral_);
794 : DCHECK_NULL(boilerplate_);
795 5775 : boilerplate_ = broker->GetOrCreateData(site->boilerplate())->AsJSObject();
796 : boilerplate_->SerializeAsBoilerplate(broker);
797 :
798 : DCHECK_NULL(nested_site_);
799 5775 : nested_site_ = broker->GetOrCreateData(site->nested_site());
800 5775 : if (nested_site_->IsAllocationSite()) {
801 248 : nested_site_->AsAllocationSite()->SerializeBoilerplate(broker);
802 : }
803 : }
804 :
805 91540406 : HeapObjectData::HeapObjectData(JSHeapBroker* broker, ObjectData** storage,
806 : Handle<HeapObject> object)
807 : : ObjectData(broker, storage, object, kSerializedHeapObject),
808 183078964 : boolean_value_(object->BooleanValue(broker->isolate())),
809 : // We have to use a raw cast below instead of AsMap() because of
810 : // recursion. AsMap() would call IsMap(), which accesses the
811 : // instance_type_ member. In the case of constructing the MapData for the
812 : // meta map (whose map is itself), this member has not yet been
813 : // initialized.
814 274618684 : map_(static_cast<MapData*>(broker->GetOrCreateData(object->map()))) {
815 91539272 : CHECK(broker->SerializingAllowed());
816 91539272 : }
817 :
818 : namespace {
819 2761748 : bool IsReadOnlyLengthDescriptor(Isolate* isolate, Handle<Map> jsarray_map) {
820 : DCHECK(!jsarray_map->is_dictionary_map());
821 : Handle<Name> length_string = isolate->factory()->length_string();
822 2761748 : DescriptorArray descriptors = jsarray_map->instance_descriptors();
823 : int number = descriptors->Search(*length_string, *jsarray_map);
824 : DCHECK_NE(DescriptorArray::kNotFound, number);
825 5523501 : return descriptors->GetDetails(number).IsReadOnly();
826 : }
827 :
828 96292780 : bool SupportsFastArrayIteration(Isolate* isolate, Handle<Map> map) {
829 6507115 : return map->instance_type() == JS_ARRAY_TYPE &&
830 6504992 : IsFastElementsKind(map->elements_kind()) &&
831 5575936 : map->prototype()->IsJSArray() &&
832 5575939 : isolate->IsAnyInitialArrayPrototype(
833 101868350 : handle(JSArray::cast(map->prototype()), isolate)) &&
834 101868363 : isolate->IsNoElementsProtectorIntact();
835 : }
836 :
837 48146487 : bool SupportsFastArrayResize(Isolate* isolate, Handle<Map> map) {
838 53669993 : return SupportsFastArrayIteration(isolate, map) && map->is_extensible() &&
839 50908095 : !map->is_dictionary_map() && !IsReadOnlyLengthDescriptor(isolate, map);
840 : }
841 : } // namespace
842 :
843 48143569 : MapData::MapData(JSHeapBroker* broker, ObjectData** storage, Handle<Map> object)
844 : : HeapObjectData(broker, storage, object),
845 : instance_type_(object->instance_type()),
846 : instance_size_(object->instance_size()),
847 : bit_field_(object->bit_field()),
848 : bit_field2_(object->bit_field2()),
849 : bit_field3_(object->bit_field3()),
850 : can_be_deprecated_(object->NumberOfOwnDescriptors() > 0
851 73299355 : ? object->CanBeDeprecated()
852 : : false),
853 : can_transition_(object->CanTransition()),
854 : in_object_properties_start_in_words_(
855 : object->IsJSObjectMap() ? object->GetInObjectPropertiesStartInWords()
856 : : 0),
857 : in_object_properties_(
858 80740285 : object->IsJSObjectMap() ? object->GetInObjectProperties() : 0),
859 : constructor_function_index_(object->IsPrimitiveMap()
860 : ? object->GetConstructorFunctionIndex()
861 : : Map::kNoConstructorFunctionIndex),
862 96286436 : next_free_property_index_(object->NextFreePropertyIndex()),
863 96286252 : unused_property_fields_(object->UnusedPropertyFields()),
864 : supports_fast_array_iteration_(
865 48143128 : SupportsFastArrayIteration(broker->isolate(), object)),
866 : supports_fast_array_resize_(
867 48143075 : SupportsFastArrayResize(broker->isolate(), object)),
868 924329153 : elements_kind_generalizations_(broker->zone()) {}
869 :
870 7495124 : JSFunctionData::JSFunctionData(JSHeapBroker* broker, ObjectData** storage,
871 : Handle<JSFunction> object)
872 : : JSObjectData(broker, storage, object),
873 14990206 : has_feedback_vector_(object->has_feedback_vector()),
874 21448058 : has_initial_map_(object->has_prototype_slot() &&
875 13952937 : object->has_initial_map()),
876 21448030 : has_prototype_(object->has_prototype_slot() && object->has_prototype()),
877 : PrototypeRequiresRuntimeLookup_(
878 29980428 : object->PrototypeRequiresRuntimeLookup()) {}
879 :
880 5204157 : void JSFunctionData::Serialize(JSHeapBroker* broker) {
881 5694101 : if (serialized_) return;
882 4714213 : serialized_ = true;
883 :
884 4714213 : TraceScope tracer(broker, this, "JSFunctionData::Serialize");
885 : Handle<JSFunction> function = Handle<JSFunction>::cast(object());
886 :
887 : DCHECK_NULL(context_);
888 : DCHECK_NULL(native_context_);
889 : DCHECK_NULL(initial_map_);
890 : DCHECK_NULL(prototype_);
891 : DCHECK_NULL(shared_);
892 : DCHECK_NULL(feedback_vector_);
893 :
894 4714212 : context_ = broker->GetOrCreateData(function->context())->AsContext();
895 : native_context_ =
896 4714204 : broker->GetOrCreateData(function->native_context())->AsNativeContext();
897 4714202 : shared_ = broker->GetOrCreateData(function->shared())->AsSharedFunctionInfo();
898 : feedback_vector_ = has_feedback_vector()
899 5651706 : ? broker->GetOrCreateData(function->feedback_vector())
900 468746 : ->AsFeedbackVector()
901 9428410 : : nullptr;
902 : initial_map_ = has_initial_map()
903 3721674 : ? broker->GetOrCreateData(function->initial_map())->AsMap()
904 8435871 : : nullptr;
905 12163539 : prototype_ = has_prototype() ? broker->GetOrCreateData(function->prototype())
906 9428432 : : nullptr;
907 :
908 4714224 : if (initial_map_ != nullptr) {
909 : initial_map_instance_size_with_min_slack_ =
910 3721683 : function->ComputeInstanceSizeWithMinSlack(broker->isolate());
911 3721682 : if (initial_map_->instance_type() == JS_ARRAY_TYPE) {
912 464027 : initial_map_->SerializeElementsKindGeneralizations(broker);
913 : }
914 3721685 : initial_map_->SerializeConstructor(broker);
915 : // TODO(neis): This is currently only needed for native_context's
916 : // object_function, as used by GetObjectCreateMap. If no further use sites
917 : // show up, we should move this into NativeContextData::Serialize.
918 3721669 : initial_map_->SerializePrototype(broker);
919 : }
920 : }
921 :
922 464025 : void MapData::SerializeElementsKindGeneralizations(JSHeapBroker* broker) {
923 464025 : if (serialized_elements_kind_generalizations_) return;
924 464025 : serialized_elements_kind_generalizations_ = true;
925 :
926 : TraceScope tracer(broker, this,
927 464025 : "MapData::SerializeElementsKindGeneralizations");
928 : DCHECK_EQ(instance_type(), JS_ARRAY_TYPE);
929 : MapRef self(broker, this);
930 464026 : ElementsKind from_kind = self.elements_kind();
931 : DCHECK(elements_kind_generalizations_.empty());
932 6032348 : for (int i = FIRST_FAST_ELEMENTS_KIND; i <= LAST_FAST_ELEMENTS_KIND; i++) {
933 : ElementsKind to_kind = static_cast<ElementsKind>(i);
934 2784161 : if (IsMoreGeneralElementsKindTransition(from_kind, to_kind)) {
935 : Handle<Map> target =
936 2320137 : Map::AsElementsKind(broker->isolate(), self.object(), to_kind);
937 4640249 : elements_kind_generalizations_.push_back(
938 4640277 : broker->GetOrCreateData(target)->AsMap());
939 : }
940 : }
941 : }
942 :
943 : class DescriptorArrayData : public HeapObjectData {
944 : public:
945 3631 : DescriptorArrayData(JSHeapBroker* broker, ObjectData** storage,
946 : Handle<DescriptorArray> object)
947 7262 : : HeapObjectData(broker, storage, object), contents_(broker->zone()) {}
948 :
949 : ZoneVector<PropertyDescriptor>& contents() { return contents_; }
950 :
951 : private:
952 : ZoneVector<PropertyDescriptor> contents_;
953 : };
954 :
955 : class FeedbackVectorData : public HeapObjectData {
956 : public:
957 : const ZoneVector<ObjectData*>& feedback() { return feedback_; }
958 :
959 : FeedbackVectorData(JSHeapBroker* broker, ObjectData** storage,
960 : Handle<FeedbackVector> object);
961 :
962 : void SerializeSlots(JSHeapBroker* broker);
963 :
964 : private:
965 : bool serialized_ = false;
966 : ZoneVector<ObjectData*> feedback_;
967 : };
968 :
969 469306 : FeedbackVectorData::FeedbackVectorData(JSHeapBroker* broker,
970 : ObjectData** storage,
971 : Handle<FeedbackVector> object)
972 938601 : : HeapObjectData(broker, storage, object), feedback_(broker->zone()) {}
973 :
974 52495 : void FeedbackVectorData::SerializeSlots(JSHeapBroker* broker) {
975 70661 : if (serialized_) return;
976 34329 : serialized_ = true;
977 :
978 34329 : TraceScope tracer(broker, this, "FeedbackVectorData::SerializeSlots");
979 : Handle<FeedbackVector> vector = Handle<FeedbackVector>::cast(object());
980 : DCHECK(feedback_.empty());
981 34329 : feedback_.reserve(vector->length());
982 1356334 : for (int i = 0; i < vector->length(); ++i) {
983 : MaybeObject value = vector->get(i);
984 : ObjectData* slot_value =
985 : value->IsObject() ? broker->GetOrCreateData(value->cast<Object>())
986 661002 : : nullptr;
987 661009 : feedback_.push_back(slot_value);
988 760986 : if (slot_value == nullptr) continue;
989 :
990 567708 : if (slot_value->IsAllocationSite() &&
991 6686 : slot_value->AsAllocationSite()->IsFastLiteral()) {
992 5527 : slot_value->AsAllocationSite()->SerializeBoilerplate(broker);
993 555494 : } else if (slot_value->IsJSRegExp()) {
994 498 : slot_value->AsJSRegExp()->SerializeAsRegExpBoilerplate(broker);
995 : }
996 : }
997 : DCHECK_EQ(vector->length(), feedback_.size());
998 34330 : TRACE(broker, "Copied " << feedback_.size() << " slots.");
999 : }
1000 :
1001 : class FixedArrayBaseData : public HeapObjectData {
1002 : public:
1003 1127226 : FixedArrayBaseData(JSHeapBroker* broker, ObjectData** storage,
1004 : Handle<FixedArrayBase> object)
1005 2254460 : : HeapObjectData(broker, storage, object), length_(object->length()) {}
1006 :
1007 : int length() const { return length_; }
1008 :
1009 : private:
1010 : int const length_;
1011 : };
1012 :
1013 : class FixedArrayData : public FixedArrayBaseData {
1014 : public:
1015 : FixedArrayData(JSHeapBroker* broker, ObjectData** storage,
1016 : Handle<FixedArray> object);
1017 :
1018 : // Creates all elements of the fixed array.
1019 : void SerializeContents(JSHeapBroker* broker);
1020 :
1021 : ObjectData* Get(int i) const;
1022 :
1023 : private:
1024 : bool serialized_contents_ = false;
1025 : ZoneVector<ObjectData*> contents_;
1026 : };
1027 :
1028 160 : JSDataViewData::JSDataViewData(JSHeapBroker* broker, ObjectData** storage,
1029 : Handle<JSDataView> object)
1030 : : JSObjectData(broker, storage, object),
1031 : byte_length_(object->byte_length()),
1032 320 : byte_offset_(object->byte_offset()) {}
1033 :
1034 165 : JSBoundFunctionData::JSBoundFunctionData(JSHeapBroker* broker,
1035 : ObjectData** storage,
1036 : Handle<JSBoundFunction> object)
1037 165 : : JSObjectData(broker, storage, object) {}
1038 :
1039 0 : void JSBoundFunctionData::Serialize(JSHeapBroker* broker) {
1040 0 : if (serialized_) return;
1041 0 : serialized_ = true;
1042 :
1043 0 : TraceScope tracer(broker, this, "JSBoundFunctionData::Serialize");
1044 : Handle<JSBoundFunction> function = Handle<JSBoundFunction>::cast(object());
1045 :
1046 : DCHECK_NULL(bound_target_function_);
1047 : DCHECK_NULL(bound_this_);
1048 : DCHECK_NULL(bound_arguments_);
1049 :
1050 : bound_target_function_ =
1051 0 : broker->GetOrCreateData(function->bound_target_function());
1052 0 : bound_this_ = broker->GetOrCreateData(function->bound_this());
1053 : bound_arguments_ =
1054 0 : broker->GetOrCreateData(function->bound_arguments())->AsFixedArray();
1055 :
1056 0 : bound_arguments_->SerializeContents(broker);
1057 : }
1058 :
1059 3313878 : JSObjectData::JSObjectData(JSHeapBroker* broker, ObjectData** storage,
1060 : Handle<JSObject> object)
1061 : : HeapObjectData(broker, storage, object),
1062 23494763 : inobject_fields_(broker->zone()) {}
1063 :
1064 512937 : FixedArrayData::FixedArrayData(JSHeapBroker* broker, ObjectData** storage,
1065 : Handle<FixedArray> object)
1066 1025876 : : FixedArrayBaseData(broker, storage, object), contents_(broker->zone()) {}
1067 :
1068 1567 : void FixedArrayData::SerializeContents(JSHeapBroker* broker) {
1069 1567 : if (serialized_contents_) return;
1070 1567 : serialized_contents_ = true;
1071 :
1072 1567 : TraceScope tracer(broker, this, "FixedArrayData::SerializeContents");
1073 : Handle<FixedArray> array = Handle<FixedArray>::cast(object());
1074 1567 : CHECK_EQ(array->length(), length());
1075 1567 : CHECK(contents_.empty());
1076 1567 : contents_.reserve(static_cast<size_t>(length()));
1077 :
1078 14547 : for (int i = 0; i < length(); i++) {
1079 : Handle<Object> value(array->get(i), broker->isolate());
1080 12980 : contents_.push_back(broker->GetOrCreateData(value));
1081 : }
1082 1567 : TRACE(broker, "Copied " << contents_.size() << " elements.");
1083 : }
1084 :
1085 : class FixedDoubleArrayData : public FixedArrayBaseData {
1086 : public:
1087 : FixedDoubleArrayData(JSHeapBroker* broker, ObjectData** storage,
1088 : Handle<FixedDoubleArray> object);
1089 :
1090 : // Serializes all elements of the fixed array.
1091 : void SerializeContents(JSHeapBroker* broker);
1092 :
1093 : Float64 Get(int i) const;
1094 :
1095 : private:
1096 : bool serialized_contents_ = false;
1097 : ZoneVector<Float64> contents_;
1098 : };
1099 :
1100 531 : FixedDoubleArrayData::FixedDoubleArrayData(JSHeapBroker* broker,
1101 : ObjectData** storage,
1102 : Handle<FixedDoubleArray> object)
1103 1062 : : FixedArrayBaseData(broker, storage, object), contents_(broker->zone()) {}
1104 :
1105 531 : void FixedDoubleArrayData::SerializeContents(JSHeapBroker* broker) {
1106 531 : if (serialized_contents_) return;
1107 531 : serialized_contents_ = true;
1108 :
1109 531 : TraceScope tracer(broker, this, "FixedDoubleArrayData::SerializeContents");
1110 : Handle<FixedDoubleArray> self = Handle<FixedDoubleArray>::cast(object());
1111 531 : CHECK_EQ(self->length(), length());
1112 531 : CHECK(contents_.empty());
1113 531 : contents_.reserve(static_cast<size_t>(length()));
1114 :
1115 14921 : for (int i = 0; i < length(); i++) {
1116 14390 : contents_.push_back(Float64::FromBits(self->get_representation(i)));
1117 : }
1118 531 : TRACE(broker, "Copied " << contents_.size() << " elements.");
1119 : }
1120 :
1121 : class BytecodeArrayData : public FixedArrayBaseData {
1122 : public:
1123 : int register_count() const { return register_count_; }
1124 :
1125 613762 : BytecodeArrayData(JSHeapBroker* broker, ObjectData** storage,
1126 : Handle<BytecodeArray> object)
1127 : : FixedArrayBaseData(broker, storage, object),
1128 1227526 : register_count_(object->register_count()) {}
1129 :
1130 : private:
1131 : int const register_count_;
1132 : };
1133 :
1134 : class JSArrayData : public JSObjectData {
1135 : public:
1136 : JSArrayData(JSHeapBroker* broker, ObjectData** storage,
1137 : Handle<JSArray> object);
1138 : void Serialize(JSHeapBroker* broker);
1139 :
1140 : ObjectData* length() const { return length_; }
1141 :
1142 : private:
1143 : bool serialized_ = false;
1144 : ObjectData* length_ = nullptr;
1145 : };
1146 :
1147 472770 : JSArrayData::JSArrayData(JSHeapBroker* broker, ObjectData** storage,
1148 : Handle<JSArray> object)
1149 472770 : : JSObjectData(broker, storage, object) {}
1150 :
1151 3948 : void JSArrayData::Serialize(JSHeapBroker* broker) {
1152 3948 : if (serialized_) return;
1153 3948 : serialized_ = true;
1154 :
1155 3948 : TraceScope tracer(broker, this, "JSArrayData::Serialize");
1156 : Handle<JSArray> jsarray = Handle<JSArray>::cast(object());
1157 : DCHECK_NULL(length_);
1158 3948 : length_ = broker->GetOrCreateData(jsarray->length());
1159 : }
1160 :
1161 : class ScopeInfoData : public HeapObjectData {
1162 : public:
1163 : ScopeInfoData(JSHeapBroker* broker, ObjectData** storage,
1164 : Handle<ScopeInfo> object);
1165 :
1166 : int context_length() const { return context_length_; }
1167 :
1168 : private:
1169 : int const context_length_;
1170 : };
1171 :
1172 55558 : ScopeInfoData::ScopeInfoData(JSHeapBroker* broker, ObjectData** storage,
1173 : Handle<ScopeInfo> object)
1174 : : HeapObjectData(broker, storage, object),
1175 111116 : context_length_(object->ContextLength()) {}
1176 :
1177 : class SharedFunctionInfoData : public HeapObjectData {
1178 : public:
1179 : SharedFunctionInfoData(JSHeapBroker* broker, ObjectData** storage,
1180 : Handle<SharedFunctionInfo> object);
1181 :
1182 : int builtin_id() const { return builtin_id_; }
1183 : BytecodeArrayData* GetBytecodeArray() const { return GetBytecodeArray_; }
1184 : void SetSerializedForCompilation(JSHeapBroker* broker,
1185 : FeedbackVectorRef feedback);
1186 : bool IsSerializedForCompilation(FeedbackVectorRef feedback) const;
1187 : #define DECL_ACCESSOR(type, name) \
1188 : type name() const { return name##_; }
1189 : BROKER_SFI_FIELDS(DECL_ACCESSOR)
1190 : #undef DECL_ACCESSOR
1191 :
1192 : private:
1193 : int const builtin_id_;
1194 : BytecodeArrayData* const GetBytecodeArray_;
1195 : ZoneUnorderedSet<Handle<FeedbackVector>, Handle<FeedbackVector>::hash,
1196 : Handle<FeedbackVector>::equal_to>
1197 : serialized_for_compilation_;
1198 : #define DECL_MEMBER(type, name) type const name##_;
1199 : BROKER_SFI_FIELDS(DECL_MEMBER)
1200 : #undef DECL_MEMBER
1201 : };
1202 :
1203 7015655 : SharedFunctionInfoData::SharedFunctionInfoData(
1204 : JSHeapBroker* broker, ObjectData** storage,
1205 : Handle<SharedFunctionInfo> object)
1206 : : HeapObjectData(broker, storage, object),
1207 : builtin_id_(object->HasBuiltinId() ? object->builtin_id()
1208 : : Builtins::kNoBuiltinId),
1209 : GetBytecodeArray_(
1210 14031259 : object->HasBytecodeArray()
1211 7629388 : ? broker->GetOrCreateData(object->GetBytecodeArray())
1212 613765 : ->AsBytecodeArray()
1213 : : nullptr),
1214 : serialized_for_compilation_(broker->zone())
1215 : #define INIT_MEMBER(type, name) , name##_(object->name())
1216 112863598 : BROKER_SFI_FIELDS(INIT_MEMBER)
1217 : #undef INIT_MEMBER
1218 : {
1219 : DCHECK_EQ(HasBuiltinId_, builtin_id_ != Builtins::kNoBuiltinId);
1220 : DCHECK_EQ(HasBytecodeArray_, GetBytecodeArray_ != nullptr);
1221 7015639 : }
1222 :
1223 147 : void SharedFunctionInfoData::SetSerializedForCompilation(
1224 : JSHeapBroker* broker, FeedbackVectorRef feedback) {
1225 294 : CHECK(serialized_for_compilation_.insert(feedback.object()).second);
1226 147 : TRACE(broker, "Set function " << object() << " with " << feedback.object()
1227 : << " as serialized for compilation.");
1228 147 : }
1229 :
1230 0 : bool SharedFunctionInfoData::IsSerializedForCompilation(
1231 : FeedbackVectorRef feedback) const {
1232 648 : return serialized_for_compilation_.find(feedback.object()) !=
1233 0 : serialized_for_compilation_.end();
1234 : }
1235 :
1236 : class ModuleData : public HeapObjectData {
1237 : public:
1238 : ModuleData(JSHeapBroker* broker, ObjectData** storage, Handle<Module> object);
1239 : void Serialize(JSHeapBroker* broker);
1240 :
1241 : CellData* GetCell(int cell_index) const;
1242 :
1243 : private:
1244 : bool serialized_ = false;
1245 : ZoneVector<CellData*> imports_;
1246 : ZoneVector<CellData*> exports_;
1247 : };
1248 :
1249 85 : ModuleData::ModuleData(JSHeapBroker* broker, ObjectData** storage,
1250 : Handle<Module> object)
1251 : : HeapObjectData(broker, storage, object),
1252 : imports_(broker->zone()),
1253 170 : exports_(broker->zone()) {}
1254 :
1255 138 : CellData* ModuleData::GetCell(int cell_index) const {
1256 138 : CHECK(serialized_);
1257 : CellData* cell;
1258 138 : switch (ModuleDescriptor::GetCellIndexKind(cell_index)) {
1259 : case ModuleDescriptor::kImport:
1260 62 : cell = imports_.at(Module::ImportIndex(cell_index));
1261 31 : break;
1262 : case ModuleDescriptor::kExport:
1263 214 : cell = exports_.at(Module::ExportIndex(cell_index));
1264 107 : break;
1265 : case ModuleDescriptor::kInvalid:
1266 0 : UNREACHABLE();
1267 : break;
1268 : }
1269 138 : CHECK_NOT_NULL(cell);
1270 138 : return cell;
1271 : }
1272 :
1273 170 : void ModuleData::Serialize(JSHeapBroker* broker) {
1274 255 : if (serialized_) return;
1275 85 : serialized_ = true;
1276 :
1277 85 : TraceScope tracer(broker, this, "ModuleData::Serialize");
1278 : Handle<Module> module = Handle<Module>::cast(object());
1279 :
1280 : // TODO(neis): We could be smarter and only serialize the cells we care about.
1281 : // TODO(neis): Define a helper for serializing a FixedArray into a ZoneVector.
1282 :
1283 : DCHECK(imports_.empty());
1284 : Handle<FixedArray> imports(module->regular_imports(), broker->isolate());
1285 : int const imports_length = imports->length();
1286 85 : imports_.reserve(imports_length);
1287 273 : for (int i = 0; i < imports_length; ++i) {
1288 188 : imports_.push_back(broker->GetOrCreateData(imports->get(i))->AsCell());
1289 : }
1290 85 : TRACE(broker, "Copied " << imports_.size() << " imports.");
1291 :
1292 : DCHECK(exports_.empty());
1293 : Handle<FixedArray> exports(module->regular_exports(), broker->isolate());
1294 : int const exports_length = exports->length();
1295 85 : exports_.reserve(exports_length);
1296 433 : for (int i = 0; i < exports_length; ++i) {
1297 348 : exports_.push_back(broker->GetOrCreateData(exports->get(i))->AsCell());
1298 : }
1299 85 : TRACE(broker, "Copied " << exports_.size() << " exports.");
1300 : }
1301 :
1302 : class CellData : public HeapObjectData {
1303 : public:
1304 : CellData(JSHeapBroker* broker, ObjectData** storage, Handle<Cell> object);
1305 :
1306 : void Serialize(JSHeapBroker* broker);
1307 : ObjectData* value() { return value_; }
1308 :
1309 : private:
1310 : bool serialized_ = false;
1311 : ObjectData* value_ = nullptr;
1312 : };
1313 :
1314 928012 : CellData::CellData(JSHeapBroker* broker, ObjectData** storage,
1315 : Handle<Cell> object)
1316 928012 : : HeapObjectData(broker, storage, object) {}
1317 :
1318 927753 : void CellData::Serialize(JSHeapBroker* broker) {
1319 927753 : if (serialized_) return;
1320 927753 : serialized_ = true;
1321 :
1322 927753 : TraceScope tracer(broker, this, "CellData::Serialize");
1323 : auto cell = Handle<Cell>::cast(object());
1324 : DCHECK_NULL(value_);
1325 927754 : value_ = broker->GetOrCreateData(cell->value());
1326 : }
1327 :
1328 : class JSGlobalProxyData : public JSObjectData {
1329 : public:
1330 463879 : JSGlobalProxyData(JSHeapBroker* broker, ObjectData** storage,
1331 : Handle<JSGlobalProxy> object)
1332 463873 : : JSObjectData(broker, storage, object) {}
1333 : };
1334 :
1335 : class CodeData : public HeapObjectData {
1336 : public:
1337 5820584 : CodeData(JSHeapBroker* broker, ObjectData** storage, Handle<Code> object)
1338 5820584 : : HeapObjectData(broker, storage, object) {}
1339 : };
1340 :
1341 : #define DEFINE_IS_AND_AS(Name) \
1342 : bool ObjectData::Is##Name() const { \
1343 : if (kind() == kUnserializedHeapObject) { \
1344 : AllowHandleDereference allow_handle_dereference; \
1345 : return object()->Is##Name(); \
1346 : } \
1347 : if (is_smi()) return false; \
1348 : InstanceType instance_type = \
1349 : static_cast<const HeapObjectData*>(this)->map()->instance_type(); \
1350 : return InstanceTypeChecker::Is##Name(instance_type); \
1351 : } \
1352 : Name##Data* ObjectData::As##Name() { \
1353 : CHECK_EQ(kind(), kSerializedHeapObject); \
1354 : CHECK(Is##Name()); \
1355 : return static_cast<Name##Data*>(this); \
1356 : }
1357 921596597 : HEAP_BROKER_OBJECT_LIST(DEFINE_IS_AND_AS)
1358 : #undef DEFINE_IS_AND_AS
1359 :
1360 3274 : const JSObjectField& JSObjectData::GetInobjectField(int property_index) const {
1361 3274 : CHECK_LT(static_cast<size_t>(property_index), inobject_fields_.size());
1362 3274 : return inobject_fields_[property_index];
1363 : }
1364 :
1365 0 : bool JSObjectData::cow_or_empty_elements_tenured() const {
1366 40 : return cow_or_empty_elements_tenured_;
1367 : }
1368 :
1369 7106 : FixedArrayBaseData* JSObjectData::elements() const { return elements_; }
1370 :
1371 0 : void JSObjectData::SerializeAsBoilerplate(JSHeapBroker* broker) {
1372 5775 : SerializeRecursive(broker, kMaxFastLiteralDepth);
1373 0 : }
1374 :
1375 498 : void JSObjectData::SerializeElements(JSHeapBroker* broker) {
1376 498 : if (serialized_elements_) return;
1377 498 : serialized_elements_ = true;
1378 :
1379 498 : TraceScope tracer(broker, this, "JSObjectData::SerializeElements");
1380 : Handle<JSObject> boilerplate = Handle<JSObject>::cast(object());
1381 : Handle<FixedArrayBase> elements_object(boilerplate->elements(),
1382 : broker->isolate());
1383 : DCHECK_NULL(elements_);
1384 498 : elements_ = broker->GetOrCreateData(elements_object)->AsFixedArrayBase();
1385 : }
1386 :
1387 13459027 : void MapData::SerializeConstructor(JSHeapBroker* broker) {
1388 13922905 : if (serialized_constructor_) return;
1389 12995149 : serialized_constructor_ = true;
1390 :
1391 12995149 : TraceScope tracer(broker, this, "MapData::SerializeConstructor");
1392 : Handle<Map> map = Handle<Map>::cast(object());
1393 : DCHECK_NULL(constructor_);
1394 12995148 : constructor_ = broker->GetOrCreateData(map->GetConstructor());
1395 : }
1396 :
1397 4649419 : void MapData::SerializePrototype(JSHeapBroker* broker) {
1398 4649419 : if (serialized_prototype_) return;
1399 4649419 : serialized_prototype_ = true;
1400 :
1401 4649419 : TraceScope tracer(broker, this, "MapData::SerializePrototype");
1402 : Handle<Map> map = Handle<Map>::cast(object());
1403 : DCHECK_NULL(prototype_);
1404 4649418 : prototype_ = broker->GetOrCreateData(map->prototype());
1405 : }
1406 :
1407 8397 : void MapData::SerializeOwnDescriptors(JSHeapBroker* broker) {
1408 13387 : if (serialized_own_descriptors_) return;
1409 4642 : serialized_own_descriptors_ = true;
1410 :
1411 4642 : TraceScope tracer(broker, this, "MapData::SerializeOwnDescriptors");
1412 : Handle<Map> map = Handle<Map>::cast(object());
1413 :
1414 : DCHECK_NULL(instance_descriptors_);
1415 : instance_descriptors_ =
1416 4642 : broker->GetOrCreateData(map->instance_descriptors())->AsDescriptorArray();
1417 :
1418 : int const number_of_own = map->NumberOfOwnDescriptors();
1419 4642 : ZoneVector<PropertyDescriptor>& contents = instance_descriptors_->contents();
1420 4642 : int const current_size = static_cast<int>(contents.size());
1421 4642 : if (number_of_own <= current_size) return;
1422 :
1423 : Isolate* const isolate = broker->isolate();
1424 : auto descriptors =
1425 : Handle<DescriptorArray>::cast(instance_descriptors_->object());
1426 3407 : CHECK_EQ(*descriptors, map->instance_descriptors());
1427 3407 : contents.reserve(number_of_own);
1428 :
1429 : // Copy the new descriptors.
1430 11597 : for (int i = current_size; i < number_of_own; ++i) {
1431 : PropertyDescriptor d;
1432 4095 : d.key = broker->GetOrCreateData(descriptors->GetKey(i))->AsName();
1433 4095 : d.details = descriptors->GetDetails(i);
1434 4095 : if (d.details.location() == kField) {
1435 2169 : d.field_index = FieldIndex::ForDescriptor(*map, i);
1436 : d.field_owner =
1437 2169 : broker->GetOrCreateData(map->FindFieldOwner(isolate, i))->AsMap();
1438 4338 : d.field_type = broker->GetOrCreateData(descriptors->GetFieldType(i));
1439 2169 : d.is_unboxed_double_field = map->IsUnboxedDoubleField(d.field_index);
1440 : // Recurse.
1441 : }
1442 4095 : contents.push_back(d);
1443 : }
1444 3407 : CHECK_EQ(number_of_own, contents.size());
1445 :
1446 : // Recurse on the new owner maps.
1447 11597 : for (int i = current_size; i < number_of_own; ++i) {
1448 4095 : const PropertyDescriptor& d = contents[i];
1449 4095 : if (d.details.location() == kField) {
1450 4338 : CHECK_LE(
1451 : Handle<Map>::cast(d.field_owner->object())->NumberOfOwnDescriptors(),
1452 : number_of_own);
1453 2169 : d.field_owner->SerializeOwnDescriptors(broker);
1454 : }
1455 : }
1456 :
1457 3407 : TRACE(broker, "Copied " << number_of_own - current_size
1458 : << " descriptors into " << instance_descriptors_
1459 : << " (" << number_of_own << " total).");
1460 : }
1461 :
1462 6460 : void JSObjectData::SerializeRecursive(JSHeapBroker* broker, int depth) {
1463 6708 : if (serialized_as_boilerplate_) return;
1464 6212 : serialized_as_boilerplate_ = true;
1465 :
1466 6212 : TraceScope tracer(broker, this, "JSObjectData::SerializeRecursive");
1467 : Handle<JSObject> boilerplate = Handle<JSObject>::cast(object());
1468 :
1469 : // We only serialize boilerplates that pass the IsInlinableFastLiteral
1470 : // check, so we only do a sanity check on the depth here.
1471 6212 : CHECK_GT(depth, 0);
1472 6212 : CHECK(!boilerplate->map()->is_deprecated());
1473 :
1474 : // Serialize the elements.
1475 : Isolate* const isolate = broker->isolate();
1476 : Handle<FixedArrayBase> elements_object(boilerplate->elements(), isolate);
1477 :
1478 : // Boilerplates need special serialization - we need to make sure COW arrays
1479 : // are tenured. Boilerplate objects should only be reachable from their
1480 : // allocation site, so it is safe to assume that the elements have not been
1481 : // serialized yet.
1482 :
1483 : bool const empty_or_cow =
1484 10236 : elements_object->length() == 0 ||
1485 : elements_object->map() == ReadOnlyRoots(isolate).fixed_cow_array_map();
1486 6212 : if (empty_or_cow) {
1487 : // We need to make sure copy-on-write elements are tenured.
1488 4114 : if (ObjectInYoungGeneration(*elements_object)) {
1489 : elements_object = isolate->factory()->CopyAndTenureFixedCOWArray(
1490 1584 : Handle<FixedArray>::cast(elements_object));
1491 1584 : boilerplate->set_elements(*elements_object);
1492 : }
1493 4114 : cow_or_empty_elements_tenured_ = true;
1494 : }
1495 :
1496 : DCHECK_NULL(elements_);
1497 6212 : elements_ = broker->GetOrCreateData(elements_object)->AsFixedArrayBase();
1498 :
1499 6212 : if (empty_or_cow) {
1500 : // No need to do anything here. Empty or copy-on-write elements
1501 : // do not need to be serialized because we only need to store the elements
1502 : // reference to the allocated object.
1503 4196 : } else if (boilerplate->HasSmiOrObjectElements()) {
1504 1567 : elements_->AsFixedArray()->SerializeContents(broker);
1505 : Handle<FixedArray> fast_elements =
1506 : Handle<FixedArray>::cast(elements_object);
1507 : int length = elements_object->length();
1508 14547 : for (int i = 0; i < length; i++) {
1509 : Handle<Object> value(fast_elements->get(i), isolate);
1510 6490 : if (value->IsJSObject()) {
1511 399 : ObjectData* value_data = broker->GetOrCreateData(value);
1512 399 : value_data->AsJSObject()->SerializeRecursive(broker, depth - 1);
1513 : }
1514 : }
1515 : } else {
1516 1062 : CHECK(boilerplate->HasDoubleElements());
1517 531 : CHECK_LE(elements_object->Size(), kMaxRegularHeapObjectSize);
1518 531 : elements_->AsFixedDoubleArray()->SerializeContents(broker);
1519 : }
1520 :
1521 : // TODO(turbofan): Do we want to support out-of-object properties?
1522 18636 : CHECK(boilerplate->HasFastProperties() &&
1523 : boilerplate->property_array()->length() == 0);
1524 6212 : CHECK_EQ(inobject_fields_.size(), 0u);
1525 :
1526 : // Check the in-object properties.
1527 : Handle<DescriptorArray> descriptors(
1528 : boilerplate->map()->instance_descriptors(), isolate);
1529 : int const limit = boilerplate->map()->NumberOfOwnDescriptors();
1530 19728 : for (int i = 0; i < limit; i++) {
1531 6758 : PropertyDetails details = descriptors->GetDetails(i);
1532 10706 : if (details.location() != kField) continue;
1533 : DCHECK_EQ(kData, details.kind());
1534 :
1535 2810 : FieldIndex field_index = FieldIndex::ForDescriptor(boilerplate->map(), i);
1536 : // Make sure {field_index} agrees with {inobject_properties} on the index of
1537 : // this field.
1538 : DCHECK_EQ(field_index.property_index(),
1539 : static_cast<int>(inobject_fields_.size()));
1540 : if (boilerplate->IsUnboxedDoubleField(field_index)) {
1541 : double value = boilerplate->RawFastDoublePropertyAt(field_index);
1542 : inobject_fields_.push_back(JSObjectField{value});
1543 : } else {
1544 : Handle<Object> value(boilerplate->RawFastPropertyAt(field_index),
1545 5620 : isolate);
1546 2810 : ObjectData* value_data = broker->GetOrCreateData(value);
1547 2810 : if (value->IsJSObject()) {
1548 286 : value_data->AsJSObject()->SerializeRecursive(broker, depth - 1);
1549 : }
1550 5620 : inobject_fields_.push_back(JSObjectField{value_data});
1551 : }
1552 : }
1553 6212 : TRACE(broker, "Copied " << inobject_fields_.size() << " in-object fields.");
1554 :
1555 6212 : map()->SerializeOwnDescriptors(broker);
1556 :
1557 6212 : if (IsJSArray()) AsJSArray()->Serialize(broker);
1558 : }
1559 :
1560 498 : void JSRegExpData::SerializeAsRegExpBoilerplate(JSHeapBroker* broker) {
1561 498 : if (serialized_as_reg_exp_boilerplate_) return;
1562 498 : serialized_as_reg_exp_boilerplate_ = true;
1563 :
1564 498 : TraceScope tracer(broker, this, "JSRegExpData::SerializeAsRegExpBoilerplate");
1565 : Handle<JSRegExp> boilerplate = Handle<JSRegExp>::cast(object());
1566 :
1567 498 : SerializeElements(broker);
1568 :
1569 : raw_properties_or_hash_ =
1570 498 : broker->GetOrCreateData(boilerplate->raw_properties_or_hash());
1571 498 : data_ = broker->GetOrCreateData(boilerplate->data());
1572 498 : source_ = broker->GetOrCreateData(boilerplate->source());
1573 498 : flags_ = broker->GetOrCreateData(boilerplate->flags());
1574 498 : last_index_ = broker->GetOrCreateData(boilerplate->last_index());
1575 : }
1576 :
1577 1262254 : bool ObjectRef::equals(const ObjectRef& other) const {
1578 33665044 : return data_ == other.data_;
1579 : }
1580 :
1581 1690724 : Isolate* ObjectRef::isolate() const { return broker()->isolate(); }
1582 :
1583 22900 : ContextRef ContextRef::previous() const {
1584 22900 : if (broker()->mode() == JSHeapBroker::kDisabled) {
1585 : AllowHandleAllocation handle_allocation;
1586 : AllowHandleDereference handle_dereference;
1587 : return ContextRef(broker(),
1588 45800 : handle(object()->previous(), broker()->isolate()));
1589 : }
1590 0 : return ContextRef(broker(), data()->AsContext()->previous());
1591 : }
1592 :
1593 : // Not needed for TypedLowering.
1594 26463 : ObjectRef ContextRef::get(int index) const {
1595 26463 : if (broker()->mode() == JSHeapBroker::kDisabled) {
1596 : AllowHandleAllocation handle_allocation;
1597 : AllowHandleDereference handle_dereference;
1598 : Handle<Object> value(object()->get(index), broker()->isolate());
1599 26447 : return ObjectRef(broker(), value);
1600 : }
1601 32 : return ObjectRef(broker(), data()->AsContext()->GetSlot(index));
1602 : }
1603 :
1604 485563 : JSHeapBroker::JSHeapBroker(Isolate* isolate, Zone* broker_zone)
1605 : : isolate_(isolate),
1606 : broker_zone_(broker_zone),
1607 : current_zone_(broker_zone),
1608 : refs_(new (zone())
1609 485566 : RefsMap(kMinimalRefsBucketCount, AddressMatcher(), zone())),
1610 : array_and_object_prototypes_(zone()),
1611 1942257 : feedback_(zone()) {
1612 : // Note that this initialization of the refs_ pointer with the minimal
1613 : // initial capacity is redundant in the normal use case (concurrent
1614 : // compilation enabled, standard objects to be serialized), as the map
1615 : // is going to be replaced immediatelly with a larger capacity one.
1616 : // It doesn't seem to affect the performance in a noticeable way though.
1617 485572 : TRACE(this, "Constructing heap broker.");
1618 485572 : }
1619 :
1620 0 : std::ostream& JSHeapBroker::Trace() {
1621 0 : return trace_out_ << "[" << this << "] "
1622 0 : << std::string(trace_indentation_ * 2, ' ');
1623 : }
1624 :
1625 463859 : void JSHeapBroker::StartSerializing() {
1626 463859 : CHECK_EQ(mode_, kDisabled);
1627 463859 : TRACE(this, "Starting serialization.");
1628 463867 : mode_ = kSerializing;
1629 463867 : refs_->Clear();
1630 463867 : }
1631 :
1632 463870 : void JSHeapBroker::StopSerializing() {
1633 463870 : CHECK_EQ(mode_, kSerializing);
1634 463870 : TRACE(this, "Stopping serialization.");
1635 463870 : mode_ = kSerialized;
1636 463870 : }
1637 :
1638 463571 : void JSHeapBroker::Retire() {
1639 463571 : CHECK_EQ(mode_, kSerialized);
1640 463571 : TRACE(this, "Retiring.");
1641 463571 : mode_ = kRetired;
1642 463571 : }
1643 :
1644 0 : bool JSHeapBroker::SerializingAllowed() const { return mode() == kSerializing; }
1645 :
1646 928239 : void JSHeapBroker::SetNativeContextRef() {
1647 1856481 : native_context_ = NativeContextRef(this, isolate()->native_context());
1648 928242 : }
1649 :
1650 5268098 : bool IsShareable(Handle<Object> object, Isolate* isolate) {
1651 : Builtins* const b = isolate->builtins();
1652 :
1653 : int index;
1654 : RootIndex root_index;
1655 5268104 : return (object->IsHeapObject() &&
1656 5297452 : b->IsBuiltinHandle(Handle<HeapObject>::cast(object), &index)) ||
1657 5268070 : isolate->roots_table().IsRootHandle(object, &root_index);
1658 : }
1659 :
1660 463855 : void JSHeapBroker::SerializeShareableObjects() {
1661 463855 : PerIsolateCompilerCache::Setup(isolate());
1662 463858 : compiler_cache_ = isolate()->compiler_cache();
1663 :
1664 463858 : if (compiler_cache_->HasSnapshot()) {
1665 : RefsMap* snapshot = compiler_cache_->GetSnapshot();
1666 :
1667 449190 : refs_ = new (zone()) RefsMap(snapshot, zone());
1668 449201 : return;
1669 : }
1670 :
1671 : TraceScope tracer(
1672 : this, "JSHeapBroker::SerializeShareableObjects (building snapshot)");
1673 :
1674 : refs_ =
1675 29354 : new (zone()) RefsMap(kInitialRefsBucketCount, AddressMatcher(), zone());
1676 :
1677 14748 : current_zone_ = compiler_cache_->zone();
1678 :
1679 : Builtins* const b = isolate()->builtins();
1680 : {
1681 : Builtins::Name builtins[] = {
1682 : Builtins::kAllocateInYoungGeneration,
1683 : Builtins::kAllocateInOldGeneration,
1684 : Builtins::kArgumentsAdaptorTrampoline,
1685 : Builtins::kArrayConstructorImpl,
1686 : Builtins::kCallFunctionForwardVarargs,
1687 : Builtins::kCallFunction_ReceiverIsAny,
1688 : Builtins::kCallFunction_ReceiverIsNotNullOrUndefined,
1689 : Builtins::kCallFunction_ReceiverIsNullOrUndefined,
1690 : Builtins::kConstructFunctionForwardVarargs,
1691 : Builtins::kForInFilter,
1692 : Builtins::kJSBuiltinsConstructStub,
1693 : Builtins::kJSConstructStubGeneric,
1694 : Builtins::kStringAdd_CheckNone,
1695 : Builtins::kStringAdd_ConvertLeft,
1696 : Builtins::kStringAdd_ConvertRight,
1697 : Builtins::kToNumber,
1698 : Builtins::kToObject,
1699 14748 : };
1700 513732 : for (auto id : builtins) {
1701 498985 : GetOrCreateData(b->builtin_handle(id));
1702 : }
1703 : }
1704 44481010 : for (int32_t id = 0; id < Builtins::builtin_count; ++id) {
1705 22233201 : if (Builtins::KindOf(id) == Builtins::TFJ) {
1706 9978506 : GetOrCreateData(b->builtin_handle(id));
1707 : }
1708 : }
1709 :
1710 15833651 : for (RefsMap::Entry* p = refs_->Start(); p != nullptr; p = refs_->Next(p)) {
1711 5268099 : CHECK(IsShareable(p->value->object(), isolate()));
1712 : }
1713 :
1714 : // TODO(mslekova):
1715 : // Serialize root objects (from factory).
1716 14677 : compiler_cache()->SetSnapshot(refs_);
1717 14677 : current_zone_ = broker_zone_;
1718 : }
1719 :
1720 463876 : void JSHeapBroker::CollectArrayAndObjectPrototypes() {
1721 : DisallowHeapAllocation no_gc;
1722 463876 : CHECK_EQ(mode(), kSerializing);
1723 463876 : CHECK(array_and_object_prototypes_.empty());
1724 :
1725 : Object maybe_context = isolate()->heap()->native_contexts_list();
1726 3877710 : while (!maybe_context->IsUndefined(isolate())) {
1727 1706918 : Context context = Context::cast(maybe_context);
1728 : Object array_prot = context->get(Context::INITIAL_ARRAY_PROTOTYPE_INDEX);
1729 : Object object_prot = context->get(Context::INITIAL_OBJECT_PROTOTYPE_INDEX);
1730 3413833 : array_and_object_prototypes_.emplace(JSObject::cast(array_prot), isolate());
1731 3413831 : array_and_object_prototypes_.emplace(JSObject::cast(object_prot),
1732 3413831 : isolate());
1733 1706917 : maybe_context = context->next_context_link();
1734 : }
1735 :
1736 463875 : CHECK(!array_and_object_prototypes_.empty());
1737 463875 : }
1738 :
1739 65414 : bool JSHeapBroker::IsArrayOrObjectPrototype(const JSObjectRef& object) const {
1740 65414 : if (mode() == kDisabled) {
1741 130812 : return isolate()->IsInAnyContext(*object.object(),
1742 127555 : Context::INITIAL_ARRAY_PROTOTYPE_INDEX) ||
1743 62149 : isolate()->IsInAnyContext(*object.object(),
1744 : Context::INITIAL_OBJECT_PROTOTYPE_INDEX);
1745 : }
1746 8 : CHECK(!array_and_object_prototypes_.empty());
1747 16 : return array_and_object_prototypes_.find(object.object()) !=
1748 : array_and_object_prototypes_.end();
1749 : }
1750 :
1751 463877 : void JSHeapBroker::SerializeStandardObjects() {
1752 463901 : if (mode() == kDisabled) return;
1753 463853 : CHECK_EQ(mode(), kSerializing);
1754 :
1755 463853 : SerializeShareableObjects();
1756 :
1757 : TraceScope tracer(this, "JSHeapBroker::SerializeStandardObjects");
1758 :
1759 463877 : CollectArrayAndObjectPrototypes();
1760 :
1761 463875 : SetNativeContextRef();
1762 463867 : native_context().Serialize();
1763 :
1764 : Factory* const f = isolate()->factory();
1765 :
1766 : // Maps, strings, oddballs
1767 463878 : GetOrCreateData(f->arguments_marker_map());
1768 463877 : GetOrCreateData(f->bigint_string());
1769 463877 : GetOrCreateData(f->block_context_map());
1770 463876 : GetOrCreateData(f->boolean_map());
1771 463877 : GetOrCreateData(f->boolean_string());
1772 463876 : GetOrCreateData(f->catch_context_map());
1773 463877 : GetOrCreateData(f->empty_fixed_array());
1774 463877 : GetOrCreateData(f->empty_string());
1775 463878 : GetOrCreateData(f->eval_context_map());
1776 463877 : GetOrCreateData(f->false_string());
1777 463878 : GetOrCreateData(f->false_value());
1778 463878 : GetOrCreateData(f->fixed_array_map());
1779 463878 : GetOrCreateData(f->fixed_cow_array_map());
1780 463877 : GetOrCreateData(f->fixed_double_array_map());
1781 463878 : GetOrCreateData(f->function_context_map());
1782 463877 : GetOrCreateData(f->function_string());
1783 463878 : GetOrCreateData(f->heap_number_map());
1784 463878 : GetOrCreateData(f->length_string());
1785 463878 : GetOrCreateData(f->many_closures_cell_map());
1786 463877 : GetOrCreateData(f->minus_zero_value());
1787 463877 : GetOrCreateData(f->mutable_heap_number_map());
1788 463878 : GetOrCreateData(f->name_dictionary_map());
1789 463878 : GetOrCreateData(f->NaN_string());
1790 463877 : GetOrCreateData(f->null_map());
1791 463874 : GetOrCreateData(f->null_string());
1792 463878 : GetOrCreateData(f->null_value());
1793 463878 : GetOrCreateData(f->number_string());
1794 463878 : GetOrCreateData(f->object_string());
1795 463878 : GetOrCreateData(f->one_pointer_filler_map());
1796 463874 : GetOrCreateData(f->optimized_out());
1797 463876 : GetOrCreateData(f->optimized_out_map());
1798 463877 : GetOrCreateData(f->property_array_map());
1799 463878 : GetOrCreateData(f->sloppy_arguments_elements_map());
1800 463877 : GetOrCreateData(f->stale_register());
1801 463878 : GetOrCreateData(f->stale_register_map());
1802 463877 : GetOrCreateData(f->string_string());
1803 463878 : GetOrCreateData(f->symbol_string());
1804 463877 : GetOrCreateData(f->termination_exception_map());
1805 463878 : GetOrCreateData(f->the_hole_map());
1806 463878 : GetOrCreateData(f->the_hole_value());
1807 463878 : GetOrCreateData(f->true_string());
1808 463878 : GetOrCreateData(f->true_value());
1809 463878 : GetOrCreateData(f->undefined_map());
1810 463878 : GetOrCreateData(f->undefined_string());
1811 463878 : GetOrCreateData(f->undefined_value());
1812 463878 : GetOrCreateData(f->uninitialized_map());
1813 463878 : GetOrCreateData(f->with_context_map());
1814 463878 : GetOrCreateData(f->zero_string());
1815 :
1816 : // Protector cells
1817 : GetOrCreateData(f->array_buffer_detaching_protector())
1818 : ->AsPropertyCell()
1819 463877 : ->Serialize(this);
1820 463878 : GetOrCreateData(f->array_constructor_protector())->AsCell()->Serialize(this);
1821 : GetOrCreateData(f->array_iterator_protector())
1822 : ->AsPropertyCell()
1823 463878 : ->Serialize(this);
1824 : GetOrCreateData(f->array_species_protector())
1825 : ->AsPropertyCell()
1826 463878 : ->Serialize(this);
1827 : GetOrCreateData(f->no_elements_protector())
1828 : ->AsPropertyCell()
1829 463878 : ->Serialize(this);
1830 : GetOrCreateData(f->promise_hook_protector())
1831 : ->AsPropertyCell()
1832 463878 : ->Serialize(this);
1833 : GetOrCreateData(f->promise_species_protector())
1834 : ->AsPropertyCell()
1835 463878 : ->Serialize(this);
1836 : GetOrCreateData(f->promise_then_protector())
1837 : ->AsPropertyCell()
1838 463878 : ->Serialize(this);
1839 463878 : GetOrCreateData(f->string_length_protector())->AsCell()->Serialize(this);
1840 :
1841 : // CEntry stub
1842 927754 : GetOrCreateData(
1843 463878 : CodeFactory::CEntry(isolate(), 1, kDontSaveFPRegs, kArgvOnStack, true));
1844 :
1845 463876 : TRACE(this, "Finished serializing standard objects.");
1846 : }
1847 :
1848 0 : ObjectData* JSHeapBroker::GetData(Handle<Object> object) const {
1849 51535580 : RefsMap::Entry* entry = refs_->Lookup(object.address());
1850 51535983 : return entry ? entry->value : nullptr;
1851 : }
1852 :
1853 : // clang-format off
1854 208342400 : ObjectData* JSHeapBroker::GetOrCreateData(Handle<Object> object) {
1855 208342400 : CHECK(SerializingAllowed());
1856 208342400 : RefsMap::Entry* entry = refs_->LookupOrInsert(object.address(), zone());
1857 208347486 : ObjectData** data_storage = &(entry->value);
1858 208347486 : if (*data_storage == nullptr) {
1859 : // TODO(neis): Remove these Allow* once we serialize everything upfront.
1860 : AllowHandleAllocation handle_allocation;
1861 : AllowHandleDereference handle_dereference;
1862 92078448 : if (object->IsSmi()) {
1863 1070478 : new (zone()) ObjectData(this, data_storage, object, kSmi);
1864 : #define CREATE_DATA_IF_MATCH(name) \
1865 : } else if (object->Is##name()) { \
1866 : new (zone()) name##Data(this, data_storage, Handle<name>::cast(object));
1867 2189199098 : HEAP_BROKER_OBJECT_LIST(CREATE_DATA_IF_MATCH)
1868 : #undef CREATE_DATA_IF_MATCH
1869 : } else {
1870 0 : UNREACHABLE();
1871 : }
1872 : }
1873 208346140 : CHECK_NOT_NULL(*data_storage);
1874 208346140 : return (*data_storage);
1875 : }
1876 : // clang-format on
1877 :
1878 165001083 : ObjectData* JSHeapBroker::GetOrCreateData(Object object) {
1879 164999640 : return GetOrCreateData(handle(object, isolate()));
1880 : }
1881 :
1882 : #define DEFINE_IS_AND_AS(Name) \
1883 : bool ObjectRef::Is##Name() const { return data()->Is##Name(); } \
1884 : Name##Ref ObjectRef::As##Name() const { \
1885 : DCHECK(Is##Name()); \
1886 : return Name##Ref(broker(), data()); \
1887 : }
1888 79692633 : HEAP_BROKER_OBJECT_LIST(DEFINE_IS_AND_AS)
1889 : #undef DEFINE_IS_AND_AS
1890 :
1891 24209932 : bool ObjectRef::IsSmi() const { return data()->is_smi(); }
1892 :
1893 652396 : int ObjectRef::AsSmi() const {
1894 : DCHECK(IsSmi());
1895 : // Handle-dereference is always allowed for Handle<Smi>.
1896 652396 : return Handle<Smi>::cast(object())->value();
1897 : }
1898 :
1899 16 : base::Optional<MapRef> JSObjectRef::GetObjectCreateMap() const {
1900 16 : if (broker()->mode() == JSHeapBroker::kDisabled) {
1901 : AllowHandleAllocation handle_allocation;
1902 : AllowHandleDereference allow_handle_dereference;
1903 : AllowHeapAllocation heap_allocation;
1904 : Handle<Map> instance_map;
1905 0 : if (Map::TryGetObjectCreateMap(broker()->isolate(), object())
1906 : .ToHandle(&instance_map)) {
1907 0 : return MapRef(broker(), instance_map);
1908 : } else {
1909 0 : return base::Optional<MapRef>();
1910 : }
1911 : }
1912 16 : MapData* map_data = data()->AsJSObject()->object_create_map();
1913 : return map_data != nullptr ? MapRef(broker(), map_data)
1914 24 : : base::Optional<MapRef>();
1915 : }
1916 :
1917 : #define DEF_TESTER(Type, ...) \
1918 : bool MapRef::Is##Type##Map() const { \
1919 : return InstanceTypeChecker::Is##Type(instance_type()); \
1920 : }
1921 685564 : INSTANCE_TYPE_CHECKERS(DEF_TESTER)
1922 : #undef DEF_TESTER
1923 :
1924 1994 : base::Optional<MapRef> MapRef::AsElementsKind(ElementsKind kind) const {
1925 1994 : if (broker()->mode() == JSHeapBroker::kDisabled) {
1926 : AllowHandleAllocation handle_allocation;
1927 : AllowHeapAllocation heap_allocation;
1928 : AllowHandleDereference allow_handle_dereference;
1929 : return MapRef(broker(),
1930 0 : Map::AsElementsKind(broker()->isolate(), object(), kind));
1931 : }
1932 1994 : if (kind == elements_kind()) return *this;
1933 : const ZoneVector<MapData*>& elements_kind_generalizations =
1934 846 : data()->AsMap()->elements_kind_generalizations();
1935 1469 : for (auto data : elements_kind_generalizations) {
1936 : MapRef map(broker(), data);
1937 2315 : if (map.elements_kind() == kind) return map;
1938 : }
1939 0 : return base::Optional<MapRef>();
1940 : }
1941 :
1942 0 : void MapRef::SerializeForElementLoad() {
1943 0 : CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
1944 0 : data()->AsMap()->SerializeForElementLoad(broker());
1945 0 : }
1946 :
1947 0 : void MapRef::SerializeForElementStore() {
1948 0 : CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
1949 0 : data()->AsMap()->SerializeForElementStore(broker());
1950 0 : }
1951 :
1952 : namespace {
1953 : // This helper function has two modes. If {prototype_maps} is nullptr, the
1954 : // prototype chain is serialized as necessary to determine the result.
1955 : // Otherwise, the heap is untouched and the encountered prototypes are pushed
1956 : // onto {prototype_maps}.
1957 0 : bool HasOnlyStablePrototypesWithFastElementsHelper(
1958 : JSHeapBroker* broker, MapRef const& map,
1959 : ZoneVector<MapRef>* prototype_maps) {
1960 0 : for (MapRef prototype_map = map;;) {
1961 0 : if (prototype_maps == nullptr) prototype_map.SerializePrototype();
1962 0 : prototype_map = prototype_map.prototype().AsHeapObject().map();
1963 0 : if (prototype_map.oddball_type() == OddballType::kNull) return true;
1964 0 : if (!map.prototype().IsJSObject() || !prototype_map.is_stable() ||
1965 0 : !IsFastElementsKind(prototype_map.elements_kind())) {
1966 : return false;
1967 : }
1968 0 : if (prototype_maps != nullptr) prototype_maps->push_back(prototype_map);
1969 : }
1970 : }
1971 : } // namespace
1972 :
1973 0 : void MapData::SerializeForElementLoad(JSHeapBroker* broker) {
1974 0 : if (serialized_for_element_load_) return;
1975 0 : serialized_for_element_load_ = true;
1976 :
1977 0 : TraceScope tracer(broker, this, "MapData::SerializeForElementLoad");
1978 0 : SerializePrototype(broker);
1979 : }
1980 :
1981 0 : void MapData::SerializeForElementStore(JSHeapBroker* broker) {
1982 0 : if (serialized_for_element_store_) return;
1983 0 : serialized_for_element_store_ = true;
1984 :
1985 0 : TraceScope tracer(broker, this, "MapData::SerializeForElementStore");
1986 0 : HasOnlyStablePrototypesWithFastElementsHelper(broker, MapRef(broker, this),
1987 0 : nullptr);
1988 : }
1989 :
1990 1957 : bool MapRef::HasOnlyStablePrototypesWithFastElements(
1991 : ZoneVector<MapRef>* prototype_maps) {
1992 1957 : for (MapRef prototype_map = *this;;) {
1993 5766 : if (prototype_maps == nullptr) prototype_map.SerializePrototype();
1994 5766 : prototype_map = prototype_map.prototype().AsHeapObject().map();
1995 5766 : if (prototype_map.oddball_type() == OddballType::kNull) return true;
1996 11441 : if (!prototype().IsJSObject() || !prototype_map.is_stable() ||
1997 3809 : !IsFastElementsKind(prototype_map.elements_kind())) {
1998 : return false;
1999 : }
2000 3809 : if (prototype_maps != nullptr) prototype_maps->push_back(prototype_map);
2001 : }
2002 : }
2003 :
2004 3805 : bool MapRef::supports_fast_array_iteration() const {
2005 3805 : if (broker()->mode() == JSHeapBroker::kDisabled) {
2006 : AllowHandleDereference allow_handle_dereference;
2007 : AllowHandleAllocation handle_allocation;
2008 3805 : return SupportsFastArrayIteration(broker()->isolate(), object());
2009 : }
2010 0 : return data()->AsMap()->supports_fast_array_iteration();
2011 : }
2012 :
2013 3388 : bool MapRef::supports_fast_array_resize() const {
2014 3388 : if (broker()->mode() == JSHeapBroker::kDisabled) {
2015 : AllowHandleDereference allow_handle_dereference;
2016 : AllowHandleAllocation handle_allocation;
2017 3388 : return SupportsFastArrayResize(broker()->isolate(), object());
2018 : }
2019 0 : return data()->AsMap()->supports_fast_array_resize();
2020 : }
2021 :
2022 5058 : int JSFunctionRef::InitialMapInstanceSizeWithMinSlack() const {
2023 5058 : if (broker()->mode() == JSHeapBroker::kDisabled) {
2024 : AllowHandleDereference allow_handle_dereference;
2025 : AllowHandleAllocation handle_allocation;
2026 1 : return object()->ComputeInstanceSizeWithMinSlack(broker()->isolate());
2027 : }
2028 10114 : return data()->AsJSFunction()->initial_map_instance_size_with_min_slack();
2029 : }
2030 :
2031 : // Not needed for TypedLowering.
2032 : base::Optional<ScriptContextTableRef::LookupResult>
2033 0 : ScriptContextTableRef::lookup(const NameRef& name) const {
2034 : AllowHandleAllocation handle_allocation;
2035 : AllowHandleDereference handle_dereference;
2036 0 : if (!name.IsString()) return {};
2037 : ScriptContextTable::LookupResult lookup_result;
2038 : auto table = object();
2039 0 : if (!ScriptContextTable::Lookup(broker()->isolate(), *table,
2040 0 : *name.AsString().object(), &lookup_result)) {
2041 0 : return {};
2042 : }
2043 : Handle<Context> script_context = ScriptContextTable::GetContext(
2044 0 : broker()->isolate(), table, lookup_result.context_index);
2045 : LookupResult result{ContextRef(broker(), script_context),
2046 0 : lookup_result.mode == VariableMode::kConst,
2047 0 : lookup_result.slot_index};
2048 : return result;
2049 : }
2050 :
2051 16896402 : OddballType MapRef::oddball_type() const {
2052 16896402 : if (instance_type() != ODDBALL_TYPE) {
2053 : return OddballType::kNone;
2054 : }
2055 : Factory* f = broker()->isolate()->factory();
2056 10281767 : if (equals(MapRef(broker(), f->undefined_map()))) {
2057 : return OddballType::kUndefined;
2058 : }
2059 9350619 : if (equals(MapRef(broker(), f->null_map()))) {
2060 : return OddballType::kNull;
2061 : }
2062 9315781 : if (equals(MapRef(broker(), f->boolean_map()))) {
2063 : return OddballType::kBoolean;
2064 : }
2065 2519115 : if (equals(MapRef(broker(), f->the_hole_map()))) {
2066 : return OddballType::kHole;
2067 : }
2068 930806 : if (equals(MapRef(broker(), f->uninitialized_map()))) {
2069 : return OddballType::kUninitialized;
2070 : }
2071 : DCHECK(equals(MapRef(broker(), f->termination_exception_map())) ||
2072 : equals(MapRef(broker(), f->arguments_marker_map())) ||
2073 : equals(MapRef(broker(), f->optimized_out_map())) ||
2074 : equals(MapRef(broker(), f->stale_register_map())));
2075 928935 : return OddballType::kOther;
2076 : }
2077 :
2078 52305 : ObjectRef FeedbackVectorRef::get(FeedbackSlot slot) const {
2079 52305 : if (broker()->mode() == JSHeapBroker::kDisabled) {
2080 : AllowHandleAllocation handle_allocation;
2081 : AllowHandleDereference handle_dereference;
2082 : Handle<Object> value(object()->Get(slot)->cast<Object>(),
2083 : broker()->isolate());
2084 0 : return ObjectRef(broker(), value);
2085 : }
2086 : int i = FeedbackVector::GetIndex(slot);
2087 156915 : return ObjectRef(broker(), data()->AsFeedbackVector()->feedback().at(i));
2088 : }
2089 :
2090 0 : double JSObjectRef::RawFastDoublePropertyAt(FieldIndex index) const {
2091 0 : if (broker()->mode() == JSHeapBroker::kDisabled) {
2092 : AllowHandleDereference handle_dereference;
2093 : return object()->RawFastDoublePropertyAt(index);
2094 : }
2095 0 : JSObjectData* object_data = data()->AsJSObject();
2096 0 : CHECK(index.is_inobject());
2097 0 : return object_data->GetInobjectField(index.property_index()).AsDouble();
2098 : }
2099 :
2100 3274 : ObjectRef JSObjectRef::RawFastPropertyAt(FieldIndex index) const {
2101 3274 : if (broker()->mode() == JSHeapBroker::kDisabled) {
2102 : AllowHandleAllocation handle_allocation;
2103 : AllowHandleDereference handle_dereference;
2104 : return ObjectRef(broker(), handle(object()->RawFastPropertyAt(index),
2105 0 : broker()->isolate()));
2106 : }
2107 3274 : JSObjectData* object_data = data()->AsJSObject();
2108 3274 : CHECK(index.is_inobject());
2109 : return ObjectRef(
2110 : broker(),
2111 6548 : object_data->GetInobjectField(index.property_index()).AsObject());
2112 : }
2113 :
2114 5993 : bool AllocationSiteRef::IsFastLiteral() const {
2115 5993 : if (broker()->mode() == JSHeapBroker::kDisabled) {
2116 : AllowHeapAllocation allow_heap_allocation; // For TryMigrateInstance.
2117 : AllowHandleAllocation allow_handle_allocation;
2118 : AllowHandleDereference allow_handle_dereference;
2119 : return IsInlinableFastLiteral(
2120 : handle(object()->boilerplate(), broker()->isolate()));
2121 : }
2122 5993 : return data()->AsAllocationSite()->IsFastLiteral();
2123 : }
2124 :
2125 40 : void JSObjectRef::EnsureElementsTenured() {
2126 40 : if (broker()->mode() == JSHeapBroker::kDisabled) {
2127 : AllowHandleAllocation allow_handle_allocation;
2128 : AllowHandleDereference allow_handle_dereference;
2129 : AllowHeapAllocation allow_heap_allocation;
2130 :
2131 0 : Handle<FixedArrayBase> object_elements = elements().object();
2132 0 : if (ObjectInYoungGeneration(*object_elements)) {
2133 : // If we would like to pretenure a fixed cow array, we must ensure that
2134 : // the array is already in old space, otherwise we'll create too many
2135 : // old-to-new-space pointers (overflowing the store buffer).
2136 : object_elements =
2137 : broker()->isolate()->factory()->CopyAndTenureFixedCOWArray(
2138 0 : Handle<FixedArray>::cast(object_elements));
2139 0 : object()->set_elements(*object_elements);
2140 : }
2141 : return;
2142 : }
2143 80 : CHECK(data()->AsJSObject()->cow_or_empty_elements_tenured());
2144 : }
2145 :
2146 3274 : FieldIndex MapRef::GetFieldIndexFor(int descriptor_index) const {
2147 3274 : if (broker()->mode() == JSHeapBroker::kDisabled) {
2148 : AllowHandleDereference allow_handle_dereference;
2149 0 : return FieldIndex::ForDescriptor(*object(), descriptor_index);
2150 : }
2151 3274 : DescriptorArrayData* descriptors = data()->AsMap()->instance_descriptors();
2152 6548 : return descriptors->contents().at(descriptor_index).field_index;
2153 : }
2154 :
2155 32800 : int MapRef::GetInObjectPropertyOffset(int i) const {
2156 32800 : if (broker()->mode() == JSHeapBroker::kDisabled) {
2157 : AllowHandleDereference allow_handle_dereference;
2158 : return object()->GetInObjectPropertyOffset(i);
2159 : }
2160 32796 : return (GetInObjectPropertiesStartInWords() + i) * kTaggedSize;
2161 : }
2162 :
2163 76207 : PropertyDetails MapRef::GetPropertyDetails(int descriptor_index) const {
2164 76207 : if (broker()->mode() == JSHeapBroker::kDisabled) {
2165 : AllowHandleDereference allow_handle_dereference;
2166 68914 : return object()->instance_descriptors()->GetDetails(descriptor_index);
2167 : }
2168 7293 : DescriptorArrayData* descriptors = data()->AsMap()->instance_descriptors();
2169 14586 : return descriptors->contents().at(descriptor_index).details;
2170 : }
2171 :
2172 3274 : NameRef MapRef::GetPropertyKey(int descriptor_index) const {
2173 3274 : if (broker()->mode() == JSHeapBroker::kDisabled) {
2174 : AllowHandleAllocation handle_allocation;
2175 : AllowHandleDereference allow_handle_dereference;
2176 : return NameRef(
2177 : broker(),
2178 0 : handle(object()->instance_descriptors()->GetKey(descriptor_index),
2179 0 : broker()->isolate()));
2180 : }
2181 3274 : DescriptorArrayData* descriptors = data()->AsMap()->instance_descriptors();
2182 9822 : return NameRef(broker(), descriptors->contents().at(descriptor_index).key);
2183 : }
2184 :
2185 4095 : bool MapRef::IsFixedCowArrayMap() const {
2186 : Handle<Map> fixed_cow_array_map =
2187 : ReadOnlyRoots(broker()->isolate()).fixed_cow_array_map_handle();
2188 4095 : return equals(MapRef(broker(), fixed_cow_array_map));
2189 : }
2190 :
2191 109567 : bool MapRef::IsPrimitiveMap() const {
2192 117449 : return instance_type() <= LAST_PRIMITIVE_TYPE;
2193 : }
2194 :
2195 73409 : MapRef MapRef::FindFieldOwner(int descriptor_index) const {
2196 73409 : if (broker()->mode() == JSHeapBroker::kDisabled) {
2197 : AllowHandleAllocation handle_allocation;
2198 : AllowHandleDereference allow_handle_dereference;
2199 : Handle<Map> owner(
2200 : object()->FindFieldOwner(broker()->isolate(), descriptor_index),
2201 146786 : broker()->isolate());
2202 73393 : return MapRef(broker(), owner);
2203 : }
2204 16 : DescriptorArrayData* descriptors = data()->AsMap()->instance_descriptors();
2205 : return MapRef(broker(),
2206 48 : descriptors->contents().at(descriptor_index).field_owner);
2207 : }
2208 :
2209 4495 : ObjectRef MapRef::GetFieldType(int descriptor_index) const {
2210 4495 : if (broker()->mode() == JSHeapBroker::kDisabled) {
2211 : AllowHandleAllocation handle_allocation;
2212 : AllowHandleDereference allow_handle_dereference;
2213 : Handle<FieldType> field_type(
2214 8958 : object()->instance_descriptors()->GetFieldType(descriptor_index),
2215 : broker()->isolate());
2216 4479 : return ObjectRef(broker(), field_type);
2217 : }
2218 16 : DescriptorArrayData* descriptors = data()->AsMap()->instance_descriptors();
2219 : return ObjectRef(broker(),
2220 48 : descriptors->contents().at(descriptor_index).field_type);
2221 : }
2222 :
2223 3274 : bool MapRef::IsUnboxedDoubleField(int descriptor_index) const {
2224 3274 : if (broker()->mode() == JSHeapBroker::kDisabled) {
2225 : AllowHandleDereference allow_handle_dereference;
2226 0 : return object()->IsUnboxedDoubleField(
2227 : FieldIndex::ForDescriptor(*object(), descriptor_index));
2228 : }
2229 3274 : DescriptorArrayData* descriptors = data()->AsMap()->instance_descriptors();
2230 6548 : return descriptors->contents().at(descriptor_index).is_unboxed_double_field;
2231 : }
2232 :
2233 108 : uint16_t StringRef::GetFirstChar() {
2234 108 : if (broker()->mode() == JSHeapBroker::kDisabled) {
2235 : AllowHandleDereference allow_handle_dereference;
2236 : return object()->Get(0);
2237 : }
2238 108 : return data()->AsString()->first_char();
2239 : }
2240 :
2241 841 : base::Optional<double> StringRef::ToNumber() {
2242 841 : if (broker()->mode() == JSHeapBroker::kDisabled) {
2243 : AllowHandleDereference allow_handle_dereference;
2244 : AllowHandleAllocation allow_handle_allocation;
2245 : AllowHeapAllocation allow_heap_allocation;
2246 : int flags = ALLOW_HEX | ALLOW_OCTAL | ALLOW_BINARY;
2247 0 : return StringToDouble(broker()->isolate(), object(), flags);
2248 : }
2249 841 : return data()->AsString()->to_number();
2250 : }
2251 :
2252 449 : uint32_t InternalizedStringRef::array_index() const {
2253 449 : if (broker()->mode() == JSHeapBroker::kDisabled) {
2254 : AllowHandleDereference allow_handle_dereference;
2255 : AllowHandleAllocation allow_handle_allocation;
2256 : uint32_t result;
2257 449 : if (!object()->AsArrayIndex(&result)) {
2258 449 : result = kNotAnArrayIndex;
2259 : }
2260 449 : return result;
2261 : }
2262 0 : return data()->AsInternalizedString()->array_index();
2263 : }
2264 :
2265 6779 : ObjectRef FixedArrayRef::get(int i) const {
2266 6779 : if (broker()->mode() == JSHeapBroker::kDisabled) {
2267 : AllowHandleAllocation handle_allocation;
2268 : AllowHandleDereference allow_handle_dereference;
2269 208 : return ObjectRef(broker(), handle(object()->get(i), broker()->isolate()));
2270 : }
2271 13142 : return ObjectRef(broker(), data()->AsFixedArray()->Get(i));
2272 : }
2273 :
2274 7195 : bool FixedDoubleArrayRef::is_the_hole(int i) const {
2275 7195 : if (broker()->mode() == JSHeapBroker::kDisabled) {
2276 : AllowHandleDereference allow_handle_dereference;
2277 : return object()->is_the_hole(i);
2278 : }
2279 14390 : return data()->AsFixedDoubleArray()->Get(i).is_hole_nan();
2280 : }
2281 :
2282 7096 : double FixedDoubleArrayRef::get_scalar(int i) const {
2283 7096 : if (broker()->mode() == JSHeapBroker::kDisabled) {
2284 : AllowHandleDereference allow_handle_dereference;
2285 : return object()->get_scalar(i);
2286 : }
2287 14192 : CHECK(!data()->AsFixedDoubleArray()->Get(i).is_hole_nan());
2288 7096 : return data()->AsFixedDoubleArray()->Get(i).get_scalar();
2289 : }
2290 :
2291 : #define IF_BROKER_DISABLED_ACCESS_HANDLE_C(holder, name) \
2292 : if (broker()->mode() == JSHeapBroker::kDisabled) { \
2293 : AllowHandleAllocation handle_allocation; \
2294 : AllowHandleDereference allow_handle_dereference; \
2295 : return object()->name(); \
2296 : }
2297 :
2298 : #define IF_BROKER_DISABLED_ACCESS_HANDLE(holder, result, name) \
2299 : if (broker()->mode() == JSHeapBroker::kDisabled) { \
2300 : AllowHandleAllocation handle_allocation; \
2301 : AllowHandleDereference allow_handle_dereference; \
2302 : return result##Ref(broker(), \
2303 : handle(object()->name(), broker()->isolate())); \
2304 : }
2305 :
2306 : // Macros for definining a const getter that, depending on the broker mode,
2307 : // either looks into the handle or into the serialized data.
2308 : #define BIMODAL_ACCESSOR(holder, result, name) \
2309 : result##Ref holder##Ref::name() const { \
2310 : IF_BROKER_DISABLED_ACCESS_HANDLE(holder, result, name); \
2311 : return result##Ref(broker(), ObjectRef::data()->As##holder()->name()); \
2312 : }
2313 :
2314 : // Like above except that the result type is not an XYZRef.
2315 : #define BIMODAL_ACCESSOR_C(holder, result, name) \
2316 : result holder##Ref::name() const { \
2317 : IF_BROKER_DISABLED_ACCESS_HANDLE_C(holder, name); \
2318 : return ObjectRef::data()->As##holder()->name(); \
2319 : }
2320 :
2321 : // Like above but for BitFields.
2322 : #define BIMODAL_ACCESSOR_B(holder, field, name, BitField) \
2323 : typename BitField::FieldType holder##Ref::name() const { \
2324 : IF_BROKER_DISABLED_ACCESS_HANDLE_C(holder, name); \
2325 : return BitField::decode(ObjectRef::data()->As##holder()->field()); \
2326 : }
2327 :
2328 36132 : BIMODAL_ACCESSOR(AllocationSite, Object, nested_site)
2329 1524 : BIMODAL_ACCESSOR_C(AllocationSite, bool, CanInlineCall)
2330 22494 : BIMODAL_ACCESSOR_C(AllocationSite, bool, PointsToLiteral)
2331 8856 : BIMODAL_ACCESSOR_C(AllocationSite, ElementsKind, GetElementsKind)
2332 14500 : BIMODAL_ACCESSOR_C(AllocationSite, AllocationType, GetAllocationType)
2333 :
2334 1545 : BIMODAL_ACCESSOR_C(BytecodeArray, int, register_count)
2335 :
2336 75027 : BIMODAL_ACCESSOR(Cell, Object, value)
2337 :
2338 203423382 : BIMODAL_ACCESSOR(HeapObject, Map, map)
2339 :
2340 12057 : BIMODAL_ACCESSOR(JSArray, Object, length)
2341 :
2342 666 : BIMODAL_ACCESSOR(JSBoundFunction, Object, bound_target_function)
2343 501 : BIMODAL_ACCESSOR(JSBoundFunction, Object, bound_this)
2344 666 : BIMODAL_ACCESSOR(JSBoundFunction, FixedArray, bound_arguments)
2345 :
2346 848 : BIMODAL_ACCESSOR_C(JSDataView, size_t, byte_length)
2347 424 : BIMODAL_ACCESSOR_C(JSDataView, size_t, byte_offset)
2348 :
2349 0 : BIMODAL_ACCESSOR_C(JSFunction, bool, has_feedback_vector)
2350 21044 : BIMODAL_ACCESSOR_C(JSFunction, bool, has_initial_map)
2351 4758 : BIMODAL_ACCESSOR_C(JSFunction, bool, has_prototype)
2352 4368 : BIMODAL_ACCESSOR_C(JSFunction, bool, PrototypeRequiresRuntimeLookup)
2353 4788 : BIMODAL_ACCESSOR(JSFunction, Context, context)
2354 1001846 : BIMODAL_ACCESSOR(JSFunction, NativeContext, native_context)
2355 86463 : BIMODAL_ACCESSOR(JSFunction, Map, initial_map)
2356 5276 : BIMODAL_ACCESSOR(JSFunction, Object, prototype)
2357 911751 : BIMODAL_ACCESSOR(JSFunction, SharedFunctionInfo, shared)
2358 177 : BIMODAL_ACCESSOR(JSFunction, FeedbackVector, feedback_vector)
2359 :
2360 12516 : BIMODAL_ACCESSOR_C(JSTypedArray, bool, is_on_heap)
2361 2654 : BIMODAL_ACCESSOR_C(JSTypedArray, size_t, length_value)
2362 3981 : BIMODAL_ACCESSOR(JSTypedArray, HeapObject, buffer)
2363 :
2364 2152279 : BIMODAL_ACCESSOR_B(Map, bit_field2, elements_kind, Map::ElementsKindBits)
2365 0 : BIMODAL_ACCESSOR_B(Map, bit_field2, is_extensible, Map::IsExtensibleBit)
2366 0 : BIMODAL_ACCESSOR_B(Map, bit_field3, is_deprecated, Map::IsDeprecatedBit)
2367 400 : BIMODAL_ACCESSOR_B(Map, bit_field3, is_dictionary_map, Map::IsDictionaryMapBit)
2368 25936 : BIMODAL_ACCESSOR_B(Map, bit_field3, NumberOfOwnDescriptors,
2369 : Map::NumberOfOwnDescriptorsBits)
2370 296 : BIMODAL_ACCESSOR_B(Map, bit_field3, has_hidden_prototype,
2371 : Map::HasHiddenPrototypeBit)
2372 184984 : BIMODAL_ACCESSOR_B(Map, bit_field3, is_migration_target,
2373 : Map::IsMigrationTargetBit)
2374 155776 : BIMODAL_ACCESSOR_B(Map, bit_field, has_prototype_slot, Map::HasPrototypeSlotBit)
2375 104618 : BIMODAL_ACCESSOR_B(Map, bit_field, is_access_check_needed,
2376 : Map::IsAccessCheckNeededBit)
2377 66788634 : BIMODAL_ACCESSOR_B(Map, bit_field, is_callable, Map::IsCallableBit)
2378 101354 : BIMODAL_ACCESSOR_B(Map, bit_field, has_indexed_interceptor,
2379 : Map::HasIndexedInterceptorBit)
2380 42050 : BIMODAL_ACCESSOR_B(Map, bit_field, is_constructor, Map::IsConstructorBit)
2381 66760268 : BIMODAL_ACCESSOR_B(Map, bit_field, is_undetectable, Map::IsUndetectableBit)
2382 141032 : BIMODAL_ACCESSOR_C(Map, int, instance_size)
2383 6894 : BIMODAL_ACCESSOR_C(Map, int, NextFreePropertyIndex)
2384 0 : BIMODAL_ACCESSOR_C(Map, int, UnusedPropertyFields)
2385 299673 : BIMODAL_ACCESSOR(Map, Object, prototype)
2386 101990174 : BIMODAL_ACCESSOR_C(Map, InstanceType, instance_type)
2387 27522 : BIMODAL_ACCESSOR(Map, Object, GetConstructor)
2388 :
2389 : #define DEF_NATIVE_CONTEXT_ACCESSOR(type, name) \
2390 : BIMODAL_ACCESSOR(NativeContext, type, name)
2391 204666 : BROKER_NATIVE_CONTEXT_FIELDS(DEF_NATIVE_CONTEXT_ACCESSOR)
2392 : #undef DEF_NATIVE_CONTEXT_ACCESSOR
2393 :
2394 640428 : BIMODAL_ACCESSOR(PropertyCell, Object, value)
2395 1122750 : BIMODAL_ACCESSOR_C(PropertyCell, PropertyDetails, property_details)
2396 :
2397 257152 : BIMODAL_ACCESSOR_C(SharedFunctionInfo, int, builtin_id)
2398 1545 : BIMODAL_ACCESSOR(SharedFunctionInfo, BytecodeArray, GetBytecodeArray)
2399 : #define DEF_SFI_ACCESSOR(type, name) \
2400 : BIMODAL_ACCESSOR_C(SharedFunctionInfo, type, name)
2401 2826059 : BROKER_SFI_FIELDS(DEF_SFI_ACCESSOR)
2402 : #undef DEF_SFI_ACCESSOR
2403 :
2404 163716 : BIMODAL_ACCESSOR_C(String, int, length)
2405 :
2406 1327 : void* JSTypedArrayRef::elements_external_pointer() const {
2407 1327 : if (broker()->mode() == JSHeapBroker::kDisabled) {
2408 : AllowHandleDereference allow_handle_dereference;
2409 : return FixedTypedArrayBase::cast(object()->elements())->external_pointer();
2410 : }
2411 0 : return data()->AsJSTypedArray()->elements_external_pointer();
2412 : }
2413 :
2414 32 : bool MapRef::IsInobjectSlackTrackingInProgress() const {
2415 32 : IF_BROKER_DISABLED_ACCESS_HANDLE_C(Map, IsInobjectSlackTrackingInProgress);
2416 32 : return Map::ConstructionCounterBits::decode(data()->AsMap()->bit_field3()) !=
2417 32 : Map::kNoSlackTracking;
2418 : }
2419 :
2420 7882 : int MapRef::constructor_function_index() const {
2421 7882 : IF_BROKER_DISABLED_ACCESS_HANDLE_C(Map, GetConstructorFunctionIndex);
2422 0 : CHECK(IsPrimitiveMap());
2423 0 : return data()->AsMap()->constructor_function_index();
2424 : }
2425 :
2426 225391 : bool MapRef::is_stable() const {
2427 225391 : IF_BROKER_DISABLED_ACCESS_HANDLE_C(Map, is_stable);
2428 27808 : return !Map::IsUnstableBit::decode(data()->AsMap()->bit_field3());
2429 : }
2430 :
2431 21490 : bool MapRef::CanBeDeprecated() const {
2432 42980 : IF_BROKER_DISABLED_ACCESS_HANDLE_C(Map, CanBeDeprecated);
2433 0 : CHECK_GT(NumberOfOwnDescriptors(), 0);
2434 0 : return data()->AsMap()->can_be_deprecated();
2435 : }
2436 :
2437 160811 : bool MapRef::CanTransition() const {
2438 160811 : IF_BROKER_DISABLED_ACCESS_HANDLE_C(Map, CanTransition);
2439 37 : return data()->AsMap()->can_transition();
2440 : }
2441 :
2442 38822 : int MapRef::GetInObjectPropertiesStartInWords() const {
2443 38822 : IF_BROKER_DISABLED_ACCESS_HANDLE_C(Map, GetInObjectPropertiesStartInWords);
2444 77642 : return data()->AsMap()->in_object_properties_start_in_words();
2445 : }
2446 :
2447 77326 : int MapRef::GetInObjectProperties() const {
2448 79760 : IF_BROKER_DISABLED_ACCESS_HANDLE_C(Map, GetInObjectProperties);
2449 149784 : return data()->AsMap()->in_object_properties();
2450 : }
2451 :
2452 9296 : int ScopeInfoRef::ContextLength() const {
2453 9296 : IF_BROKER_DISABLED_ACCESS_HANDLE_C(ScopeInfo, ContextLength);
2454 9296 : return data()->AsScopeInfo()->context_length();
2455 : }
2456 :
2457 0 : bool StringRef::IsExternalString() const {
2458 0 : IF_BROKER_DISABLED_ACCESS_HANDLE_C(String, IsExternalString);
2459 0 : return data()->AsString()->is_external_string();
2460 : }
2461 :
2462 0 : bool StringRef::IsSeqString() const {
2463 0 : IF_BROKER_DISABLED_ACCESS_HANDLE_C(String, IsSeqString);
2464 0 : return data()->AsString()->is_seq_string();
2465 : }
2466 :
2467 31995 : MapRef NativeContextRef::GetFunctionMapFromIndex(int index) const {
2468 : DCHECK_GE(index, Context::FIRST_FUNCTION_MAP_INDEX);
2469 : DCHECK_LE(index, Context::LAST_FUNCTION_MAP_INDEX);
2470 31995 : if (broker()->mode() == JSHeapBroker::kDisabled) {
2471 0 : return get(index).AsMap();
2472 : }
2473 31995 : return MapRef(broker(), data()->AsNativeContext()->function_maps().at(
2474 95985 : index - Context::FIRST_FUNCTION_MAP_INDEX));
2475 : }
2476 :
2477 2094 : MapRef NativeContextRef::GetInitialJSArrayMap(ElementsKind kind) const {
2478 2094 : switch (kind) {
2479 : case PACKED_SMI_ELEMENTS:
2480 904 : return js_array_packed_smi_elements_map();
2481 : case HOLEY_SMI_ELEMENTS:
2482 40 : return js_array_holey_smi_elements_map();
2483 : case PACKED_DOUBLE_ELEMENTS:
2484 42 : return js_array_packed_double_elements_map();
2485 : case HOLEY_DOUBLE_ELEMENTS:
2486 348 : return js_array_holey_double_elements_map();
2487 : case PACKED_ELEMENTS:
2488 430 : return js_array_packed_elements_map();
2489 : case HOLEY_ELEMENTS:
2490 330 : return js_array_holey_elements_map();
2491 : default:
2492 0 : UNREACHABLE();
2493 : }
2494 : }
2495 :
2496 7882 : base::Optional<JSFunctionRef> NativeContextRef::GetConstructorFunction(
2497 : const MapRef& map) const {
2498 7882 : CHECK(map.IsPrimitiveMap());
2499 7882 : switch (map.constructor_function_index()) {
2500 : case Map::kNoConstructorFunctionIndex:
2501 : return base::nullopt;
2502 : case Context::BIGINT_FUNCTION_INDEX:
2503 0 : return bigint_function();
2504 : case Context::BOOLEAN_FUNCTION_INDEX:
2505 1050 : return boolean_function();
2506 : case Context::NUMBER_FUNCTION_INDEX:
2507 2766 : return number_function();
2508 : case Context::STRING_FUNCTION_INDEX:
2509 11878 : return string_function();
2510 : case Context::SYMBOL_FUNCTION_INDEX:
2511 70 : return symbol_function();
2512 : default:
2513 0 : UNREACHABLE();
2514 : }
2515 : }
2516 :
2517 167 : bool ObjectRef::IsNullOrUndefined() const {
2518 167 : if (IsSmi()) return false;
2519 167 : OddballType type = AsHeapObject().map().oddball_type();
2520 167 : return type == OddballType::kNull || type == OddballType::kUndefined;
2521 : }
2522 :
2523 121946 : bool ObjectRef::BooleanValue() const {
2524 121946 : if (broker()->mode() == JSHeapBroker::kDisabled) {
2525 : AllowHandleDereference allow_handle_dereference;
2526 9576 : return object()->BooleanValue(broker()->isolate());
2527 : }
2528 112370 : return IsSmi() ? (AsSmi() != 0) : data()->AsHeapObject()->boolean_value();
2529 : }
2530 :
2531 1085 : Maybe<double> ObjectRef::OddballToNumber() const {
2532 1085 : OddballType type = AsHeapObject().map().oddball_type();
2533 :
2534 1085 : switch (type) {
2535 : case OddballType::kBoolean: {
2536 : ObjectRef true_ref(broker(),
2537 493 : broker()->isolate()->factory()->true_value());
2538 493 : return this->equals(true_ref) ? Just(1.0) : Just(0.0);
2539 : break;
2540 : }
2541 : case OddballType::kUndefined: {
2542 : return Just(std::numeric_limits<double>::quiet_NaN());
2543 : break;
2544 : }
2545 : case OddballType::kNull: {
2546 : return Just(0.0);
2547 : break;
2548 : }
2549 : default: {
2550 : return Nothing<double>();
2551 : break;
2552 : }
2553 : }
2554 : }
2555 :
2556 2448507 : double HeapNumberRef::value() const {
2557 2448507 : IF_BROKER_DISABLED_ACCESS_HANDLE_C(HeapNumber, value);
2558 146 : return data()->AsHeapNumber()->value();
2559 : }
2560 :
2561 128 : double MutableHeapNumberRef::value() const {
2562 128 : IF_BROKER_DISABLED_ACCESS_HANDLE_C(MutableHeapNumber, value);
2563 128 : return data()->AsMutableHeapNumber()->value();
2564 : }
2565 :
2566 138 : CellRef ModuleRef::GetCell(int cell_index) const {
2567 138 : if (broker()->mode() == JSHeapBroker::kDisabled) {
2568 : AllowHandleAllocation handle_allocation;
2569 : AllowHandleDereference allow_handle_dereference;
2570 : return CellRef(broker(),
2571 0 : handle(object()->GetCell(cell_index), broker()->isolate()));
2572 : }
2573 276 : return CellRef(broker(), data()->AsModule()->GetCell(cell_index));
2574 : }
2575 :
2576 69730634 : ObjectRef::ObjectRef(JSHeapBroker* broker, Handle<Object> object)
2577 69730634 : : broker_(broker) {
2578 69730634 : switch (broker->mode()) {
2579 : case JSHeapBroker::kSerialized:
2580 51535983 : data_ = broker->GetData(object);
2581 51535983 : break;
2582 : case JSHeapBroker::kSerializing:
2583 8869464 : data_ = broker->GetOrCreateData(object);
2584 8869466 : break;
2585 : case JSHeapBroker::kDisabled: {
2586 : RefsMap::Entry* entry =
2587 9325878 : broker->refs_->LookupOrInsert(object.address(), broker->zone());
2588 9325885 : ObjectData** storage = &(entry->value);
2589 9325885 : if (*storage == nullptr) {
2590 : AllowHandleDereference handle_dereference;
2591 : entry->value = new (broker->zone())
2592 : ObjectData(broker, storage, object,
2593 4183110 : object->IsSmi() ? kSmi : kUnserializedHeapObject);
2594 : }
2595 9325885 : data_ = *storage;
2596 9325885 : break;
2597 : }
2598 : case JSHeapBroker::kRetired:
2599 0 : UNREACHABLE();
2600 : }
2601 69731046 : CHECK_WITH_MSG(data_ != nullptr, "Object is not known to the heap broker");
2602 69731046 : }
2603 :
2604 : namespace {
2605 2480704 : OddballType GetOddballType(Isolate* isolate, Map map) {
2606 2480704 : if (map->instance_type() != ODDBALL_TYPE) {
2607 : return OddballType::kNone;
2608 : }
2609 : ReadOnlyRoots roots(isolate);
2610 541145 : if (map == roots.undefined_map()) {
2611 : return OddballType::kUndefined;
2612 : }
2613 503267 : if (map == roots.null_map()) {
2614 : return OddballType::kNull;
2615 : }
2616 503082 : if (map == roots.boolean_map()) {
2617 : return OddballType::kBoolean;
2618 : }
2619 489214 : if (map == roots.the_hole_map()) {
2620 : return OddballType::kHole;
2621 : }
2622 488535 : if (map == roots.uninitialized_map()) {
2623 : return OddballType::kUninitialized;
2624 : }
2625 : DCHECK(map == roots.termination_exception_map() ||
2626 : map == roots.arguments_marker_map() ||
2627 : map == roots.optimized_out_map() || map == roots.stale_register_map());
2628 0 : return OddballType::kOther;
2629 : }
2630 : } // namespace
2631 :
2632 19167794 : HeapObjectType HeapObjectRef::GetHeapObjectType() const {
2633 19167794 : if (broker()->mode() == JSHeapBroker::kDisabled) {
2634 : AllowHandleDereference handle_dereference;
2635 : Map map = Handle<HeapObject>::cast(object())->map();
2636 : HeapObjectType::Flags flags(0);
2637 2480704 : if (map->is_undetectable()) flags |= HeapObjectType::kUndetectable;
2638 2480704 : if (map->is_callable()) flags |= HeapObjectType::kCallable;
2639 : return HeapObjectType(map->instance_type(), flags,
2640 4961408 : GetOddballType(broker()->isolate(), map));
2641 : }
2642 : HeapObjectType::Flags flags(0);
2643 16687090 : if (map().is_undetectable()) flags |= HeapObjectType::kUndetectable;
2644 16687063 : if (map().is_callable()) flags |= HeapObjectType::kCallable;
2645 16687058 : return HeapObjectType(map().instance_type(), flags, map().oddball_type());
2646 : }
2647 11796 : base::Optional<JSObjectRef> AllocationSiteRef::boilerplate() const {
2648 11796 : if (broker()->mode() == JSHeapBroker::kDisabled) {
2649 : AllowHandleAllocation handle_allocation;
2650 : AllowHandleDereference allow_handle_dereference;
2651 : return JSObjectRef(broker(),
2652 0 : handle(object()->boilerplate(), broker()->isolate()));
2653 : }
2654 11796 : JSObjectData* boilerplate = data()->AsAllocationSite()->boilerplate();
2655 11796 : if (boilerplate) {
2656 : return JSObjectRef(broker(), boilerplate);
2657 : } else {
2658 : return base::nullopt;
2659 : }
2660 : }
2661 :
2662 10041 : ElementsKind JSObjectRef::GetElementsKind() const {
2663 10041 : return map().elements_kind();
2664 : }
2665 :
2666 7106 : FixedArrayBaseRef JSObjectRef::elements() const {
2667 7106 : if (broker()->mode() == JSHeapBroker::kDisabled) {
2668 : AllowHandleAllocation handle_allocation;
2669 : AllowHandleDereference allow_handle_dereference;
2670 : return FixedArrayBaseRef(broker(),
2671 0 : handle(object()->elements(), broker()->isolate()));
2672 : }
2673 14212 : return FixedArrayBaseRef(broker(), data()->AsJSObject()->elements());
2674 : }
2675 :
2676 13398 : int FixedArrayBaseRef::length() const {
2677 13398 : IF_BROKER_DISABLED_ACCESS_HANDLE_C(FixedArrayBase, length);
2678 12968 : return data()->AsFixedArrayBase()->length();
2679 : }
2680 :
2681 6571 : ObjectData* FixedArrayData::Get(int i) const {
2682 6571 : CHECK_LT(i, static_cast<int>(contents_.size()));
2683 13142 : CHECK_NOT_NULL(contents_[i]);
2684 6571 : return contents_[i];
2685 : }
2686 :
2687 21387 : Float64 FixedDoubleArrayData::Get(int i) const {
2688 21387 : CHECK_LT(i, static_cast<int>(contents_.size()));
2689 42774 : return contents_[i];
2690 : }
2691 :
2692 52495 : void FeedbackVectorRef::SerializeSlots() {
2693 52495 : data()->AsFeedbackVector()->SerializeSlots(broker());
2694 52496 : }
2695 :
2696 582 : ObjectRef JSRegExpRef::data() const {
2697 582 : IF_BROKER_DISABLED_ACCESS_HANDLE(JSRegExp, Object, data);
2698 1164 : return ObjectRef(broker(), ObjectRef::data()->AsJSRegExp()->data());
2699 : }
2700 :
2701 582 : ObjectRef JSRegExpRef::flags() const {
2702 582 : IF_BROKER_DISABLED_ACCESS_HANDLE(JSRegExp, Object, flags);
2703 1164 : return ObjectRef(broker(), ObjectRef::data()->AsJSRegExp()->flags());
2704 : }
2705 :
2706 582 : ObjectRef JSRegExpRef::last_index() const {
2707 582 : IF_BROKER_DISABLED_ACCESS_HANDLE(JSRegExp, Object, last_index);
2708 1164 : return ObjectRef(broker(), ObjectRef::data()->AsJSRegExp()->last_index());
2709 : }
2710 :
2711 582 : ObjectRef JSRegExpRef::raw_properties_or_hash() const {
2712 582 : IF_BROKER_DISABLED_ACCESS_HANDLE(JSRegExp, Object, raw_properties_or_hash);
2713 : return ObjectRef(broker(),
2714 1164 : ObjectRef::data()->AsJSRegExp()->raw_properties_or_hash());
2715 : }
2716 :
2717 582 : ObjectRef JSRegExpRef::source() const {
2718 582 : IF_BROKER_DISABLED_ACCESS_HANDLE(JSRegExp, Object, source);
2719 1164 : return ObjectRef(broker(), ObjectRef::data()->AsJSRegExp()->source());
2720 : }
2721 :
2722 859051 : Handle<Object> ObjectRef::object() const { return data_->object(); }
2723 :
2724 : #define DEF_OBJECT_GETTER(T) \
2725 : Handle<T> T##Ref::object() const { \
2726 : return Handle<T>(reinterpret_cast<Address*>(data_->object().address())); \
2727 : }
2728 38030213 : HEAP_BROKER_OBJECT_LIST(DEF_OBJECT_GETTER)
2729 : #undef DEF_OBJECT_GETTER
2730 :
2731 435118207 : JSHeapBroker* ObjectRef::broker() const { return broker_; }
2732 :
2733 214152239 : ObjectData* ObjectRef::data() const {
2734 214152239 : switch (broker()->mode()) {
2735 : case JSHeapBroker::kDisabled:
2736 20276292 : CHECK_NE(data_->kind(), kSerializedHeapObject);
2737 : return data_;
2738 : case JSHeapBroker::kSerializing:
2739 : case JSHeapBroker::kSerialized:
2740 193875947 : CHECK_NE(data_->kind(), kUnserializedHeapObject);
2741 : return data_;
2742 : case JSHeapBroker::kRetired:
2743 0 : UNREACHABLE();
2744 : }
2745 0 : }
2746 :
2747 0 : Reduction NoChangeBecauseOfMissingData(JSHeapBroker* broker,
2748 : const char* function, int line) {
2749 0 : if (FLAG_trace_heap_broker) {
2750 : PrintF("[%p] Skipping optimization in %s at line %d due to missing data\n",
2751 0 : broker, function, line);
2752 : }
2753 0 : return AdvancedReducer::NoChange();
2754 : }
2755 :
2756 463875 : NativeContextData::NativeContextData(JSHeapBroker* broker, ObjectData** storage,
2757 : Handle<NativeContext> object)
2758 927760 : : ContextData(broker, storage, object), function_maps_(broker->zone()) {}
2759 :
2760 463856 : void NativeContextData::Serialize(JSHeapBroker* broker) {
2761 463856 : if (serialized_) return;
2762 463856 : serialized_ = true;
2763 :
2764 463856 : TraceScope tracer(broker, this, "NativeContextData::Serialize");
2765 : Handle<NativeContext> context = Handle<NativeContext>::cast(object());
2766 :
2767 : #define SERIALIZE_MEMBER(type, name) \
2768 : DCHECK_NULL(name##_); \
2769 : name##_ = broker->GetOrCreateData(context->name())->As##type(); \
2770 : if (name##_->IsJSFunction()) name##_->AsJSFunction()->Serialize(broker); \
2771 : if (name##_->IsMap()) name##_->AsMap()->SerializeConstructor(broker);
2772 14380173 : BROKER_COMPULSORY_NATIVE_CONTEXT_FIELDS(SERIALIZE_MEMBER)
2773 463878 : if (!broker->isolate()->bootstrapper()->IsActive()) {
2774 2779242 : BROKER_OPTIONAL_NATIVE_CONTEXT_FIELDS(SERIALIZE_MEMBER)
2775 : }
2776 : #undef SERIALIZE_MEMBER
2777 :
2778 463878 : bound_function_with_constructor_map_->SerializePrototype(broker);
2779 463878 : bound_function_without_constructor_map_->SerializePrototype(broker);
2780 :
2781 : DCHECK(function_maps_.empty());
2782 : int const first = Context::FIRST_FUNCTION_MAP_INDEX;
2783 : int const last = Context::LAST_FUNCTION_MAP_INDEX;
2784 463878 : function_maps_.reserve(last + 1 - first);
2785 22729749 : for (int i = first; i <= last; ++i) {
2786 33398808 : function_maps_.push_back(broker->GetOrCreateData(context->get(i))->AsMap());
2787 : }
2788 : }
2789 :
2790 1255077 : void JSFunctionRef::Serialize() {
2791 1255077 : if (broker()->mode() == JSHeapBroker::kDisabled) return;
2792 1029279 : CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
2793 1029279 : data()->AsJSFunction()->Serialize(broker());
2794 : }
2795 :
2796 59 : bool JSFunctionRef::IsSerializedForCompilation() const {
2797 59 : return shared().IsSerializedForCompilation(feedback_vector());
2798 : }
2799 :
2800 147 : void SharedFunctionInfoRef::SetSerializedForCompilation(
2801 : FeedbackVectorRef feedback) {
2802 147 : CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
2803 147 : data()->AsSharedFunctionInfo()->SetSerializedForCompilation(broker(),
2804 147 : feedback);
2805 147 : }
2806 :
2807 324 : bool SharedFunctionInfoRef::IsSerializedForCompilation(
2808 : FeedbackVectorRef feedback) const {
2809 324 : CHECK_NE(broker()->mode(), JSHeapBroker::kDisabled);
2810 648 : return data()->AsSharedFunctionInfo()->IsSerializedForCompilation(feedback);
2811 : }
2812 :
2813 1138292 : void JSObjectRef::SerializeObjectCreateMap() {
2814 1138292 : if (broker()->mode() == JSHeapBroker::kDisabled) return;
2815 1138299 : CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
2816 1138299 : data()->AsJSObject()->SerializeObjectCreateMap(broker());
2817 : }
2818 :
2819 73345 : void MapRef::SerializeOwnDescriptors() {
2820 73345 : if (broker()->mode() == JSHeapBroker::kDisabled) return;
2821 16 : CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
2822 16 : data()->AsMap()->SerializeOwnDescriptors(broker());
2823 : }
2824 :
2825 90179 : void MapRef::SerializePrototype() {
2826 90179 : if (broker()->mode() == JSHeapBroker::kDisabled) return;
2827 0 : CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
2828 0 : data()->AsMap()->SerializePrototype(broker());
2829 : }
2830 :
2831 170 : void ModuleRef::Serialize() {
2832 170 : if (broker()->mode() == JSHeapBroker::kDisabled) return;
2833 170 : CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
2834 170 : data()->AsModule()->Serialize(broker());
2835 : }
2836 :
2837 1352688 : void ContextRef::SerializeContextChain() {
2838 1352688 : if (broker()->mode() == JSHeapBroker::kDisabled) return;
2839 1081546 : CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
2840 1081546 : data()->AsContext()->SerializeContextChain(broker());
2841 : }
2842 :
2843 26500 : void ContextRef::SerializeSlot(int index) {
2844 26500 : if (broker()->mode() == JSHeapBroker::kDisabled) return;
2845 16 : CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
2846 16 : data()->AsContext()->SerializeSlot(broker(), index);
2847 : }
2848 :
2849 463855 : void NativeContextRef::Serialize() {
2850 463855 : if (broker()->mode() == JSHeapBroker::kDisabled) return;
2851 463863 : CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
2852 463863 : data()->AsNativeContext()->Serialize(broker());
2853 : }
2854 :
2855 1327 : void JSTypedArrayRef::Serialize() {
2856 1327 : if (broker()->mode() == JSHeapBroker::kDisabled) return;
2857 0 : CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
2858 0 : data()->AsJSTypedArray()->Serialize(broker());
2859 : }
2860 :
2861 0 : bool JSTypedArrayRef::serialized() const {
2862 0 : CHECK_NE(broker()->mode(), JSHeapBroker::kDisabled);
2863 0 : return data()->AsJSTypedArray()->serialized();
2864 : }
2865 :
2866 222 : void JSBoundFunctionRef::Serialize() {
2867 222 : if (broker()->mode() == JSHeapBroker::kDisabled) return;
2868 0 : CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
2869 0 : data()->AsJSBoundFunction()->Serialize(broker());
2870 : }
2871 :
2872 192987 : void PropertyCellRef::Serialize() {
2873 192987 : if (broker()->mode() == JSHeapBroker::kDisabled) return;
2874 0 : CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
2875 0 : data()->AsPropertyCell()->Serialize(broker());
2876 : }
2877 :
2878 52316 : bool CanInlineElementAccess(MapRef const& map) {
2879 52316 : if (!map.IsJSObjectMap()) return false;
2880 50677 : if (map.is_access_check_needed()) return false;
2881 50677 : if (map.has_indexed_interceptor()) return false;
2882 50669 : ElementsKind const elements_kind = map.elements_kind();
2883 50669 : if (IsFastElementsKind(elements_kind)) return true;
2884 15629 : if (IsFixedTypedArrayElementsKind(elements_kind) &&
2885 15629 : elements_kind != BIGUINT64_ELEMENTS &&
2886 : elements_kind != BIGINT64_ELEMENTS) {
2887 : return true;
2888 : }
2889 1633 : return false;
2890 : }
2891 :
2892 0 : GlobalAccessFeedback::GlobalAccessFeedback(PropertyCellRef cell)
2893 : : ProcessedFeedback(kGlobalAccess),
2894 : cell_or_context_(cell),
2895 192736 : index_and_immutable_(0 /* doesn't matter */) {}
2896 :
2897 0 : GlobalAccessFeedback::GlobalAccessFeedback(ContextRef script_context,
2898 : int slot_index, bool immutable)
2899 : : ProcessedFeedback(kGlobalAccess),
2900 : cell_or_context_(script_context),
2901 114 : index_and_immutable_(FeedbackNexus::SlotIndexBits::encode(slot_index) |
2902 228 : FeedbackNexus::ImmutabilityBit::encode(immutable)) {
2903 : DCHECK_EQ(this->slot_index(), slot_index);
2904 : DCHECK_EQ(this->immutable(), immutable);
2905 0 : }
2906 :
2907 385586 : bool GlobalAccessFeedback::IsPropertyCell() const {
2908 771400 : return cell_or_context_.IsPropertyCell();
2909 : }
2910 192736 : PropertyCellRef GlobalAccessFeedback::property_cell() const {
2911 : DCHECK(IsPropertyCell());
2912 192736 : return cell_or_context_.AsPropertyCell();
2913 : }
2914 :
2915 114 : ContextRef GlobalAccessFeedback::script_context() const {
2916 : DCHECK(IsScriptContextSlot());
2917 114 : return cell_or_context_.AsContext();
2918 : }
2919 114 : int GlobalAccessFeedback::slot_index() const {
2920 114 : CHECK(IsScriptContextSlot());
2921 228 : return FeedbackNexus::SlotIndexBits::decode(index_and_immutable_);
2922 : }
2923 114 : bool GlobalAccessFeedback::immutable() const {
2924 114 : CHECK(IsScriptContextSlot());
2925 228 : return FeedbackNexus::ImmutabilityBit::decode(index_and_immutable_);
2926 : }
2927 :
2928 0 : base::Optional<ObjectRef> GlobalAccessFeedback::GetConstantValue() const {
2929 0 : if (IsScriptContextSlot() && immutable()) {
2930 : // Return the value of this global variable if it's guaranteed to be
2931 : // constant.
2932 0 : return script_context().get(slot_index());
2933 : }
2934 0 : return {};
2935 : }
2936 :
2937 0 : ElementAccessFeedback::ElementAccessFeedback(Zone* zone)
2938 : : ProcessedFeedback(kElementAccess),
2939 : receiver_maps(zone),
2940 0 : transitions(zone) {}
2941 :
2942 14552 : ElementAccessFeedback::MapIterator::MapIterator(
2943 : ElementAccessFeedback const& processed, JSHeapBroker* broker)
2944 14552 : : processed_(processed), broker_(broker) {
2945 29104 : CHECK_LT(processed.receiver_maps.size(),
2946 : std::numeric_limits<size_t>::max() - processed.transitions.size());
2947 14552 : }
2948 :
2949 29403 : bool ElementAccessFeedback::MapIterator::done() const {
2950 60055 : return index_ >=
2951 120110 : processed_.receiver_maps.size() + processed_.transitions.size();
2952 : }
2953 :
2954 14851 : void ElementAccessFeedback::MapIterator::advance() { index_++; }
2955 :
2956 30652 : MapRef ElementAccessFeedback::MapIterator::current() const {
2957 30652 : CHECK(!done());
2958 : size_t receiver_maps_size = processed_.receiver_maps.size();
2959 : Handle<Map> map;
2960 30652 : if (index_ < receiver_maps_size) {
2961 29533 : map = processed_.receiver_maps[index_];
2962 : } else {
2963 2238 : map = processed_.transitions[index_ - receiver_maps_size].first;
2964 : }
2965 61304 : return MapRef(broker_, map);
2966 : }
2967 :
2968 14552 : ElementAccessFeedback::MapIterator ElementAccessFeedback::all_maps(
2969 : JSHeapBroker* broker) const {
2970 14552 : return MapIterator(*this, broker);
2971 : }
2972 :
2973 24 : FeedbackSource::FeedbackSource(FeedbackNexus const& nexus)
2974 24 : : vector(nexus.vector_handle()), slot(nexus.slot()) {}
2975 :
2976 1219417 : FeedbackSource::FeedbackSource(VectorSlotPair const& pair)
2977 1219417 : : vector(pair.vector()), slot(pair.slot()) {}
2978 :
2979 63 : void JSHeapBroker::SetFeedback(FeedbackSource const& source,
2980 : ProcessedFeedback const* feedback) {
2981 63 : auto insertion = feedback_.insert({source, feedback});
2982 63 : CHECK(insertion.second);
2983 63 : }
2984 :
2985 67 : bool JSHeapBroker::HasFeedback(FeedbackSource const& source) const {
2986 67 : return feedback_.find(source) != feedback_.end();
2987 : }
2988 :
2989 59 : ProcessedFeedback const* JSHeapBroker::GetFeedback(
2990 : FeedbackSource const& source) const {
2991 : auto it = feedback_.find(source);
2992 59 : CHECK_NE(it, feedback_.end());
2993 59 : return it->second;
2994 : }
2995 :
2996 8 : ElementAccessFeedback const* JSHeapBroker::GetElementAccessFeedback(
2997 : FeedbackSource const& source) const {
2998 8 : ProcessedFeedback const* feedback = GetFeedback(source);
2999 8 : if (feedback == nullptr) return nullptr;
3000 0 : CHECK_EQ(feedback->kind(), ProcessedFeedback::kElementAccess);
3001 : return static_cast<ElementAccessFeedback const*>(feedback);
3002 : }
3003 :
3004 51 : GlobalAccessFeedback const* JSHeapBroker::GetGlobalAccessFeedback(
3005 : FeedbackSource const& source) const {
3006 51 : ProcessedFeedback const* feedback = GetFeedback(source);
3007 51 : if (feedback == nullptr) return nullptr;
3008 0 : CHECK_EQ(feedback->kind(), ProcessedFeedback::kGlobalAccess);
3009 : return static_cast<GlobalAccessFeedback const*>(feedback);
3010 : }
3011 :
3012 23155 : ElementAccessFeedback const* JSHeapBroker::ProcessFeedbackMapsForElementAccess(
3013 : MapHandles const& maps) {
3014 : // Collect possible transition targets.
3015 : MapHandles possible_transition_targets;
3016 23155 : possible_transition_targets.reserve(maps.size());
3017 49038 : for (Handle<Map> map : maps) {
3018 76356 : if (CanInlineElementAccess(MapRef(this, map)) &&
3019 43569 : IsFastElementsKind(map->elements_kind()) &&
3020 : GetInitialFastElementsKind() != map->elements_kind()) {
3021 13172 : possible_transition_targets.push_back(map);
3022 : }
3023 : }
3024 :
3025 23155 : if (maps.empty()) return nullptr;
3026 :
3027 : ElementAccessFeedback* result = new (zone()) ElementAccessFeedback(zone());
3028 :
3029 : // Separate the actual receiver maps and the possible transition sources.
3030 49022 : for (Handle<Map> map : maps) {
3031 : // Don't generate elements kind transitions from stable maps.
3032 : Map transition_target = map->is_stable()
3033 : ? Map()
3034 : : map->FindElementsKindTransitionedMap(
3035 41207 : isolate(), possible_transition_targets);
3036 25883 : if (transition_target.is_null()) {
3037 24238 : result->receiver_maps.push_back(map);
3038 : } else {
3039 1645 : result->transitions.emplace_back(map,
3040 3290 : handle(transition_target, isolate()));
3041 : }
3042 : }
3043 :
3044 : #ifdef ENABLE_SLOW_DCHECKS
3045 : // No transition sources appear in {receiver_maps}.
3046 : // All transition targets appear in {receiver_maps}.
3047 : for (auto& transition : result->transitions) {
3048 : CHECK(std::none_of(
3049 : result->receiver_maps.cbegin(), result->receiver_maps.cend(),
3050 : [&](Handle<Map> map) { return map.equals(transition.first); }));
3051 : CHECK(std::any_of(
3052 : result->receiver_maps.cbegin(), result->receiver_maps.cend(),
3053 : [&](Handle<Map> map) { return map.equals(transition.second); }));
3054 : }
3055 : #endif
3056 23139 : CHECK(!result->receiver_maps.empty());
3057 :
3058 : return result;
3059 : }
3060 :
3061 1219413 : GlobalAccessFeedback const* JSHeapBroker::ProcessFeedbackForGlobalAccess(
3062 : FeedbackSource const& source) {
3063 : FeedbackNexus nexus(source.vector, source.slot);
3064 : DCHECK(nexus.kind() == FeedbackSlotKind::kLoadGlobalInsideTypeof ||
3065 : nexus.kind() == FeedbackSlotKind::kLoadGlobalNotInsideTypeof ||
3066 : nexus.kind() == FeedbackSlotKind::kStoreGlobalSloppy ||
3067 : nexus.kind() == FeedbackSlotKind::kStoreGlobalStrict);
3068 1412386 : if (nexus.ic_state() != MONOMORPHIC || nexus.GetFeedback()->IsCleared()) {
3069 : return nullptr;
3070 : }
3071 :
3072 385700 : Handle<Object> feedback_value(nexus.GetFeedback()->GetHeapObjectOrSmi(),
3073 : isolate());
3074 :
3075 192850 : if (feedback_value->IsSmi()) {
3076 : // The wanted name belongs to a script-scope variable and the feedback tells
3077 : // us where to find its value.
3078 114 : int number = feedback_value->Number();
3079 : int const script_context_index =
3080 228 : FeedbackNexus::ContextIndexBits::decode(number);
3081 114 : int const context_slot_index = FeedbackNexus::SlotIndexBits::decode(number);
3082 : bool const immutable = FeedbackNexus::ImmutabilityBit::decode(number);
3083 : Handle<Context> context = ScriptContextTable::GetContext(
3084 228 : isolate(), native_context().script_context_table().object(),
3085 114 : script_context_index);
3086 : {
3087 : ObjectRef contents(this,
3088 114 : handle(context->get(context_slot_index), isolate()));
3089 228 : CHECK(!contents.equals(
3090 : ObjectRef(this, isolate()->factory()->the_hole_value())));
3091 : }
3092 : ContextRef context_ref(this, context);
3093 114 : if (immutable) {
3094 37 : context_ref.SerializeSlot(context_slot_index);
3095 : }
3096 : return new (zone())
3097 114 : GlobalAccessFeedback(context_ref, context_slot_index, immutable);
3098 : }
3099 :
3100 192736 : CHECK(feedback_value->IsPropertyCell());
3101 : // The wanted name belongs (or did belong) to a property on the global
3102 : // object and the feedback is the cell holding its value.
3103 : PropertyCellRef cell(this, Handle<PropertyCell>::cast(feedback_value));
3104 192736 : cell.Serialize();
3105 192736 : return new (zone()) GlobalAccessFeedback(cell);
3106 : }
3107 :
3108 : #undef BIMODAL_ACCESSOR
3109 : #undef BIMODAL_ACCESSOR_B
3110 : #undef BIMODAL_ACCESSOR_C
3111 : #undef IF_BROKER_DISABLED_ACCESS_HANDLE
3112 : #undef IF_BROKER_DISABLED_ACCESS_HANDLE_C
3113 : #undef TRACE
3114 :
3115 : } // namespace compiler
3116 : } // namespace internal
3117 120216 : } // namespace v8
|