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 : #ifndef V8_OBJECTS_JS_OBJECTS_INL_H_
6 : #define V8_OBJECTS_JS_OBJECTS_INL_H_
7 :
8 : #include "src/objects/js-objects.h"
9 :
10 : #include "src/feedback-vector.h"
11 : #include "src/heap/heap-write-barrier.h"
12 : #include "src/keys.h"
13 : #include "src/lookup-inl.h"
14 : #include "src/objects/embedder-data-slot-inl.h"
15 : #include "src/objects/feedback-cell-inl.h"
16 : #include "src/objects/heap-number-inl.h"
17 : #include "src/objects/property-array-inl.h"
18 : #include "src/objects/shared-function-info.h"
19 : #include "src/objects/slots.h"
20 : #include "src/objects/smi-inl.h"
21 : #include "src/prototype.h"
22 :
23 : // Has to be the last include (doesn't have include guards):
24 : #include "src/objects/object-macros.h"
25 :
26 : namespace v8 {
27 : namespace internal {
28 :
29 855882776 : OBJECT_CONSTRUCTORS_IMPL(JSReceiver, HeapObject)
30 1306310438 : OBJECT_CONSTRUCTORS_IMPL(JSObject, JSReceiver)
31 420 : OBJECT_CONSTRUCTORS_IMPL(JSAsyncFromSyncIterator, JSObject)
32 4790 : OBJECT_CONSTRUCTORS_IMPL(JSBoundFunction, JSObject)
33 748728 : OBJECT_CONSTRUCTORS_IMPL(JSDate, JSObject)
34 347693358 : OBJECT_CONSTRUCTORS_IMPL(JSFunction, JSObject)
35 184653732 : OBJECT_CONSTRUCTORS_IMPL(JSGlobalObject, JSObject)
36 21403416 : OBJECT_CONSTRUCTORS_IMPL(JSGlobalProxy, JSObject)
37 46418 : JSIteratorResult::JSIteratorResult(Address ptr) : JSObject(ptr) {}
38 2847176 : OBJECT_CONSTRUCTORS_IMPL(JSMessageObject, JSObject)
39 0 : OBJECT_CONSTRUCTORS_IMPL(JSStringIterator, JSObject)
40 1080530 : OBJECT_CONSTRUCTORS_IMPL(JSValue, JSObject)
41 :
42 113748 : NEVER_READ_ONLY_SPACE_IMPL(JSReceiver)
43 :
44 210 : CAST_ACCESSOR(JSAsyncFromSyncIterator)
45 2395 : CAST_ACCESSOR(JSBoundFunction)
46 374364 : CAST_ACCESSOR(JSDate)
47 173846708 : CAST_ACCESSOR(JSFunction)
48 92326945 : CAST_ACCESSOR(JSGlobalObject)
49 10701708 : CAST_ACCESSOR(JSGlobalProxy)
50 23209 : CAST_ACCESSOR(JSIteratorResult)
51 1423588 : CAST_ACCESSOR(JSMessageObject)
52 653158738 : CAST_ACCESSOR(JSObject)
53 427941392 : CAST_ACCESSOR(JSReceiver)
54 0 : CAST_ACCESSOR(JSStringIterator)
55 540265 : CAST_ACCESSOR(JSValue)
56 :
57 18029162 : MaybeHandle<Object> JSReceiver::GetProperty(Isolate* isolate,
58 : Handle<JSReceiver> receiver,
59 : Handle<Name> name) {
60 18029162 : LookupIterator it(isolate, receiver, name, receiver);
61 28079911 : if (!it.IsFound()) return it.factory()->undefined_value();
62 7978413 : return Object::GetProperty(&it);
63 : }
64 :
65 50337192 : MaybeHandle<Object> JSReceiver::GetElement(Isolate* isolate,
66 : Handle<JSReceiver> receiver,
67 : uint32_t index) {
68 : LookupIterator it(isolate, receiver, index, receiver);
69 99907710 : if (!it.IsFound()) return it.factory()->undefined_value();
70 766674 : return Object::GetProperty(&it);
71 : }
72 :
73 5664206 : Handle<Object> JSReceiver::GetDataProperty(Handle<JSReceiver> object,
74 : Handle<Name> name) {
75 : LookupIterator it(object, name, object,
76 5664206 : LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
77 7987021 : if (!it.IsFound()) return it.factory()->undefined_value();
78 3341391 : return GetDataProperty(&it);
79 : }
80 :
81 3266503 : MaybeHandle<Object> JSReceiver::GetPrototype(Isolate* isolate,
82 : Handle<JSReceiver> receiver) {
83 : // We don't expect access checks to be needed on JSProxy objects.
84 : DCHECK(!receiver->IsAccessCheckNeeded() || receiver->IsJSObject());
85 : PrototypeIterator iter(isolate, receiver, kStartAtReceiver,
86 3266503 : PrototypeIterator::END_AT_NON_HIDDEN);
87 3244797 : do {
88 3273166 : if (!iter.AdvanceFollowingProxies()) return MaybeHandle<Object>();
89 3244797 : } while (!iter.IsAtEnd());
90 3238134 : return PrototypeIterator::GetCurrent(iter);
91 : }
92 :
93 290956 : MaybeHandle<Object> JSReceiver::GetProperty(Isolate* isolate,
94 : Handle<JSReceiver> receiver,
95 : const char* name) {
96 290956 : Handle<String> str = isolate->factory()->InternalizeUtf8String(name);
97 290956 : return GetProperty(isolate, receiver, str);
98 : }
99 :
100 : // static
101 1044 : V8_WARN_UNUSED_RESULT MaybeHandle<FixedArray> JSReceiver::OwnPropertyKeys(
102 : Handle<JSReceiver> object) {
103 : return KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly,
104 : ALL_PROPERTIES,
105 1739 : GetKeysConversion::kConvertToString);
106 : }
107 :
108 11165645 : bool JSObject::PrototypeHasNoElements(Isolate* isolate, JSObject object) {
109 : DisallowHeapAllocation no_gc;
110 : HeapObject prototype = HeapObject::cast(object->map()->prototype());
111 : ReadOnlyRoots roots(isolate);
112 : HeapObject null = roots.null_value();
113 : FixedArrayBase empty_fixed_array = roots.empty_fixed_array();
114 : FixedArrayBase empty_slow_element_dictionary =
115 : roots.empty_slow_element_dictionary();
116 54873994 : while (prototype != null) {
117 : Map map = prototype->map();
118 32552229 : if (map->IsCustomElementsReceiverMap()) return false;
119 32551220 : FixedArrayBase elements = JSObject::cast(prototype)->elements();
120 32551117 : if (elements != empty_fixed_array &&
121 : elements != empty_slow_element_dictionary) {
122 : return false;
123 : }
124 : prototype = HeapObject::cast(map->prototype());
125 : }
126 : return true;
127 : }
128 :
129 885187281 : ACCESSORS(JSReceiver, raw_properties_or_hash, Object, kPropertiesOrHashOffset)
130 :
131 393090059 : FixedArrayBase JSObject::elements() const {
132 393090059 : Object array = READ_FIELD(this, kElementsOffset);
133 393090277 : return FixedArrayBase::cast(array);
134 : }
135 :
136 90695 : void JSObject::EnsureCanContainHeapObjectElements(Handle<JSObject> object) {
137 90695 : JSObject::ValidateElements(*object);
138 : ElementsKind elements_kind = object->map()->elements_kind();
139 90695 : if (!IsObjectElementsKind(elements_kind)) {
140 0 : if (IsHoleyElementsKind(elements_kind)) {
141 0 : TransitionElementsKind(object, HOLEY_ELEMENTS);
142 : } else {
143 0 : TransitionElementsKind(object, PACKED_ELEMENTS);
144 : }
145 : }
146 90695 : }
147 :
148 : template <typename TSlot>
149 548844 : void JSObject::EnsureCanContainElements(Handle<JSObject> object, TSlot objects,
150 : uint32_t count,
151 : EnsureElementsMode mode) {
152 : static_assert(std::is_same<TSlot, FullObjectSlot>::value ||
153 : std::is_same<TSlot, ObjectSlot>::value,
154 : "Only ObjectSlot and FullObjectSlot are expected here");
155 548844 : ElementsKind current_kind = object->GetElementsKind();
156 : ElementsKind target_kind = current_kind;
157 : {
158 : DisallowHeapAllocation no_allocation;
159 : DCHECK(mode != ALLOW_COPIED_DOUBLE_ELEMENTS);
160 : bool is_holey = IsHoleyElementsKind(current_kind);
161 1097688 : if (current_kind == HOLEY_ELEMENTS) return;
162 1097638 : Object the_hole = object->GetReadOnlyRoots().the_hole_value();
163 29477036 : for (uint32_t i = 0; i < count; ++i, ++objects) {
164 14189699 : Object current = *objects;
165 14189699 : if (current == the_hole) {
166 : is_holey = true;
167 : target_kind = GetHoleyElementsKind(target_kind);
168 12699300 : } else if (!current->IsSmi()) {
169 10648143 : if (mode == ALLOW_CONVERTED_DOUBLE_ELEMENTS && current->IsNumber()) {
170 1880619 : if (IsSmiElementsKind(target_kind)) {
171 219 : if (is_holey) {
172 : target_kind = HOLEY_DOUBLE_ELEMENTS;
173 : } else {
174 : target_kind = PACKED_DOUBLE_ELEMENTS;
175 : }
176 : }
177 3625301 : } else if (is_holey) {
178 : target_kind = HOLEY_ELEMENTS;
179 0 : break;
180 : } else {
181 : target_kind = PACKED_ELEMENTS;
182 : }
183 : }
184 : }
185 : }
186 548819 : if (target_kind != current_kind) {
187 94607 : TransitionElementsKind(object, target_kind);
188 : }
189 : }
190 :
191 93433 : void JSObject::EnsureCanContainElements(Handle<JSObject> object,
192 : Handle<FixedArrayBase> elements,
193 : uint32_t length,
194 : EnsureElementsMode mode) {
195 93433 : ReadOnlyRoots roots = object->GetReadOnlyRoots();
196 93433 : if (elements->map() != roots.fixed_double_array_map()) {
197 : DCHECK(elements->map() == roots.fixed_array_map() ||
198 : elements->map() == roots.fixed_cow_array_map());
199 93433 : if (mode == ALLOW_COPIED_DOUBLE_ELEMENTS) {
200 : mode = DONT_ALLOW_DOUBLE_ELEMENTS;
201 : }
202 : ObjectSlot objects =
203 186866 : Handle<FixedArray>::cast(elements)->GetFirstElementAddress();
204 93433 : EnsureCanContainElements(object, objects, length, mode);
205 : return;
206 : }
207 :
208 : DCHECK(mode == ALLOW_COPIED_DOUBLE_ELEMENTS);
209 0 : if (object->GetElementsKind() == HOLEY_SMI_ELEMENTS) {
210 0 : TransitionElementsKind(object, HOLEY_DOUBLE_ELEMENTS);
211 0 : } else if (object->GetElementsKind() == PACKED_SMI_ELEMENTS) {
212 : Handle<FixedDoubleArray> double_array =
213 0 : Handle<FixedDoubleArray>::cast(elements);
214 0 : for (uint32_t i = 0; i < length; ++i) {
215 0 : if (double_array->is_the_hole(i)) {
216 0 : TransitionElementsKind(object, HOLEY_DOUBLE_ELEMENTS);
217 0 : return;
218 : }
219 : }
220 0 : TransitionElementsKind(object, PACKED_DOUBLE_ELEMENTS);
221 : }
222 : }
223 :
224 963582 : void JSObject::SetMapAndElements(Handle<JSObject> object, Handle<Map> new_map,
225 : Handle<FixedArrayBase> value) {
226 963582 : JSObject::MigrateToMap(object, new_map);
227 : DCHECK((object->map()->has_fast_smi_or_object_elements() ||
228 : (*value == object->GetReadOnlyRoots().empty_fixed_array()) ||
229 : object->map()->has_fast_string_wrapper_elements()) ==
230 : (value->map() == object->GetReadOnlyRoots().fixed_array_map() ||
231 : value->map() == object->GetReadOnlyRoots().fixed_cow_array_map()));
232 : DCHECK((*value == object->GetReadOnlyRoots().empty_fixed_array()) ||
233 : (object->map()->has_fast_double_elements() ==
234 : value->IsFixedDoubleArray()));
235 963582 : object->set_elements(*value);
236 963582 : }
237 :
238 9473587 : void JSObject::set_elements(FixedArrayBase value, WriteBarrierMode mode) {
239 9473587 : WRITE_FIELD(*this, kElementsOffset, value);
240 25683173 : CONDITIONAL_WRITE_BARRIER(*this, kElementsOffset, value, mode);
241 9473619 : }
242 :
243 41584051 : void JSObject::initialize_elements() {
244 41584051 : FixedArrayBase elements = map()->GetInitialElements();
245 41584051 : WRITE_FIELD(*this, kElementsOffset, elements);
246 41584051 : }
247 :
248 621088 : InterceptorInfo JSObject::GetIndexedInterceptor() {
249 621088 : return map()->GetIndexedInterceptor();
250 : }
251 :
252 1538689 : InterceptorInfo JSObject::GetNamedInterceptor() {
253 1538689 : return map()->GetNamedInterceptor();
254 : }
255 :
256 : int JSObject::GetHeaderSize() const { return GetHeaderSize(map()); }
257 :
258 3440166 : int JSObject::GetHeaderSize(const Map map) {
259 : // Check for the most common kind of JavaScript object before
260 : // falling into the generic switch. This speeds up the internal
261 : // field operations considerably on average.
262 : InstanceType instance_type = map->instance_type();
263 : return instance_type == JS_OBJECT_TYPE
264 : ? JSObject::kHeaderSize
265 5146972 : : GetHeaderSize(instance_type, map->has_prototype_slot());
266 : }
267 :
268 : // static
269 : int JSObject::GetEmbedderFieldsStartOffset(const Map map) {
270 : // Embedder fields are located after the header size rounded up to the
271 : // kSystemPointerSize, whereas in-object properties are at the end of the
272 : // object.
273 1867950 : int header_size = GetHeaderSize(map);
274 : if (kTaggedSize == kSystemPointerSize) {
275 : DCHECK(IsAligned(header_size, kSystemPointerSize));
276 : return header_size;
277 : } else {
278 : return RoundUp(header_size, kSystemPointerSize);
279 : }
280 : }
281 :
282 1867950 : int JSObject::GetEmbedderFieldsStartOffset() {
283 1867965 : return GetEmbedderFieldsStartOffset(map());
284 : }
285 :
286 : // static
287 1572218 : int JSObject::GetEmbedderFieldCount(const Map map) {
288 : int instance_size = map->instance_size();
289 1572218 : if (instance_size == kVariableSizeSentinel) return 0;
290 : // Embedder fields are located after the header size rounded up to the
291 : // kSystemPointerSize, whereas in-object properties are at the end of the
292 : // object. We don't have to round up the header size here because division by
293 : // kEmbedderDataSlotSizeInTaggedSlots will swallow potential padding in case
294 : // of (kTaggedSize != kSystemPointerSize) anyway.
295 1572218 : return (((instance_size - GetHeaderSize(map)) >> kTaggedSizeLog2) -
296 1572217 : map->GetInObjectProperties()) /
297 1572218 : kEmbedderDataSlotSizeInTaggedSlots;
298 : }
299 :
300 688501 : int JSObject::GetEmbedderFieldCount() const {
301 688501 : return GetEmbedderFieldCount(map());
302 : }
303 :
304 1867855 : int JSObject::GetEmbedderFieldOffset(int index) {
305 : DCHECK_LT(static_cast<unsigned>(index),
306 : static_cast<unsigned>(GetEmbedderFieldCount()));
307 1867950 : return GetEmbedderFieldsStartOffset() + (kEmbedderDataSlotSize * index);
308 : }
309 :
310 950599 : Object JSObject::GetEmbedderField(int index) {
311 950609 : return EmbedderDataSlot(*this, index).load_tagged();
312 : }
313 :
314 915210 : void JSObject::SetEmbedderField(int index, Object value) {
315 : EmbedderDataSlot::store_tagged(*this, index, value);
316 915215 : }
317 :
318 : void JSObject::SetEmbedderField(int index, Smi value) {
319 : EmbedderDataSlot(*this, index).store_smi(value);
320 : }
321 :
322 53750240 : bool JSObject::IsUnboxedDoubleField(FieldIndex index) {
323 : if (!FLAG_unbox_double_fields) return false;
324 53750240 : return map()->IsUnboxedDoubleField(index);
325 : }
326 :
327 : // Access fast-case object properties at index. The use of these routines
328 : // is needed to correctly distinguish between properties stored in-object and
329 : // properties stored in the properties array.
330 53714527 : Object JSObject::RawFastPropertyAt(FieldIndex index) {
331 : DCHECK(!IsUnboxedDoubleField(index));
332 53714527 : if (index.is_inobject()) {
333 5532463 : return READ_FIELD(this, index.offset());
334 : } else {
335 48182064 : return property_array()->get(index.outobject_array_index());
336 : }
337 : }
338 :
339 : double JSObject::RawFastDoublePropertyAt(FieldIndex index) {
340 : DCHECK(IsUnboxedDoubleField(index));
341 21583 : return READ_DOUBLE_FIELD(this, index.offset());
342 : }
343 :
344 : uint64_t JSObject::RawFastDoublePropertyAsBitsAt(FieldIndex index) {
345 : DCHECK(IsUnboxedDoubleField(index));
346 6129 : return READ_UINT64_FIELD(this, index.offset());
347 : }
348 :
349 49543965 : void JSObject::RawFastPropertyAtPut(FieldIndex index, Object value) {
350 49543965 : if (index.is_inobject()) {
351 : int offset = index.offset();
352 34587019 : WRITE_FIELD(*this, offset, value);
353 69174042 : WRITE_BARRIER(*this, offset, value);
354 : } else {
355 14956946 : property_array()->set(index.outobject_array_index(), value);
356 : }
357 49543973 : }
358 :
359 : void JSObject::RawFastDoublePropertyAsBitsAtPut(FieldIndex index,
360 : uint64_t bits) {
361 : // Double unboxing is enabled only on 64-bit platforms without pointer
362 : // compression.
363 : DCHECK_EQ(kDoubleSize, kTaggedSize);
364 48486 : Address field_addr = FIELD_ADDR(*this, index.offset());
365 : base::Relaxed_Store(reinterpret_cast<base::AtomicWord*>(field_addr),
366 48486 : static_cast<base::AtomicWord>(bits));
367 : }
368 :
369 314828 : void JSObject::FastPropertyAtPut(FieldIndex index, Object value) {
370 314828 : if (IsUnboxedDoubleField(index)) {
371 : DCHECK(value->IsMutableHeapNumber());
372 : // Ensure that all bits of the double value are preserved.
373 : RawFastDoublePropertyAsBitsAtPut(
374 : index, MutableHeapNumber::cast(value)->value_as_bits());
375 : } else {
376 314823 : RawFastPropertyAtPut(index, value);
377 : }
378 314828 : }
379 :
380 46751859 : void JSObject::WriteToField(int descriptor, PropertyDetails details,
381 : Object value) {
382 : DCHECK_EQ(kField, details.location());
383 : DCHECK_EQ(kData, details.kind());
384 : DisallowHeapAllocation no_gc;
385 46751859 : FieldIndex index = FieldIndex::ForDescriptor(map(), descriptor);
386 46751874 : if (details.representation().IsDouble()) {
387 : // Nothing more to be done.
388 49392 : if (value->IsUninitialized()) {
389 1287 : return;
390 : }
391 : // Manipulating the signaling NaN used for the hole and uninitialized
392 : // double field sentinel in C++, e.g. with bit_cast or value()/set_value(),
393 : // will change its value on ia32 (the x87 stack is used to return values
394 : // and stores to the stack silently clear the signalling bit).
395 : uint64_t bits;
396 48105 : if (value->IsSmi()) {
397 6315 : bits = bit_cast<uint64_t>(static_cast<double>(Smi::ToInt(value)));
398 : } else {
399 : DCHECK(value->IsHeapNumber());
400 : bits = HeapNumber::cast(value)->value_as_bits();
401 : }
402 48105 : if (IsUnboxedDoubleField(index)) {
403 : RawFastDoublePropertyAsBitsAtPut(index, bits);
404 : } else {
405 7372 : auto box = MutableHeapNumber::cast(RawFastPropertyAt(index));
406 : box->set_value_as_bits(bits);
407 : }
408 : } else {
409 46702482 : RawFastPropertyAtPut(index, value);
410 : }
411 : }
412 :
413 515252 : int JSObject::GetInObjectPropertyOffset(int index) {
414 515252 : return map()->GetInObjectPropertyOffset(index);
415 : }
416 :
417 : Object JSObject::InObjectPropertyAt(int index) {
418 0 : int offset = GetInObjectPropertyOffset(index);
419 0 : return READ_FIELD(*this, offset);
420 : }
421 :
422 515252 : Object JSObject::InObjectPropertyAtPut(int index, Object value,
423 : WriteBarrierMode mode) {
424 : // Adjust for the number of properties stored in the object.
425 515252 : int offset = GetInObjectPropertyOffset(index);
426 515252 : WRITE_FIELD(*this, offset, value);
427 628978 : CONDITIONAL_WRITE_BARRIER(*this, offset, value, mode);
428 515252 : return value;
429 : }
430 :
431 23080988 : void JSObject::InitializeBody(Map map, int start_offset,
432 : Object pre_allocated_value, Object filler_value) {
433 : DCHECK(!filler_value->IsHeapObject() || !Heap::InNewSpace(filler_value));
434 : DCHECK(!pre_allocated_value->IsHeapObject() ||
435 : !Heap::InNewSpace(pre_allocated_value));
436 : int size = map->instance_size();
437 : int offset = start_offset;
438 23080988 : if (filler_value != pre_allocated_value) {
439 : int end_of_pre_allocated_offset =
440 242386 : size - (map->UnusedPropertyFields() * kTaggedSize);
441 : DCHECK_LE(kHeaderSize, end_of_pre_allocated_offset);
442 604080 : while (offset < end_of_pre_allocated_offset) {
443 119304 : WRITE_FIELD(*this, offset, pre_allocated_value);
444 119304 : offset += kTaggedSize;
445 : }
446 : }
447 150191736 : while (offset < size) {
448 127110746 : WRITE_FIELD(*this, offset, filler_value);
449 127110746 : offset += kTaggedSize;
450 : }
451 23080990 : }
452 :
453 : Object JSBoundFunction::raw_bound_target_function() const {
454 : return READ_FIELD(this, kBoundTargetFunctionOffset);
455 : }
456 :
457 10899 : ACCESSORS(JSBoundFunction, bound_target_function, JSReceiver,
458 : kBoundTargetFunctionOffset)
459 4692 : ACCESSORS(JSBoundFunction, bound_this, Object, kBoundThisOffset)
460 9300 : ACCESSORS(JSBoundFunction, bound_arguments, FixedArray, kBoundArgumentsOffset)
461 :
462 587217908 : ACCESSORS(JSFunction, shared, SharedFunctionInfo, kSharedFunctionInfoOffset)
463 233940831 : ACCESSORS(JSFunction, raw_feedback_cell, FeedbackCell, kFeedbackCellOffset)
464 :
465 53400264 : ACCESSORS(JSGlobalObject, native_context, Context, kNativeContextOffset)
466 615468 : ACCESSORS(JSGlobalObject, global_proxy, JSObject, kGlobalProxyOffset)
467 :
468 18468600 : ACCESSORS(JSGlobalProxy, native_context, Object, kNativeContextOffset)
469 :
470 11382211 : FeedbackVector JSFunction::feedback_vector() const {
471 : DCHECK(has_feedback_vector());
472 22764464 : return FeedbackVector::cast(raw_feedback_cell()->value());
473 : }
474 :
475 : // Code objects that are marked for deoptimization are not considered to be
476 : // optimized. This is because the JSFunction might have been already
477 : // deoptimized but its code() still needs to be unlinked, which will happen on
478 : // its next activation.
479 : // TODO(jupvfranco): rename this function. Maybe RunOptimizedCode,
480 : // or IsValidOptimizedCode.
481 3772111 : bool JSFunction::IsOptimized() {
482 15403198 : return is_compiled() && code()->kind() == Code::OPTIMIZED_FUNCTION &&
483 8363857 : !code()->marked_for_deoptimization();
484 : }
485 :
486 581482 : bool JSFunction::HasOptimizedCode() {
487 1158352 : return IsOptimized() ||
488 2888952 : (has_feedback_vector() && feedback_vector()->has_optimized_code() &&
489 1167742 : !feedback_vector()->optimized_code()->marked_for_deoptimization());
490 : }
491 :
492 479856 : bool JSFunction::HasOptimizationMarker() {
493 479856 : return has_feedback_vector() && feedback_vector()->has_optimization_marker();
494 : }
495 :
496 : void JSFunction::ClearOptimizationMarker() {
497 : DCHECK(has_feedback_vector());
498 330569 : feedback_vector()->ClearOptimizationMarker();
499 : }
500 :
501 : // Optimized code marked for deoptimization will tier back down to running
502 : // interpreted on its next activation, and already doesn't count as IsOptimized.
503 7174 : bool JSFunction::IsInterpreted() {
504 35171 : return is_compiled() && (code()->is_interpreter_trampoline_builtin() ||
505 20204 : (code()->kind() == Code::OPTIMIZED_FUNCTION &&
506 20883 : code()->marked_for_deoptimization()));
507 : }
508 :
509 : bool JSFunction::ChecksOptimizationMarker() {
510 : return code()->checks_optimization_marker();
511 : }
512 :
513 157233 : bool JSFunction::IsMarkedForOptimization() {
514 314456 : return has_feedback_vector() && feedback_vector()->optimization_marker() ==
515 157243 : OptimizationMarker::kCompileOptimized;
516 : }
517 :
518 148650 : bool JSFunction::IsMarkedForConcurrentOptimization() {
519 297300 : return has_feedback_vector() &&
520 445950 : feedback_vector()->optimization_marker() ==
521 148650 : OptimizationMarker::kCompileOptimizedConcurrent;
522 : }
523 :
524 202753 : bool JSFunction::IsInOptimizationQueue() {
525 405476 : return has_feedback_vector() && feedback_vector()->optimization_marker() ==
526 202783 : OptimizationMarker::kInOptimizationQueue;
527 : }
528 :
529 301843 : void JSFunction::CompleteInobjectSlackTrackingIfActive() {
530 603686 : if (!has_prototype_slot()) return;
531 323038 : if (has_initial_map() && initial_map()->IsInobjectSlackTrackingInProgress()) {
532 115553 : initial_map()->CompleteInobjectSlackTracking(GetIsolate());
533 : }
534 : }
535 :
536 195 : AbstractCode JSFunction::abstract_code() {
537 195 : if (IsInterpreted()) {
538 284 : return AbstractCode::cast(shared()->GetBytecodeArray());
539 : } else {
540 106 : return AbstractCode::cast(code());
541 : }
542 : }
543 :
544 14777835 : Code JSFunction::code() const {
545 29555681 : return Code::cast(READ_FIELD(*this, kCodeOffset));
546 : }
547 :
548 17237398 : void JSFunction::set_code(Code value) {
549 : DCHECK(!Heap::InNewSpace(value));
550 17237398 : WRITE_FIELD(*this, kCodeOffset, value);
551 17237398 : MarkingBarrier(*this, RawField(kCodeOffset), value);
552 17237405 : }
553 :
554 : void JSFunction::set_code_no_write_barrier(Code value) {
555 : DCHECK(!Heap::InNewSpace(value));
556 : WRITE_FIELD(*this, kCodeOffset, value);
557 : }
558 :
559 : void JSFunction::ClearOptimizedCodeSlot(const char* reason) {
560 : if (has_feedback_vector() && feedback_vector()->has_optimized_code()) {
561 : if (FLAG_trace_opt) {
562 : PrintF("[evicting entry from optimizing code feedback slot (%s) for ",
563 : reason);
564 : ShortPrint();
565 : PrintF("]\n");
566 : }
567 : feedback_vector()->ClearOptimizedCode();
568 : }
569 : }
570 :
571 4624 : void JSFunction::SetOptimizationMarker(OptimizationMarker marker) {
572 : DCHECK(has_feedback_vector());
573 : DCHECK(ChecksOptimizationMarker());
574 : DCHECK(!HasOptimizedCode());
575 :
576 497015 : feedback_vector()->SetOptimizationMarker(marker);
577 4624 : }
578 :
579 17220768 : bool JSFunction::has_feedback_vector() const {
580 51662321 : return shared()->is_compiled() &&
581 51662355 : !raw_feedback_cell()->value()->IsUndefined();
582 : }
583 :
584 26884240 : Context JSFunction::context() {
585 53768484 : return Context::cast(READ_FIELD(*this, kContextOffset));
586 : }
587 :
588 418028 : bool JSFunction::has_context() const {
589 1254084 : return READ_FIELD(*this, kContextOffset)->IsContext();
590 : }
591 :
592 1091119 : JSGlobalProxy JSFunction::global_proxy() { return context()->global_proxy(); }
593 :
594 8271486 : Context JSFunction::native_context() { return context()->native_context(); }
595 :
596 15523206 : void JSFunction::set_context(Object value) {
597 : DCHECK(value->IsUndefined() || value->IsContext());
598 15523206 : WRITE_FIELD(*this, kContextOffset, value);
599 31046429 : WRITE_BARRIER(*this, kContextOffset, value);
600 15523226 : }
601 :
602 340260426 : ACCESSORS_CHECKED(JSFunction, prototype_or_initial_map, Object,
603 : kPrototypeOrInitialMapOffset, map()->has_prototype_slot())
604 :
605 24309722 : bool JSFunction::has_prototype_slot() const {
606 24309722 : return map()->has_prototype_slot();
607 : }
608 :
609 79630224 : Map JSFunction::initial_map() { return Map::cast(prototype_or_initial_map()); }
610 :
611 43904431 : bool JSFunction::has_initial_map() {
612 : DCHECK(has_prototype_slot());
613 87809014 : return prototype_or_initial_map()->IsMap();
614 : }
615 :
616 7045070 : bool JSFunction::has_instance_prototype() {
617 : DCHECK(has_prototype_slot());
618 7927288 : return has_initial_map() || !prototype_or_initial_map()->IsTheHole();
619 : }
620 :
621 6747160 : bool JSFunction::has_prototype() {
622 : DCHECK(has_prototype_slot());
623 6747160 : return map()->has_non_instance_prototype() || has_instance_prototype();
624 : }
625 :
626 7718639 : bool JSFunction::has_prototype_property() {
627 15439031 : return (has_prototype_slot() && IsConstructor()) ||
628 8764293 : IsGeneratorFunction(shared()->kind());
629 : }
630 :
631 7718639 : bool JSFunction::PrototypeRequiresRuntimeLookup() {
632 14393376 : return !has_prototype_property() || map()->has_non_instance_prototype();
633 : }
634 :
635 5880979 : Object JSFunction::instance_prototype() {
636 : DCHECK(has_instance_prototype());
637 11441621 : if (has_initial_map()) return initial_map()->prototype();
638 : // When there is no initial map and the prototype is a JSReceiver, the
639 : // initial map field is used for the prototype field.
640 320375 : return prototype_or_initial_map();
641 : }
642 :
643 4622574 : Object JSFunction::prototype() {
644 : DCHECK(has_prototype());
645 : // If the function's prototype property has been set to a non-JSReceiver
646 : // value, that value is stored in the constructor field of the map.
647 4622574 : if (map()->has_non_instance_prototype()) {
648 13414 : Object prototype = map()->GetConstructor();
649 : // The map must have a prototype in that field, not a back pointer.
650 : DCHECK(!prototype->IsMap());
651 : DCHECK(!prototype->IsFunctionTemplateInfo());
652 13414 : return prototype;
653 : }
654 4609160 : return instance_prototype();
655 : }
656 :
657 4421647 : bool JSFunction::is_compiled() const {
658 17383384 : return code()->builtin_index() != Builtins::kCompileLazy &&
659 12961737 : shared()->is_compiled();
660 : }
661 :
662 1515523 : void JSFunction::ResetIfBytecodeFlushed() {
663 1515523 : if (!shared()->is_compiled()) {
664 : // Bytecode was flushed and function is now uncompiled, reset JSFunction
665 : // by setting code to CompileLazy and clearing the feedback vector.
666 1240410 : if (code()->builtin_index() != Builtins::kCompileLazy) {
667 60 : set_code(GetIsolate()->builtins()->builtin(i::Builtins::kCompileLazy));
668 : }
669 1240411 : if (raw_feedback_cell()->value()->IsFeedbackVector()) {
670 : raw_feedback_cell()->set_value(
671 70 : ReadOnlyRoots(GetIsolate()).undefined_value());
672 : }
673 : }
674 1515541 : }
675 :
676 1637157 : ACCESSORS(JSValue, value, Object, kValueOffset)
677 :
678 1019339 : ACCESSORS(JSDate, value, Object, kValueOffset)
679 498396 : ACCESSORS(JSDate, cache_stamp, Object, kCacheStampOffset)
680 37287 : ACCESSORS(JSDate, year, Object, kYearOffset)
681 35343 : ACCESSORS(JSDate, month, Object, kMonthOffset)
682 34830 : ACCESSORS(JSDate, day, Object, kDayOffset)
683 34614 : ACCESSORS(JSDate, weekday, Object, kWeekdayOffset)
684 44064 : ACCESSORS(JSDate, hour, Object, kHourOffset)
685 37152 : ACCESSORS(JSDate, min, Object, kMinOffset)
686 35289 : ACCESSORS(JSDate, sec, Object, kSecOffset)
687 :
688 : MessageTemplate JSMessageObject::type() const {
689 8706 : Object value = READ_FIELD(this, kTypeOffset);
690 4353 : return MessageTemplateFromInt(Smi::ToInt(value));
691 : }
692 : void JSMessageObject::set_type(MessageTemplate value) {
693 1368822 : WRITE_FIELD(this, kTypeOffset, Smi::FromInt(static_cast<int>(value)));
694 : }
695 6902605 : ACCESSORS(JSMessageObject, argument, Object, kArgumentsOffset)
696 6989472 : ACCESSORS(JSMessageObject, script, Script, kScriptOffset)
697 6850302 : ACCESSORS(JSMessageObject, stack_frames, Object, kStackFramesOffset)
698 1491720 : SMI_ACCESSORS(JSMessageObject, start_position, kStartPositionOffset)
699 1394250 : SMI_ACCESSORS(JSMessageObject, end_position, kEndPositionOffset)
700 1413874 : SMI_ACCESSORS(JSMessageObject, error_level, kErrorLevelOffset)
701 :
702 342541506 : ElementsKind JSObject::GetElementsKind() const {
703 : ElementsKind kind = map()->elements_kind();
704 : #if VERIFY_HEAP && DEBUG
705 : FixedArrayBase fixed_array =
706 : FixedArrayBase::unchecked_cast(READ_FIELD(this, kElementsOffset));
707 :
708 : // If a GC was caused while constructing this object, the elements
709 : // pointer may point to a one pointer filler map.
710 : if (ElementsAreSafeToExamine()) {
711 : Map map = fixed_array->map();
712 : if (IsSmiOrObjectElementsKind(kind)) {
713 : DCHECK(map == GetReadOnlyRoots().fixed_array_map() ||
714 : map == GetReadOnlyRoots().fixed_cow_array_map());
715 : } else if (IsDoubleElementsKind(kind)) {
716 : DCHECK(fixed_array->IsFixedDoubleArray() ||
717 : fixed_array == GetReadOnlyRoots().empty_fixed_array());
718 : } else if (kind == DICTIONARY_ELEMENTS) {
719 : DCHECK(fixed_array->IsFixedArray());
720 : DCHECK(fixed_array->IsDictionary());
721 : } else {
722 : DCHECK(kind > DICTIONARY_ELEMENTS);
723 : }
724 : DCHECK(!IsSloppyArgumentsElementsKind(kind) ||
725 : (elements()->IsFixedArray() && elements()->length() >= 2));
726 : }
727 : #endif
728 342541506 : return kind;
729 : }
730 :
731 1569149 : bool JSObject::HasObjectElements() {
732 3560976 : return IsObjectElementsKind(GetElementsKind());
733 : }
734 :
735 2117154 : bool JSObject::HasSmiElements() { return IsSmiElementsKind(GetElementsKind()); }
736 :
737 1350000 : bool JSObject::HasSmiOrObjectElements() {
738 2704512 : return IsSmiOrObjectElementsKind(GetElementsKind());
739 : }
740 :
741 1353078 : bool JSObject::HasDoubleElements() {
742 3554274 : return IsDoubleElementsKind(GetElementsKind());
743 : }
744 :
745 4953404 : bool JSObject::HasHoleyElements() {
746 9906808 : return IsHoleyElementsKind(GetElementsKind());
747 : }
748 :
749 90758 : bool JSObject::HasFastElements() {
750 2837681 : return IsFastElementsKind(GetElementsKind());
751 : }
752 :
753 113156 : bool JSObject::HasFastPackedElements() {
754 226312 : return IsFastPackedElementsKind(GetElementsKind());
755 : }
756 :
757 621 : bool JSObject::HasDictionaryElements() {
758 504914 : return GetElementsKind() == DICTIONARY_ELEMENTS;
759 : }
760 :
761 : bool JSObject::HasFastArgumentsElements() {
762 : return GetElementsKind() == FAST_SLOPPY_ARGUMENTS_ELEMENTS;
763 : }
764 :
765 : bool JSObject::HasSlowArgumentsElements() {
766 159692 : return GetElementsKind() == SLOW_SLOPPY_ARGUMENTS_ELEMENTS;
767 : }
768 :
769 63 : bool JSObject::HasSloppyArgumentsElements() {
770 917126 : return IsSloppyArgumentsElementsKind(GetElementsKind());
771 : }
772 :
773 : bool JSObject::HasStringWrapperElements() {
774 115592 : return IsStringWrapperElementsKind(GetElementsKind());
775 : }
776 :
777 : bool JSObject::HasFastStringWrapperElements() {
778 1083162 : return GetElementsKind() == FAST_STRING_WRAPPER_ELEMENTS;
779 : }
780 :
781 : bool JSObject::HasSlowStringWrapperElements() {
782 251054 : return GetElementsKind() == SLOW_STRING_WRAPPER_ELEMENTS;
783 : }
784 :
785 1571970 : bool JSObject::HasFixedTypedArrayElements() {
786 : DCHECK(!elements().is_null());
787 1571970 : return map()->has_fixed_typed_array_elements();
788 : }
789 :
790 : #define FIXED_TYPED_ELEMENTS_CHECK(Type, type, TYPE, ctype) \
791 : bool JSObject::HasFixed##Type##Elements() { \
792 : FixedArrayBase array = elements(); \
793 : return array->map()->instance_type() == FIXED_##TYPE##_ARRAY_TYPE; \
794 : }
795 :
796 900 : TYPED_ARRAYS(FIXED_TYPED_ELEMENTS_CHECK)
797 :
798 : #undef FIXED_TYPED_ELEMENTS_CHECK
799 :
800 6302562 : bool JSObject::HasNamedInterceptor() { return map()->has_named_interceptor(); }
801 :
802 1227981 : bool JSObject::HasIndexedInterceptor() {
803 1227981 : return map()->has_indexed_interceptor();
804 : }
805 :
806 : void JSGlobalObject::set_global_dictionary(GlobalDictionary dictionary) {
807 : DCHECK(IsJSGlobalObject());
808 92870 : set_raw_properties_or_hash(dictionary);
809 : }
810 :
811 80129426 : GlobalDictionary JSGlobalObject::global_dictionary() {
812 : DCHECK(!HasFastProperties());
813 : DCHECK(IsJSGlobalObject());
814 160258865 : return GlobalDictionary::cast(raw_properties_or_hash());
815 : }
816 :
817 15176 : NumberDictionary JSObject::element_dictionary() {
818 : DCHECK(HasDictionaryElements() || HasSlowStringWrapperElements());
819 30352 : return NumberDictionary::cast(elements());
820 : }
821 :
822 15522447 : void JSReceiver::initialize_properties() {
823 15522447 : ReadOnlyRoots roots = GetReadOnlyRoots();
824 : DCHECK(!Heap::InNewSpace(roots.empty_fixed_array()));
825 : DCHECK(!Heap::InNewSpace(roots.empty_property_dictionary()));
826 15522455 : if (map()->is_dictionary_map()) {
827 32 : WRITE_FIELD(this, kPropertiesOrHashOffset,
828 : roots.empty_property_dictionary());
829 : } else {
830 15522417 : WRITE_FIELD(this, kPropertiesOrHashOffset, roots.empty_fixed_array());
831 : }
832 15522449 : }
833 :
834 111209579 : bool JSReceiver::HasFastProperties() const {
835 : DCHECK(
836 : raw_properties_or_hash()->IsSmi() ||
837 : (raw_properties_or_hash()->IsDictionary() == map()->is_dictionary_map()));
838 111209579 : return !map()->is_dictionary_map();
839 : }
840 :
841 13182765 : NameDictionary JSReceiver::property_dictionary() const {
842 : DCHECK(!IsJSGlobalObject());
843 : DCHECK(!HasFastProperties());
844 :
845 13182765 : Object prop = raw_properties_or_hash();
846 13182769 : if (prop->IsSmi()) {
847 18 : return GetReadOnlyRoots().empty_property_dictionary();
848 : }
849 :
850 : return NameDictionary::cast(prop);
851 : }
852 :
853 : // TODO(gsathya): Pass isolate directly to this function and access
854 : // the heap from this.
855 79923548 : PropertyArray JSReceiver::property_array() const {
856 : DCHECK(HasFastProperties());
857 :
858 79923548 : Object prop = raw_properties_or_hash();
859 159845167 : if (prop->IsSmi() || prop == GetReadOnlyRoots().empty_fixed_array()) {
860 19062252 : return GetReadOnlyRoots().empty_property_array();
861 : }
862 :
863 : return PropertyArray::cast(prop);
864 : }
865 :
866 655795 : Maybe<bool> JSReceiver::HasProperty(Handle<JSReceiver> object,
867 : Handle<Name> name) {
868 : LookupIterator it = LookupIterator::PropertyOrElement(object->GetIsolate(),
869 655795 : object, name, object);
870 655795 : return HasProperty(&it);
871 : }
872 :
873 5668 : Maybe<bool> JSReceiver::HasOwnProperty(Handle<JSReceiver> object,
874 : uint32_t index) {
875 11336 : if (object->IsJSModuleNamespace()) return Just(false);
876 :
877 11336 : if (object->IsJSObject()) { // Shortcut.
878 : LookupIterator it(object->GetIsolate(), object, index, object,
879 : LookupIterator::OWN);
880 5587 : return HasProperty(&it);
881 : }
882 :
883 : Maybe<PropertyAttributes> attributes =
884 81 : JSReceiver::GetOwnPropertyAttributes(object, index);
885 81 : MAYBE_RETURN(attributes, Nothing<bool>());
886 81 : return Just(attributes.FromJust() != ABSENT);
887 : }
888 :
889 6880458 : Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
890 : Handle<JSReceiver> object, Handle<Name> name) {
891 : LookupIterator it = LookupIterator::PropertyOrElement(object->GetIsolate(),
892 6880458 : object, name, object);
893 6880458 : return GetPropertyAttributes(&it);
894 : }
895 :
896 629107 : Maybe<PropertyAttributes> JSReceiver::GetOwnPropertyAttributes(
897 : Handle<JSReceiver> object, Handle<Name> name) {
898 : LookupIterator it = LookupIterator::PropertyOrElement(
899 629107 : object->GetIsolate(), object, name, object, LookupIterator::OWN);
900 629107 : return GetPropertyAttributes(&it);
901 : }
902 :
903 81 : Maybe<PropertyAttributes> JSReceiver::GetOwnPropertyAttributes(
904 : Handle<JSReceiver> object, uint32_t index) {
905 : LookupIterator it(object->GetIsolate(), object, index, object,
906 : LookupIterator::OWN);
907 81 : return GetPropertyAttributes(&it);
908 : }
909 :
910 1745566 : Maybe<bool> JSReceiver::HasElement(Handle<JSReceiver> object, uint32_t index) {
911 : LookupIterator it(object->GetIsolate(), object, index, object);
912 1745566 : return HasProperty(&it);
913 : }
914 :
915 : Maybe<PropertyAttributes> JSReceiver::GetElementAttributes(
916 : Handle<JSReceiver> object, uint32_t index) {
917 : Isolate* isolate = object->GetIsolate();
918 : LookupIterator it(isolate, object, index, object);
919 : return GetPropertyAttributes(&it);
920 : }
921 :
922 : Maybe<PropertyAttributes> JSReceiver::GetOwnElementAttributes(
923 : Handle<JSReceiver> object, uint32_t index) {
924 : Isolate* isolate = object->GetIsolate();
925 : LookupIterator it(isolate, object, index, object, LookupIterator::OWN);
926 : return GetPropertyAttributes(&it);
927 : }
928 :
929 : bool JSGlobalObject::IsDetached() {
930 : return JSGlobalProxy::cast(global_proxy())->IsDetachedFrom(*this);
931 : }
932 :
933 492334 : bool JSGlobalProxy::IsDetachedFrom(JSGlobalObject global) const {
934 : const PrototypeIterator iter(this->GetIsolate(), *this);
935 984668 : return iter.GetCurrent() != global;
936 : }
937 :
938 : inline int JSGlobalProxy::SizeWithEmbedderFields(int embedder_field_count) {
939 : DCHECK_GE(embedder_field_count, 0);
940 91805 : return kSize + embedder_field_count * kEmbedderDataSlotSize;
941 : }
942 :
943 113061 : ACCESSORS(JSIteratorResult, value, Object, kValueOffset)
944 108585 : ACCESSORS(JSIteratorResult, done, Object, kDoneOffset)
945 :
946 1050 : ACCESSORS(JSAsyncFromSyncIterator, sync_iterator, JSReceiver,
947 : kSyncIteratorOffset)
948 1050 : ACCESSORS(JSAsyncFromSyncIterator, next, Object, kNextOffset)
949 :
950 0 : ACCESSORS(JSStringIterator, string, String, kStringOffset)
951 0 : SMI_ACCESSORS(JSStringIterator, index, kNextIndexOffset)
952 :
953 : } // namespace internal
954 : } // namespace v8
955 :
956 : #include "src/objects/object-macros-undef.h"
957 :
958 : #endif // V8_OBJECTS_JS_OBJECTS_INL_H_
|