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/common/globals.h"
9 #include "src/heap/heap-write-barrier.h"
10 #include "src/objects/elements.h"
11 #include "src/objects/embedder-data-slot-inl.h"
12 #include "src/objects/feedback-vector.h"
13 #include "src/objects/field-index-inl.h"
14 #include "src/objects/hash-table-inl.h"
15 #include "src/objects/heap-number-inl.h"
16 #include "src/objects/js-objects.h"
17 #include "src/objects/keys.h"
18 #include "src/objects/lookup-inl.h"
19 #include "src/objects/property-array-inl.h"
20 #include "src/objects/prototype-inl.h"
21 #include "src/objects/shared-function-info.h"
22 #include "src/objects/slots.h"
23 #include "src/objects/smi-inl.h"
24 
25 // Has to be the last include (doesn't have include guards):
26 #include "src/objects/object-macros.h"
27 
28 namespace v8 {
29 namespace internal {
30 
31 #include "torque-generated/src/objects/js-objects-tq-inl.inc"
32 
OBJECT_CONSTRUCTORS_IMPL(JSReceiver,HeapObject)33 OBJECT_CONSTRUCTORS_IMPL(JSReceiver, HeapObject)
34 TQ_OBJECT_CONSTRUCTORS_IMPL(JSObject)
35 TQ_OBJECT_CONSTRUCTORS_IMPL(JSCustomElementsObject)
36 TQ_OBJECT_CONSTRUCTORS_IMPL(JSSpecialObject)
37 TQ_OBJECT_CONSTRUCTORS_IMPL(JSAsyncFromSyncIterator)
38 TQ_OBJECT_CONSTRUCTORS_IMPL(JSDate)
39 OBJECT_CONSTRUCTORS_IMPL(JSGlobalObject, JSSpecialObject)
40 TQ_OBJECT_CONSTRUCTORS_IMPL(JSGlobalProxy)
41 JSIteratorResult::JSIteratorResult(Address ptr) : JSObject(ptr) {}
OBJECT_CONSTRUCTORS_IMPL(JSMessageObject,JSObject)42 OBJECT_CONSTRUCTORS_IMPL(JSMessageObject, JSObject)
43 TQ_OBJECT_CONSTRUCTORS_IMPL(JSPrimitiveWrapper)
44 TQ_OBJECT_CONSTRUCTORS_IMPL(JSStringIterator)
45 
46 NEVER_READ_ONLY_SPACE_IMPL(JSReceiver)
47 
48 CAST_ACCESSOR(JSGlobalObject)
49 CAST_ACCESSOR(JSIteratorResult)
50 CAST_ACCESSOR(JSMessageObject)
51 CAST_ACCESSOR(JSReceiver)
52 
53 MaybeHandle<Object> JSReceiver::GetProperty(Isolate* isolate,
54                                             Handle<JSReceiver> receiver,
55                                             Handle<Name> name) {
56   LookupIterator it(isolate, receiver, name, receiver);
57   if (!it.IsFound()) return it.factory()->undefined_value();
58   return Object::GetProperty(&it);
59 }
60 
GetElement(Isolate * isolate,Handle<JSReceiver> receiver,uint32_t index)61 MaybeHandle<Object> JSReceiver::GetElement(Isolate* isolate,
62                                            Handle<JSReceiver> receiver,
63                                            uint32_t index) {
64   LookupIterator it(isolate, receiver, index, receiver);
65   if (!it.IsFound()) return it.factory()->undefined_value();
66   return Object::GetProperty(&it);
67 }
68 
GetDataProperty(Handle<JSReceiver> object,Handle<Name> name)69 Handle<Object> JSReceiver::GetDataProperty(Handle<JSReceiver> object,
70                                            Handle<Name> name) {
71   LookupIterator it(object->GetIsolate(), object, name, object,
72                     LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
73   if (!it.IsFound()) return it.factory()->undefined_value();
74   return GetDataProperty(&it);
75 }
76 
GetPrototype(Isolate * isolate,Handle<JSReceiver> receiver)77 MaybeHandle<HeapObject> JSReceiver::GetPrototype(Isolate* isolate,
78                                                  Handle<JSReceiver> receiver) {
79   // We don't expect access checks to be needed on JSProxy objects.
80   DCHECK(!receiver->IsAccessCheckNeeded() || receiver->IsJSObject());
81   PrototypeIterator iter(isolate, receiver, kStartAtReceiver,
82                          PrototypeIterator::END_AT_NON_HIDDEN);
83   do {
84     if (!iter.AdvanceFollowingProxies()) return MaybeHandle<HeapObject>();
85   } while (!iter.IsAtEnd());
86   return PrototypeIterator::GetCurrent(iter);
87 }
88 
GetProperty(Isolate * isolate,Handle<JSReceiver> receiver,const char * name)89 MaybeHandle<Object> JSReceiver::GetProperty(Isolate* isolate,
90                                             Handle<JSReceiver> receiver,
91                                             const char* name) {
92   Handle<String> str = isolate->factory()->InternalizeUtf8String(name);
93   return GetProperty(isolate, receiver, str);
94 }
95 
96 // static
OwnPropertyKeys(Handle<JSReceiver> object)97 V8_WARN_UNUSED_RESULT MaybeHandle<FixedArray> JSReceiver::OwnPropertyKeys(
98     Handle<JSReceiver> object) {
99   return KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly,
100                                  ALL_PROPERTIES,
101                                  GetKeysConversion::kConvertToString);
102 }
103 
PrototypeHasNoElements(Isolate * isolate,JSObject object)104 bool JSObject::PrototypeHasNoElements(Isolate* isolate, JSObject object) {
105   DisallowHeapAllocation no_gc;
106   HeapObject prototype = HeapObject::cast(object.map().prototype());
107   ReadOnlyRoots roots(isolate);
108   HeapObject null = roots.null_value();
109   FixedArrayBase empty_fixed_array = roots.empty_fixed_array();
110   FixedArrayBase empty_slow_element_dictionary =
111       roots.empty_slow_element_dictionary();
112   while (prototype != null) {
113     Map map = prototype.map();
114     if (map.IsCustomElementsReceiverMap()) return false;
115     FixedArrayBase elements = JSObject::cast(prototype).elements();
116     if (elements != empty_fixed_array &&
117         elements != empty_slow_element_dictionary) {
118       return false;
119     }
120     prototype = HeapObject::cast(map.prototype());
121   }
122   return true;
123 }
124 
ACCESSORS(JSReceiver,raw_properties_or_hash,Object,kPropertiesOrHashOffset)125 ACCESSORS(JSReceiver, raw_properties_or_hash, Object, kPropertiesOrHashOffset)
126 
127 void JSObject::EnsureCanContainHeapObjectElements(Handle<JSObject> object) {
128   JSObject::ValidateElements(*object);
129   ElementsKind elements_kind = object->map().elements_kind();
130   if (!IsObjectElementsKind(elements_kind)) {
131     if (IsHoleyElementsKind(elements_kind)) {
132       TransitionElementsKind(object, HOLEY_ELEMENTS);
133     } else {
134       TransitionElementsKind(object, PACKED_ELEMENTS);
135     }
136   }
137 }
138 
139 template <typename TSlot>
EnsureCanContainElements(Handle<JSObject> object,TSlot objects,uint32_t count,EnsureElementsMode mode)140 void JSObject::EnsureCanContainElements(Handle<JSObject> object, TSlot objects,
141                                         uint32_t count,
142                                         EnsureElementsMode mode) {
143   static_assert(std::is_same<TSlot, FullObjectSlot>::value ||
144                     std::is_same<TSlot, ObjectSlot>::value,
145                 "Only ObjectSlot and FullObjectSlot are expected here");
146   ElementsKind current_kind = object->GetElementsKind();
147   ElementsKind target_kind = current_kind;
148   {
149     DisallowHeapAllocation no_allocation;
150     DCHECK(mode != ALLOW_COPIED_DOUBLE_ELEMENTS);
151     bool is_holey = IsHoleyElementsKind(current_kind);
152     if (current_kind == HOLEY_ELEMENTS) return;
153     Object the_hole = object->GetReadOnlyRoots().the_hole_value();
154     for (uint32_t i = 0; i < count; ++i, ++objects) {
155       Object current = *objects;
156       if (current == the_hole) {
157         is_holey = true;
158         target_kind = GetHoleyElementsKind(target_kind);
159       } else if (!current.IsSmi()) {
160         if (mode == ALLOW_CONVERTED_DOUBLE_ELEMENTS && current.IsNumber()) {
161           if (IsSmiElementsKind(target_kind)) {
162             if (is_holey) {
163               target_kind = HOLEY_DOUBLE_ELEMENTS;
164             } else {
165               target_kind = PACKED_DOUBLE_ELEMENTS;
166             }
167           }
168         } else if (is_holey) {
169           target_kind = HOLEY_ELEMENTS;
170           break;
171         } else {
172           target_kind = PACKED_ELEMENTS;
173         }
174       }
175     }
176   }
177   if (target_kind != current_kind) {
178     TransitionElementsKind(object, target_kind);
179   }
180 }
181 
EnsureCanContainElements(Handle<JSObject> object,Handle<FixedArrayBase> elements,uint32_t length,EnsureElementsMode mode)182 void JSObject::EnsureCanContainElements(Handle<JSObject> object,
183                                         Handle<FixedArrayBase> elements,
184                                         uint32_t length,
185                                         EnsureElementsMode mode) {
186   ReadOnlyRoots roots = object->GetReadOnlyRoots();
187   if (elements->map() != roots.fixed_double_array_map()) {
188     DCHECK(elements->map() == roots.fixed_array_map() ||
189            elements->map() == roots.fixed_cow_array_map());
190     if (mode == ALLOW_COPIED_DOUBLE_ELEMENTS) {
191       mode = DONT_ALLOW_DOUBLE_ELEMENTS;
192     }
193     ObjectSlot objects =
194         Handle<FixedArray>::cast(elements)->GetFirstElementAddress();
195     EnsureCanContainElements(object, objects, length, mode);
196     return;
197   }
198 
199   DCHECK(mode == ALLOW_COPIED_DOUBLE_ELEMENTS);
200   if (object->GetElementsKind() == HOLEY_SMI_ELEMENTS) {
201     TransitionElementsKind(object, HOLEY_DOUBLE_ELEMENTS);
202   } else if (object->GetElementsKind() == PACKED_SMI_ELEMENTS) {
203     Handle<FixedDoubleArray> double_array =
204         Handle<FixedDoubleArray>::cast(elements);
205     for (uint32_t i = 0; i < length; ++i) {
206       if (double_array->is_the_hole(i)) {
207         TransitionElementsKind(object, HOLEY_DOUBLE_ELEMENTS);
208         return;
209       }
210     }
211     TransitionElementsKind(object, PACKED_DOUBLE_ELEMENTS);
212   }
213 }
214 
SetMapAndElements(Handle<JSObject> object,Handle<Map> new_map,Handle<FixedArrayBase> value)215 void JSObject::SetMapAndElements(Handle<JSObject> object, Handle<Map> new_map,
216                                  Handle<FixedArrayBase> value) {
217   Isolate* isolate = object->GetIsolate();
218   JSObject::MigrateToMap(isolate, object, new_map);
219   DCHECK((object->map().has_fast_smi_or_object_elements() ||
220           (*value == ReadOnlyRoots(isolate).empty_fixed_array()) ||
221           object->map().has_fast_string_wrapper_elements()) ==
222          (value->map() == ReadOnlyRoots(isolate).fixed_array_map() ||
223           value->map() == ReadOnlyRoots(isolate).fixed_cow_array_map()));
224   DCHECK((*value == ReadOnlyRoots(isolate).empty_fixed_array()) ||
225          (object->map().has_fast_double_elements() ==
226           value->IsFixedDoubleArray()));
227   object->set_elements(*value);
228 }
229 
initialize_elements()230 void JSObject::initialize_elements() {
231   FixedArrayBase elements = map().GetInitialElements();
232   set_elements(elements, SKIP_WRITE_BARRIER);
233 }
234 
DEF_GETTER(JSObject,GetIndexedInterceptor,InterceptorInfo)235 DEF_GETTER(JSObject, GetIndexedInterceptor, InterceptorInfo) {
236   return map(isolate).GetIndexedInterceptor(isolate);
237 }
238 
DEF_GETTER(JSObject,GetNamedInterceptor,InterceptorInfo)239 DEF_GETTER(JSObject, GetNamedInterceptor, InterceptorInfo) {
240   return map(isolate).GetNamedInterceptor(isolate);
241 }
242 
243 // static
GetHeaderSize(Map map)244 int JSObject::GetHeaderSize(Map map) {
245   // Check for the most common kind of JavaScript object before
246   // falling into the generic switch. This speeds up the internal
247   // field operations considerably on average.
248   InstanceType instance_type = map.instance_type();
249   return instance_type == JS_OBJECT_TYPE
250              ? JSObject::kHeaderSize
251              : GetHeaderSize(instance_type, map.has_prototype_slot());
252 }
253 
254 // static
GetEmbedderFieldsStartOffset(Map map)255 int JSObject::GetEmbedderFieldsStartOffset(Map map) {
256   // Embedder fields are located after the object header.
257   return GetHeaderSize(map);
258 }
259 
GetEmbedderFieldsStartOffset()260 int JSObject::GetEmbedderFieldsStartOffset() {
261   return GetEmbedderFieldsStartOffset(map());
262 }
263 
264 // static
GetEmbedderFieldCount(Map map)265 int JSObject::GetEmbedderFieldCount(Map map) {
266   int instance_size = map.instance_size();
267   if (instance_size == kVariableSizeSentinel) return 0;
268   // Embedder fields are located after the object header, whereas in-object
269   // properties are located at the end of the object. We don't have to round up
270   // the header size here because division by kEmbedderDataSlotSizeInTaggedSlots
271   // will swallow potential padding in case of (kTaggedSize !=
272   // kSystemPointerSize) anyway.
273   return (((instance_size - GetEmbedderFieldsStartOffset(map)) >>
274            kTaggedSizeLog2) -
275           map.GetInObjectProperties()) /
276          kEmbedderDataSlotSizeInTaggedSlots;
277 }
278 
GetEmbedderFieldCount()279 int JSObject::GetEmbedderFieldCount() const {
280   return GetEmbedderFieldCount(map());
281 }
282 
GetEmbedderFieldOffset(int index)283 int JSObject::GetEmbedderFieldOffset(int index) {
284   DCHECK_LT(static_cast<unsigned>(index),
285             static_cast<unsigned>(GetEmbedderFieldCount()));
286   return GetEmbedderFieldsStartOffset() + (kEmbedderDataSlotSize * index);
287 }
288 
InitializeEmbedderField(Isolate * isolate,int index)289 void JSObject::InitializeEmbedderField(Isolate* isolate, int index) {
290   EmbedderDataSlot(*this, index).AllocateExternalPointerEntry(isolate);
291 }
292 
GetEmbedderField(int index)293 Object JSObject::GetEmbedderField(int index) {
294   return EmbedderDataSlot(*this, index).load_tagged();
295 }
296 
SetEmbedderField(int index,Object value)297 void JSObject::SetEmbedderField(int index, Object value) {
298   EmbedderDataSlot::store_tagged(*this, index, value);
299 }
300 
SetEmbedderField(int index,Smi value)301 void JSObject::SetEmbedderField(int index, Smi value) {
302   EmbedderDataSlot(*this, index).store_smi(value);
303 }
304 
IsUnboxedDoubleField(FieldIndex index)305 bool JSObject::IsUnboxedDoubleField(FieldIndex index) const {
306   IsolateRoot isolate = GetIsolateForPtrCompr(*this);
307   return IsUnboxedDoubleField(isolate, index);
308 }
309 
IsUnboxedDoubleField(IsolateRoot isolate,FieldIndex index)310 bool JSObject::IsUnboxedDoubleField(IsolateRoot isolate,
311                                     FieldIndex index) const {
312   if (!FLAG_unbox_double_fields) return false;
313   return map(isolate).IsUnboxedDoubleField(isolate, index);
314 }
315 
316 // Access fast-case object properties at index. The use of these routines
317 // is needed to correctly distinguish between properties stored in-object and
318 // properties stored in the properties array.
RawFastPropertyAt(FieldIndex index)319 Object JSObject::RawFastPropertyAt(FieldIndex index) const {
320   IsolateRoot isolate = GetIsolateForPtrCompr(*this);
321   return RawFastPropertyAt(isolate, index);
322 }
323 
RawFastPropertyAt(IsolateRoot isolate,FieldIndex index)324 Object JSObject::RawFastPropertyAt(IsolateRoot isolate,
325                                    FieldIndex index) const {
326   DCHECK(!IsUnboxedDoubleField(isolate, index));
327   if (index.is_inobject()) {
328     return TaggedField<Object>::load(isolate, *this, index.offset());
329   } else {
330     return property_array(isolate).get(isolate, index.outobject_array_index());
331   }
332 }
333 
RawFastDoublePropertyAt(FieldIndex index)334 double JSObject::RawFastDoublePropertyAt(FieldIndex index) const {
335   DCHECK(IsUnboxedDoubleField(index));
336   return ReadField<double>(index.offset());
337 }
338 
RawFastDoublePropertyAsBitsAt(FieldIndex index)339 uint64_t JSObject::RawFastDoublePropertyAsBitsAt(FieldIndex index) const {
340   DCHECK(IsUnboxedDoubleField(index));
341   return ReadField<uint64_t>(index.offset());
342 }
343 
RawFastInobjectPropertyAtPut(FieldIndex index,Object value,WriteBarrierMode mode)344 void JSObject::RawFastInobjectPropertyAtPut(FieldIndex index, Object value,
345                                             WriteBarrierMode mode) {
346   DCHECK(index.is_inobject());
347   int offset = index.offset();
348   WRITE_FIELD(*this, offset, value);
349   CONDITIONAL_WRITE_BARRIER(*this, offset, value, mode);
350 }
351 
RawFastPropertyAtPut(FieldIndex index,Object value,WriteBarrierMode mode)352 void JSObject::RawFastPropertyAtPut(FieldIndex index, Object value,
353                                     WriteBarrierMode mode) {
354   if (index.is_inobject()) {
355     RawFastInobjectPropertyAtPut(index, value, mode);
356   } else {
357     DCHECK_EQ(UPDATE_WRITE_BARRIER, mode);
358     property_array().set(index.outobject_array_index(), value);
359   }
360 }
361 
RawFastDoublePropertyAsBitsAtPut(FieldIndex index,uint64_t bits)362 void JSObject::RawFastDoublePropertyAsBitsAtPut(FieldIndex index,
363                                                 uint64_t bits) {
364   // Double unboxing is enabled only on 64-bit platforms without pointer
365   // compression.
366   DCHECK_EQ(kDoubleSize, kTaggedSize);
367   Address field_addr = field_address(index.offset());
368   base::Relaxed_Store(reinterpret_cast<base::AtomicWord*>(field_addr),
369                       static_cast<base::AtomicWord>(bits));
370 }
371 
FastPropertyAtPut(FieldIndex index,Object value)372 void JSObject::FastPropertyAtPut(FieldIndex index, Object value) {
373   if (IsUnboxedDoubleField(index)) {
374     DCHECK(value.IsHeapNumber());
375     // Ensure that all bits of the double value are preserved.
376     RawFastDoublePropertyAsBitsAtPut(index,
377                                      HeapNumber::cast(value).value_as_bits());
378   } else {
379     RawFastPropertyAtPut(index, value);
380   }
381 }
382 
WriteToField(InternalIndex descriptor,PropertyDetails details,Object value)383 void JSObject::WriteToField(InternalIndex descriptor, PropertyDetails details,
384                             Object value) {
385   DCHECK_EQ(kField, details.location());
386   DCHECK_EQ(kData, details.kind());
387   DisallowHeapAllocation no_gc;
388   FieldIndex index = FieldIndex::ForDescriptor(map(), descriptor);
389   if (details.representation().IsDouble()) {
390     // Manipulating the signaling NaN used for the hole and uninitialized
391     // double field sentinel in C++, e.g. with bit_cast or value()/set_value(),
392     // will change its value on ia32 (the x87 stack is used to return values
393     // and stores to the stack silently clear the signalling bit).
394     uint64_t bits;
395     if (value.IsSmi()) {
396       bits = bit_cast<uint64_t>(static_cast<double>(Smi::ToInt(value)));
397     } else if (value.IsUninitialized()) {
398       bits = kHoleNanInt64;
399     } else {
400       DCHECK(value.IsHeapNumber());
401       bits = HeapNumber::cast(value).value_as_bits();
402     }
403     if (IsUnboxedDoubleField(index)) {
404       RawFastDoublePropertyAsBitsAtPut(index, bits);
405     } else {
406       auto box = HeapNumber::cast(RawFastPropertyAt(index));
407       box.set_value_as_bits(bits);
408     }
409   } else {
410     RawFastPropertyAtPut(index, value);
411   }
412 }
413 
GetInObjectPropertyOffset(int index)414 int JSObject::GetInObjectPropertyOffset(int index) {
415   return map().GetInObjectPropertyOffset(index);
416 }
417 
InObjectPropertyAt(int index)418 Object JSObject::InObjectPropertyAt(int index) {
419   int offset = GetInObjectPropertyOffset(index);
420   return TaggedField<Object>::load(*this, offset);
421 }
422 
InObjectPropertyAtPut(int index,Object value,WriteBarrierMode mode)423 Object JSObject::InObjectPropertyAtPut(int index, Object value,
424                                        WriteBarrierMode mode) {
425   // Adjust for the number of properties stored in the object.
426   int offset = GetInObjectPropertyOffset(index);
427   WRITE_FIELD(*this, offset, value);
428   CONDITIONAL_WRITE_BARRIER(*this, offset, value, mode);
429   return value;
430 }
431 
InitializeBody(Map map,int start_offset,Object pre_allocated_value,Object filler_value)432 void JSObject::InitializeBody(Map map, int start_offset,
433                               Object pre_allocated_value, Object filler_value) {
434   DCHECK_IMPLIES(filler_value.IsHeapObject(),
435                  !ObjectInYoungGeneration(filler_value));
436   DCHECK_IMPLIES(pre_allocated_value.IsHeapObject(),
437                  !ObjectInYoungGeneration(pre_allocated_value));
438   int size = map.instance_size();
439   int offset = start_offset;
440   if (filler_value != pre_allocated_value) {
441     int end_of_pre_allocated_offset =
442         size - (map.UnusedPropertyFields() * kTaggedSize);
443     DCHECK_LE(kHeaderSize, end_of_pre_allocated_offset);
444     while (offset < end_of_pre_allocated_offset) {
445       WRITE_FIELD(*this, offset, pre_allocated_value);
446       offset += kTaggedSize;
447     }
448   }
449   while (offset < size) {
450     WRITE_FIELD(*this, offset, filler_value);
451     offset += kTaggedSize;
452   }
453 }
454 
ACCESSORS(JSGlobalObject,native_context,NativeContext,kNativeContextOffset)455 ACCESSORS(JSGlobalObject, native_context, NativeContext, kNativeContextOffset)
456 ACCESSORS(JSGlobalObject, global_proxy, JSGlobalProxy, kGlobalProxyOffset)
457 
458 DEF_GETTER(JSGlobalObject, native_context_unchecked, Object) {
459   return TaggedField<Object, kNativeContextOffset>::load(isolate, *this);
460 }
461 
DidEnsureSourcePositionsAvailable()462 bool JSMessageObject::DidEnsureSourcePositionsAvailable() const {
463   return shared_info().IsUndefined();
464 }
465 
GetStartPosition()466 int JSMessageObject::GetStartPosition() const {
467   DCHECK(DidEnsureSourcePositionsAvailable());
468   return start_position();
469 }
470 
GetEndPosition()471 int JSMessageObject::GetEndPosition() const {
472   DCHECK(DidEnsureSourcePositionsAvailable());
473   return end_position();
474 }
475 
type()476 MessageTemplate JSMessageObject::type() const {
477   return MessageTemplateFromInt(raw_type());
478 }
479 
set_type(MessageTemplate value)480 void JSMessageObject::set_type(MessageTemplate value) {
481   set_raw_type(static_cast<int>(value));
482 }
483 
ACCESSORS(JSMessageObject,argument,Object,kArgumentsOffset)484 ACCESSORS(JSMessageObject, argument, Object, kArgumentsOffset)
485 ACCESSORS(JSMessageObject, script, Script, kScriptOffset)
486 ACCESSORS(JSMessageObject, stack_frames, Object, kStackFramesOffset)
487 ACCESSORS(JSMessageObject, shared_info, HeapObject, kSharedInfoOffset)
488 ACCESSORS(JSMessageObject, bytecode_offset, Smi, kBytecodeOffsetOffset)
489 SMI_ACCESSORS(JSMessageObject, start_position, kStartPositionOffset)
490 SMI_ACCESSORS(JSMessageObject, end_position, kEndPositionOffset)
491 SMI_ACCESSORS(JSMessageObject, error_level, kErrorLevelOffset)
492 SMI_ACCESSORS(JSMessageObject, raw_type, kMessageTypeOffset)
493 
494 DEF_GETTER(JSObject, GetElementsKind, ElementsKind) {
495   ElementsKind kind = map(isolate).elements_kind();
496 #if VERIFY_HEAP && DEBUG
497   FixedArrayBase fixed_array = FixedArrayBase::unchecked_cast(
498       TaggedField<HeapObject, kElementsOffset>::load(isolate, *this));
499 
500   // If a GC was caused while constructing this object, the elements
501   // pointer may point to a one pointer filler map.
502   if (ElementsAreSafeToExamine(isolate)) {
503     Map map = fixed_array.map(isolate);
504     if (IsSmiOrObjectElementsKind(kind)) {
505       DCHECK(map == GetReadOnlyRoots(isolate).fixed_array_map() ||
506              map == GetReadOnlyRoots(isolate).fixed_cow_array_map());
507     } else if (IsDoubleElementsKind(kind)) {
508       DCHECK(fixed_array.IsFixedDoubleArray(isolate) ||
509              fixed_array == GetReadOnlyRoots(isolate).empty_fixed_array());
510     } else if (kind == DICTIONARY_ELEMENTS) {
511       DCHECK(fixed_array.IsFixedArray(isolate));
512       DCHECK(fixed_array.IsNumberDictionary(isolate));
513     } else {
514       DCHECK(kind > DICTIONARY_ELEMENTS ||
515              IsAnyNonextensibleElementsKind(kind));
516     }
517     DCHECK(!IsSloppyArgumentsElementsKind(kind) ||
518            elements(isolate).IsSloppyArgumentsElements());
519   }
520 #endif
521   return kind;
522 }
523 
DEF_GETTER(JSObject,GetElementsAccessor,ElementsAccessor *)524 DEF_GETTER(JSObject, GetElementsAccessor, ElementsAccessor*) {
525   return ElementsAccessor::ForKind(GetElementsKind(isolate));
526 }
527 
DEF_GETTER(JSObject,HasObjectElements,bool)528 DEF_GETTER(JSObject, HasObjectElements, bool) {
529   return IsObjectElementsKind(GetElementsKind(isolate));
530 }
531 
DEF_GETTER(JSObject,HasSmiElements,bool)532 DEF_GETTER(JSObject, HasSmiElements, bool) {
533   return IsSmiElementsKind(GetElementsKind(isolate));
534 }
535 
DEF_GETTER(JSObject,HasSmiOrObjectElements,bool)536 DEF_GETTER(JSObject, HasSmiOrObjectElements, bool) {
537   return IsSmiOrObjectElementsKind(GetElementsKind(isolate));
538 }
539 
DEF_GETTER(JSObject,HasDoubleElements,bool)540 DEF_GETTER(JSObject, HasDoubleElements, bool) {
541   return IsDoubleElementsKind(GetElementsKind(isolate));
542 }
543 
DEF_GETTER(JSObject,HasHoleyElements,bool)544 DEF_GETTER(JSObject, HasHoleyElements, bool) {
545   return IsHoleyElementsKind(GetElementsKind(isolate));
546 }
547 
DEF_GETTER(JSObject,HasFastElements,bool)548 DEF_GETTER(JSObject, HasFastElements, bool) {
549   return IsFastElementsKind(GetElementsKind(isolate));
550 }
551 
DEF_GETTER(JSObject,HasFastPackedElements,bool)552 DEF_GETTER(JSObject, HasFastPackedElements, bool) {
553   return IsFastPackedElementsKind(GetElementsKind(isolate));
554 }
555 
DEF_GETTER(JSObject,HasDictionaryElements,bool)556 DEF_GETTER(JSObject, HasDictionaryElements, bool) {
557   return IsDictionaryElementsKind(GetElementsKind(isolate));
558 }
559 
DEF_GETTER(JSObject,HasPackedElements,bool)560 DEF_GETTER(JSObject, HasPackedElements, bool) {
561   return GetElementsKind(isolate) == PACKED_ELEMENTS;
562 }
563 
DEF_GETTER(JSObject,HasAnyNonextensibleElements,bool)564 DEF_GETTER(JSObject, HasAnyNonextensibleElements, bool) {
565   return IsAnyNonextensibleElementsKind(GetElementsKind(isolate));
566 }
567 
DEF_GETTER(JSObject,HasSealedElements,bool)568 DEF_GETTER(JSObject, HasSealedElements, bool) {
569   return IsSealedElementsKind(GetElementsKind(isolate));
570 }
571 
DEF_GETTER(JSObject,HasNonextensibleElements,bool)572 DEF_GETTER(JSObject, HasNonextensibleElements, bool) {
573   return IsNonextensibleElementsKind(GetElementsKind(isolate));
574 }
575 
DEF_GETTER(JSObject,HasFastArgumentsElements,bool)576 DEF_GETTER(JSObject, HasFastArgumentsElements, bool) {
577   return IsFastArgumentsElementsKind(GetElementsKind(isolate));
578 }
579 
DEF_GETTER(JSObject,HasSlowArgumentsElements,bool)580 DEF_GETTER(JSObject, HasSlowArgumentsElements, bool) {
581   return IsSlowArgumentsElementsKind(GetElementsKind(isolate));
582 }
583 
DEF_GETTER(JSObject,HasSloppyArgumentsElements,bool)584 DEF_GETTER(JSObject, HasSloppyArgumentsElements, bool) {
585   return IsSloppyArgumentsElementsKind(GetElementsKind(isolate));
586 }
587 
DEF_GETTER(JSObject,HasStringWrapperElements,bool)588 DEF_GETTER(JSObject, HasStringWrapperElements, bool) {
589   return IsStringWrapperElementsKind(GetElementsKind(isolate));
590 }
591 
DEF_GETTER(JSObject,HasFastStringWrapperElements,bool)592 DEF_GETTER(JSObject, HasFastStringWrapperElements, bool) {
593   return GetElementsKind(isolate) == FAST_STRING_WRAPPER_ELEMENTS;
594 }
595 
DEF_GETTER(JSObject,HasSlowStringWrapperElements,bool)596 DEF_GETTER(JSObject, HasSlowStringWrapperElements, bool) {
597   return GetElementsKind(isolate) == SLOW_STRING_WRAPPER_ELEMENTS;
598 }
599 
DEF_GETTER(JSObject,HasTypedArrayElements,bool)600 DEF_GETTER(JSObject, HasTypedArrayElements, bool) {
601   DCHECK(!elements(isolate).is_null());
602   return map(isolate).has_typed_array_elements();
603 }
604 
605 #define FIXED_TYPED_ELEMENTS_CHECK(Type, type, TYPE, ctype) \
606   DEF_GETTER(JSObject, HasFixed##Type##Elements, bool) {    \
607     return map(isolate).elements_kind() == TYPE##_ELEMENTS; \
608   }
609 
610 TYPED_ARRAYS(FIXED_TYPED_ELEMENTS_CHECK)
611 
612 #undef FIXED_TYPED_ELEMENTS_CHECK
613 
DEF_GETTER(JSObject,HasNamedInterceptor,bool)614 DEF_GETTER(JSObject, HasNamedInterceptor, bool) {
615   return map(isolate).has_named_interceptor();
616 }
617 
DEF_GETTER(JSObject,HasIndexedInterceptor,bool)618 DEF_GETTER(JSObject, HasIndexedInterceptor, bool) {
619   return map(isolate).has_indexed_interceptor();
620 }
621 
DEF_GETTER(JSGlobalObject,global_dictionary,GlobalDictionary)622 DEF_GETTER(JSGlobalObject, global_dictionary, GlobalDictionary) {
623   DCHECK(!HasFastProperties(isolate));
624   DCHECK(IsJSGlobalObject(isolate));
625   return GlobalDictionary::cast(raw_properties_or_hash(isolate));
626 }
627 
set_global_dictionary(GlobalDictionary dictionary)628 void JSGlobalObject::set_global_dictionary(GlobalDictionary dictionary) {
629   DCHECK(IsJSGlobalObject());
630   set_raw_properties_or_hash(dictionary);
631 }
632 
DEF_GETTER(JSObject,element_dictionary,NumberDictionary)633 DEF_GETTER(JSObject, element_dictionary, NumberDictionary) {
634   DCHECK(HasDictionaryElements(isolate) ||
635          HasSlowStringWrapperElements(isolate));
636   return NumberDictionary::cast(elements(isolate));
637 }
638 
initialize_properties(Isolate * isolate)639 void JSReceiver::initialize_properties(Isolate* isolate) {
640   ReadOnlyRoots roots(isolate);
641   DCHECK(!ObjectInYoungGeneration(roots.empty_fixed_array()));
642   DCHECK(!ObjectInYoungGeneration(roots.empty_property_dictionary()));
643   DCHECK(!ObjectInYoungGeneration(roots.empty_ordered_property_dictionary()));
644   if (map(isolate).is_dictionary_map()) {
645     if (V8_DICT_MODE_PROTOTYPES_BOOL) {
646       WRITE_FIELD(*this, kPropertiesOrHashOffset,
647                   roots.empty_ordered_property_dictionary());
648     } else {
649       WRITE_FIELD(*this, kPropertiesOrHashOffset,
650                   roots.empty_property_dictionary());
651     }
652   } else {
653     WRITE_FIELD(*this, kPropertiesOrHashOffset, roots.empty_fixed_array());
654   }
655 }
656 
DEF_GETTER(JSReceiver,HasFastProperties,bool)657 DEF_GETTER(JSReceiver, HasFastProperties, bool) {
658   DCHECK(raw_properties_or_hash(isolate).IsSmi() ||
659          ((raw_properties_or_hash(isolate).IsGlobalDictionary(isolate) ||
660            raw_properties_or_hash(isolate).IsNameDictionary(isolate) ||
661            raw_properties_or_hash(isolate).IsOrderedNameDictionary(isolate)) ==
662           map(isolate).is_dictionary_map()));
663   return !map(isolate).is_dictionary_map();
664 }
665 
DEF_GETTER(JSReceiver,property_dictionary,NameDictionary)666 DEF_GETTER(JSReceiver, property_dictionary, NameDictionary) {
667   DCHECK(!IsJSGlobalObject(isolate));
668   DCHECK(!HasFastProperties(isolate));
669   DCHECK(!V8_DICT_MODE_PROTOTYPES_BOOL);
670 
671   // Can't use ReadOnlyRoots(isolate) as this isolate could be produced by
672   // i::GetIsolateForPtrCompr(HeapObject).
673   Object prop = raw_properties_or_hash(isolate);
674   if (prop.IsSmi()) {
675     return GetReadOnlyRoots(isolate).empty_property_dictionary();
676   }
677   return NameDictionary::cast(prop);
678 }
679 
DEF_GETTER(JSReceiver,property_dictionary_ordered,OrderedNameDictionary)680 DEF_GETTER(JSReceiver, property_dictionary_ordered, OrderedNameDictionary) {
681   DCHECK(!IsJSGlobalObject(isolate));
682   DCHECK(!HasFastProperties(isolate));
683   DCHECK(V8_DICT_MODE_PROTOTYPES_BOOL);
684 
685   // Can't use ReadOnlyRoots(isolate) as this isolate could be produced by
686   // i::GetIsolateForPtrCompr(HeapObject).
687   Object prop = raw_properties_or_hash(isolate);
688   if (prop.IsSmi()) {
689     return GetReadOnlyRoots(isolate).empty_ordered_property_dictionary();
690   }
691   return OrderedNameDictionary::cast(prop);
692 }
693 
694 // TODO(gsathya): Pass isolate directly to this function and access
695 // the heap from this.
DEF_GETTER(JSReceiver,property_array,PropertyArray)696 DEF_GETTER(JSReceiver, property_array, PropertyArray) {
697   DCHECK(HasFastProperties(isolate));
698   // Can't use ReadOnlyRoots(isolate) as this isolate could be produced by
699   // i::GetIsolateForPtrCompr(HeapObject).
700   Object prop = raw_properties_or_hash(isolate);
701   if (prop.IsSmi() || prop == GetReadOnlyRoots(isolate).empty_fixed_array()) {
702     return GetReadOnlyRoots(isolate).empty_property_array();
703   }
704   return PropertyArray::cast(prop);
705 }
706 
HasProperty(Handle<JSReceiver> object,Handle<Name> name)707 Maybe<bool> JSReceiver::HasProperty(Handle<JSReceiver> object,
708                                     Handle<Name> name) {
709   Isolate* isolate = object->GetIsolate();
710   LookupIterator::Key key(isolate, name);
711   LookupIterator it(isolate, object, key, object);
712   return HasProperty(&it);
713 }
714 
HasOwnProperty(Handle<JSReceiver> object,uint32_t index)715 Maybe<bool> JSReceiver::HasOwnProperty(Handle<JSReceiver> object,
716                                        uint32_t index) {
717   if (object->IsJSModuleNamespace()) return Just(false);
718 
719   if (object->IsJSObject()) {  // Shortcut.
720     LookupIterator it(object->GetIsolate(), object, index, object,
721                       LookupIterator::OWN);
722     return HasProperty(&it);
723   }
724 
725   Maybe<PropertyAttributes> attributes =
726       JSReceiver::GetOwnPropertyAttributes(object, index);
727   MAYBE_RETURN(attributes, Nothing<bool>());
728   return Just(attributes.FromJust() != ABSENT);
729 }
730 
GetPropertyAttributes(Handle<JSReceiver> object,Handle<Name> name)731 Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
732     Handle<JSReceiver> object, Handle<Name> name) {
733   Isolate* isolate = object->GetIsolate();
734   LookupIterator::Key key(isolate, name);
735   LookupIterator it(isolate, object, key, object);
736   return GetPropertyAttributes(&it);
737 }
738 
GetOwnPropertyAttributes(Handle<JSReceiver> object,Handle<Name> name)739 Maybe<PropertyAttributes> JSReceiver::GetOwnPropertyAttributes(
740     Handle<JSReceiver> object, Handle<Name> name) {
741   Isolate* isolate = object->GetIsolate();
742   LookupIterator::Key key(isolate, name);
743   LookupIterator it(isolate, object, key, object, LookupIterator::OWN);
744   return GetPropertyAttributes(&it);
745 }
746 
GetOwnPropertyAttributes(Handle<JSReceiver> object,uint32_t index)747 Maybe<PropertyAttributes> JSReceiver::GetOwnPropertyAttributes(
748     Handle<JSReceiver> object, uint32_t index) {
749   LookupIterator it(object->GetIsolate(), object, index, object,
750                     LookupIterator::OWN);
751   return GetPropertyAttributes(&it);
752 }
753 
HasElement(Handle<JSReceiver> object,uint32_t index)754 Maybe<bool> JSReceiver::HasElement(Handle<JSReceiver> object, uint32_t index) {
755   LookupIterator it(object->GetIsolate(), object, index, object);
756   return HasProperty(&it);
757 }
758 
GetElementAttributes(Handle<JSReceiver> object,uint32_t index)759 Maybe<PropertyAttributes> JSReceiver::GetElementAttributes(
760     Handle<JSReceiver> object, uint32_t index) {
761   Isolate* isolate = object->GetIsolate();
762   LookupIterator it(isolate, object, index, object);
763   return GetPropertyAttributes(&it);
764 }
765 
GetOwnElementAttributes(Handle<JSReceiver> object,uint32_t index)766 Maybe<PropertyAttributes> JSReceiver::GetOwnElementAttributes(
767     Handle<JSReceiver> object, uint32_t index) {
768   Isolate* isolate = object->GetIsolate();
769   LookupIterator it(isolate, object, index, object, LookupIterator::OWN);
770   return GetPropertyAttributes(&it);
771 }
772 
IsDetached()773 bool JSGlobalObject::IsDetached() {
774   return global_proxy().IsDetachedFrom(*this);
775 }
776 
IsDetachedFrom(JSGlobalObject global)777 bool JSGlobalProxy::IsDetachedFrom(JSGlobalObject global) const {
778   const PrototypeIterator iter(this->GetIsolate(), *this);
779   return iter.GetCurrent() != global;
780 }
781 
SizeWithEmbedderFields(int embedder_field_count)782 inline int JSGlobalProxy::SizeWithEmbedderFields(int embedder_field_count) {
783   DCHECK_GE(embedder_field_count, 0);
784   return kHeaderSize + embedder_field_count * kEmbedderDataSlotSize;
785 }
786 
ACCESSORS(JSIteratorResult,value,Object,kValueOffset)787 ACCESSORS(JSIteratorResult, value, Object, kValueOffset)
788 ACCESSORS(JSIteratorResult, done, Object, kDoneOffset)
789 
790 // If the fast-case backing storage takes up much more memory than a dictionary
791 // backing storage would, the object should have slow elements.
792 // static
793 static inline bool ShouldConvertToSlowElements(uint32_t used_elements,
794                                                uint32_t new_capacity) {
795   uint32_t size_threshold = NumberDictionary::kPreferFastElementsSizeFactor *
796                             NumberDictionary::ComputeCapacity(used_elements) *
797                             NumberDictionary::kEntrySize;
798   return size_threshold <= new_capacity;
799 }
800 
ShouldConvertToSlowElements(JSObject object,uint32_t capacity,uint32_t index,uint32_t * new_capacity)801 static inline bool ShouldConvertToSlowElements(JSObject object,
802                                                uint32_t capacity,
803                                                uint32_t index,
804                                                uint32_t* new_capacity) {
805   STATIC_ASSERT(JSObject::kMaxUncheckedOldFastElementsLength <=
806                 JSObject::kMaxUncheckedFastElementsLength);
807   if (index < capacity) {
808     *new_capacity = capacity;
809     return false;
810   }
811   if (index - capacity >= JSObject::kMaxGap) return true;
812   *new_capacity = JSObject::NewElementsCapacity(index + 1);
813   DCHECK_LT(index, *new_capacity);
814   // TODO(ulan): Check if it works with young large objects.
815   if (*new_capacity <= JSObject::kMaxUncheckedOldFastElementsLength ||
816       (*new_capacity <= JSObject::kMaxUncheckedFastElementsLength &&
817        ObjectInYoungGeneration(object))) {
818     return false;
819   }
820   return ShouldConvertToSlowElements(object.GetFastElementsUsage(),
821                                      *new_capacity);
822 }
823 
824 }  // namespace internal
825 }  // namespace v8
826 
827 #include "src/objects/object-macros-undef.h"
828 
829 #endif  // V8_OBJECTS_JS_OBJECTS_INL_H_
830