• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "src/objects/swiss-name-dictionary-inl.h"
25 
26 // Has to be the last include (doesn't have include guards):
27 #include "src/objects/object-macros.h"
28 
29 namespace v8 {
30 namespace internal {
31 
32 #include "torque-generated/src/objects/js-objects-tq-inl.inc"
33 
34 TQ_OBJECT_CONSTRUCTORS_IMPL(JSReceiver)
TQ_OBJECT_CONSTRUCTORS_IMPL(JSObject)35 TQ_OBJECT_CONSTRUCTORS_IMPL(JSObject)
36 TQ_OBJECT_CONSTRUCTORS_IMPL(JSObjectWithEmbedderSlots)
37 TQ_OBJECT_CONSTRUCTORS_IMPL(JSCustomElementsObject)
38 TQ_OBJECT_CONSTRUCTORS_IMPL(JSSpecialObject)
39 TQ_OBJECT_CONSTRUCTORS_IMPL(JSAsyncFromSyncIterator)
40 TQ_OBJECT_CONSTRUCTORS_IMPL(JSDate)
41 TQ_OBJECT_CONSTRUCTORS_IMPL(JSGlobalObject)
42 TQ_OBJECT_CONSTRUCTORS_IMPL(JSGlobalProxy)
43 JSIteratorResult::JSIteratorResult(Address ptr) : JSObject(ptr) {}
44 TQ_OBJECT_CONSTRUCTORS_IMPL(JSMessageObject)
TQ_OBJECT_CONSTRUCTORS_IMPL(JSPrimitiveWrapper)45 TQ_OBJECT_CONSTRUCTORS_IMPL(JSPrimitiveWrapper)
46 TQ_OBJECT_CONSTRUCTORS_IMPL(JSStringIterator)
47 
48 NEVER_READ_ONLY_SPACE_IMPL(JSReceiver)
49 
50 CAST_ACCESSOR(JSIteratorResult)
51 
52 DEF_GETTER(JSObject, elements, FixedArrayBase) {
53   return TaggedField<FixedArrayBase, kElementsOffset>::load(cage_base, *this);
54 }
55 
elements(RelaxedLoadTag tag)56 FixedArrayBase JSObject::elements(RelaxedLoadTag tag) const {
57   PtrComprCageBase cage_base = GetPtrComprCageBase(*this);
58   return elements(cage_base, tag);
59 }
60 
elements(PtrComprCageBase cage_base,RelaxedLoadTag)61 FixedArrayBase JSObject::elements(PtrComprCageBase cage_base,
62                                   RelaxedLoadTag) const {
63   return TaggedField<FixedArrayBase, kElementsOffset>::Relaxed_Load(cage_base,
64                                                                     *this);
65 }
66 
set_elements(FixedArrayBase value,WriteBarrierMode mode)67 void JSObject::set_elements(FixedArrayBase value, WriteBarrierMode mode) {
68   // Note the relaxed atomic store.
69   TaggedField<FixedArrayBase, kElementsOffset>::Relaxed_Store(*this, value);
70   CONDITIONAL_WRITE_BARRIER(*this, kElementsOffset, value, mode);
71 }
72 
GetProperty(Isolate * isolate,Handle<JSReceiver> receiver,Handle<Name> name)73 MaybeHandle<Object> JSReceiver::GetProperty(Isolate* isolate,
74                                             Handle<JSReceiver> receiver,
75                                             Handle<Name> name) {
76   LookupIterator it(isolate, receiver, name, receiver);
77   if (!it.IsFound()) return it.factory()->undefined_value();
78   return Object::GetProperty(&it);
79 }
80 
GetElement(Isolate * isolate,Handle<JSReceiver> receiver,uint32_t index)81 MaybeHandle<Object> JSReceiver::GetElement(Isolate* isolate,
82                                            Handle<JSReceiver> receiver,
83                                            uint32_t index) {
84   LookupIterator it(isolate, receiver, index, receiver);
85   if (!it.IsFound()) return it.factory()->undefined_value();
86   return Object::GetProperty(&it);
87 }
88 
GetDataProperty(Isolate * isolate,Handle<JSReceiver> object,Handle<Name> name)89 Handle<Object> JSReceiver::GetDataProperty(Isolate* isolate,
90                                            Handle<JSReceiver> object,
91                                            Handle<Name> name) {
92   LookupIterator it(isolate, object, name, object,
93                     LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
94   if (!it.IsFound()) return it.factory()->undefined_value();
95   return GetDataProperty(&it);
96 }
97 
GetPrototype(Isolate * isolate,Handle<JSReceiver> receiver)98 MaybeHandle<HeapObject> JSReceiver::GetPrototype(Isolate* isolate,
99                                                  Handle<JSReceiver> receiver) {
100   // We don't expect access checks to be needed on JSProxy objects.
101   DCHECK(!receiver->IsAccessCheckNeeded() || receiver->IsJSObject());
102   PrototypeIterator iter(isolate, receiver, kStartAtReceiver,
103                          PrototypeIterator::END_AT_NON_HIDDEN);
104   do {
105     if (!iter.AdvanceFollowingProxies()) return MaybeHandle<HeapObject>();
106   } while (!iter.IsAtEnd());
107   return PrototypeIterator::GetCurrent(iter);
108 }
109 
GetProperty(Isolate * isolate,Handle<JSReceiver> receiver,const char * name)110 MaybeHandle<Object> JSReceiver::GetProperty(Isolate* isolate,
111                                             Handle<JSReceiver> receiver,
112                                             const char* name) {
113   Handle<String> str = isolate->factory()->InternalizeUtf8String(name);
114   return GetProperty(isolate, receiver, str);
115 }
116 
117 // static
OwnPropertyKeys(Handle<JSReceiver> object)118 V8_WARN_UNUSED_RESULT MaybeHandle<FixedArray> JSReceiver::OwnPropertyKeys(
119     Handle<JSReceiver> object) {
120   return KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly,
121                                  ALL_PROPERTIES,
122                                  GetKeysConversion::kConvertToString);
123 }
124 
PrototypeHasNoElements(Isolate * isolate,JSObject object)125 bool JSObject::PrototypeHasNoElements(Isolate* isolate, JSObject object) {
126   DisallowGarbageCollection no_gc;
127   HeapObject prototype = HeapObject::cast(object.map().prototype());
128   ReadOnlyRoots roots(isolate);
129   HeapObject null = roots.null_value();
130   FixedArrayBase empty_fixed_array = roots.empty_fixed_array();
131   FixedArrayBase empty_slow_element_dictionary =
132       roots.empty_slow_element_dictionary();
133   while (prototype != null) {
134     Map map = prototype.map();
135     if (map.IsCustomElementsReceiverMap()) return false;
136     FixedArrayBase elements = JSObject::cast(prototype).elements();
137     if (elements != empty_fixed_array &&
138         elements != empty_slow_element_dictionary) {
139       return false;
140     }
141     prototype = HeapObject::cast(map.prototype());
142   }
143   return true;
144 }
145 
ACCESSORS(JSReceiver,raw_properties_or_hash,Object,kPropertiesOrHashOffset)146 ACCESSORS(JSReceiver, raw_properties_or_hash, Object, kPropertiesOrHashOffset)
147 RELAXED_ACCESSORS(JSReceiver, raw_properties_or_hash, Object,
148                   kPropertiesOrHashOffset)
149 
150 void JSObject::EnsureCanContainHeapObjectElements(Handle<JSObject> object) {
151   JSObject::ValidateElements(*object);
152   ElementsKind elements_kind = object->map().elements_kind();
153   if (!IsObjectElementsKind(elements_kind)) {
154     if (IsHoleyElementsKind(elements_kind)) {
155       TransitionElementsKind(object, HOLEY_ELEMENTS);
156     } else {
157       TransitionElementsKind(object, PACKED_ELEMENTS);
158     }
159   }
160 }
161 
162 template <typename TSlot>
EnsureCanContainElements(Handle<JSObject> object,TSlot objects,uint32_t count,EnsureElementsMode mode)163 void JSObject::EnsureCanContainElements(Handle<JSObject> object, TSlot objects,
164                                         uint32_t count,
165                                         EnsureElementsMode mode) {
166   static_assert(std::is_same<TSlot, FullObjectSlot>::value ||
167                     std::is_same<TSlot, ObjectSlot>::value,
168                 "Only ObjectSlot and FullObjectSlot are expected here");
169   ElementsKind current_kind = object->GetElementsKind();
170   ElementsKind target_kind = current_kind;
171   {
172     DisallowGarbageCollection no_gc;
173     DCHECK(mode != ALLOW_COPIED_DOUBLE_ELEMENTS);
174     bool is_holey = IsHoleyElementsKind(current_kind);
175     if (current_kind == HOLEY_ELEMENTS) return;
176     Object the_hole = object->GetReadOnlyRoots().the_hole_value();
177     for (uint32_t i = 0; i < count; ++i, ++objects) {
178       Object current = *objects;
179       if (current == the_hole) {
180         is_holey = true;
181         target_kind = GetHoleyElementsKind(target_kind);
182       } else if (!current.IsSmi()) {
183         if (mode == ALLOW_CONVERTED_DOUBLE_ELEMENTS && current.IsNumber()) {
184           if (IsSmiElementsKind(target_kind)) {
185             if (is_holey) {
186               target_kind = HOLEY_DOUBLE_ELEMENTS;
187             } else {
188               target_kind = PACKED_DOUBLE_ELEMENTS;
189             }
190           }
191         } else if (is_holey) {
192           target_kind = HOLEY_ELEMENTS;
193           break;
194         } else {
195           target_kind = PACKED_ELEMENTS;
196         }
197       }
198     }
199   }
200   if (target_kind != current_kind) {
201     TransitionElementsKind(object, target_kind);
202   }
203 }
204 
EnsureCanContainElements(Handle<JSObject> object,Handle<FixedArrayBase> elements,uint32_t length,EnsureElementsMode mode)205 void JSObject::EnsureCanContainElements(Handle<JSObject> object,
206                                         Handle<FixedArrayBase> elements,
207                                         uint32_t length,
208                                         EnsureElementsMode mode) {
209   ReadOnlyRoots roots = object->GetReadOnlyRoots();
210   if (elements->map() != roots.fixed_double_array_map()) {
211     DCHECK(elements->map() == roots.fixed_array_map() ||
212            elements->map() == roots.fixed_cow_array_map());
213     if (mode == ALLOW_COPIED_DOUBLE_ELEMENTS) {
214       mode = DONT_ALLOW_DOUBLE_ELEMENTS;
215     }
216     ObjectSlot objects =
217         Handle<FixedArray>::cast(elements)->GetFirstElementAddress();
218     EnsureCanContainElements(object, objects, length, mode);
219     return;
220   }
221 
222   DCHECK(mode == ALLOW_COPIED_DOUBLE_ELEMENTS);
223   if (object->GetElementsKind() == HOLEY_SMI_ELEMENTS) {
224     TransitionElementsKind(object, HOLEY_DOUBLE_ELEMENTS);
225   } else if (object->GetElementsKind() == PACKED_SMI_ELEMENTS) {
226     Handle<FixedDoubleArray> double_array =
227         Handle<FixedDoubleArray>::cast(elements);
228     for (uint32_t i = 0; i < length; ++i) {
229       if (double_array->is_the_hole(i)) {
230         TransitionElementsKind(object, HOLEY_DOUBLE_ELEMENTS);
231         return;
232       }
233     }
234     TransitionElementsKind(object, PACKED_DOUBLE_ELEMENTS);
235   }
236 }
237 
SetMapAndElements(Handle<JSObject> object,Handle<Map> new_map,Handle<FixedArrayBase> value)238 void JSObject::SetMapAndElements(Handle<JSObject> object, Handle<Map> new_map,
239                                  Handle<FixedArrayBase> value) {
240   Isolate* isolate = object->GetIsolate();
241   JSObject::MigrateToMap(isolate, object, new_map);
242   DCHECK((object->map().has_fast_smi_or_object_elements() ||
243           (*value == ReadOnlyRoots(isolate).empty_fixed_array()) ||
244           object->map().has_fast_string_wrapper_elements()) ==
245          (value->map() == ReadOnlyRoots(isolate).fixed_array_map() ||
246           value->map() == ReadOnlyRoots(isolate).fixed_cow_array_map()));
247   DCHECK((*value == ReadOnlyRoots(isolate).empty_fixed_array()) ||
248          (object->map().has_fast_double_elements() ==
249           value->IsFixedDoubleArray()));
250   object->set_elements(*value);
251 }
252 
initialize_elements()253 void JSObject::initialize_elements() {
254   FixedArrayBase elements = map().GetInitialElements();
255   set_elements(elements, SKIP_WRITE_BARRIER);
256 }
257 
DEF_GETTER(JSObject,GetIndexedInterceptor,InterceptorInfo)258 DEF_GETTER(JSObject, GetIndexedInterceptor, InterceptorInfo) {
259   return map(cage_base).GetIndexedInterceptor(cage_base);
260 }
261 
DEF_GETTER(JSObject,GetNamedInterceptor,InterceptorInfo)262 DEF_GETTER(JSObject, GetNamedInterceptor, InterceptorInfo) {
263   return map(cage_base).GetNamedInterceptor(cage_base);
264 }
265 
266 // static
GetHeaderSize(Map map)267 int JSObject::GetHeaderSize(Map map) {
268   // Check for the most common kind of JavaScript object before
269   // falling into the generic switch. This speeds up the internal
270   // field operations considerably on average.
271   InstanceType instance_type = map.instance_type();
272   return instance_type == JS_OBJECT_TYPE
273              ? JSObject::kHeaderSize
274              : GetHeaderSize(instance_type, map.has_prototype_slot());
275 }
276 
277 // static
GetEmbedderFieldsStartOffset(Map map)278 int JSObject::GetEmbedderFieldsStartOffset(Map map) {
279   // Embedder fields are located after the object header.
280   return GetHeaderSize(map);
281 }
282 
GetEmbedderFieldsStartOffset()283 int JSObject::GetEmbedderFieldsStartOffset() {
284   return GetEmbedderFieldsStartOffset(map());
285 }
286 
287 // static
MayHaveEmbedderFields(Map map)288 bool JSObject::MayHaveEmbedderFields(Map map) {
289   InstanceType instance_type = map.instance_type();
290   // TODO(v8) It'd be nice if all objects with embedder data slots inherited
291   // from JSObjectWithEmbedderSlots, but this is currently not possible due to
292   // instance_type constraints.
293   return InstanceTypeChecker::IsJSObjectWithEmbedderSlots(instance_type) ||
294          InstanceTypeChecker::IsJSSpecialObject(instance_type);
295 }
296 
MayHaveEmbedderFields()297 bool JSObject::MayHaveEmbedderFields() const {
298   return MayHaveEmbedderFields(map());
299 }
300 
301 // static
GetEmbedderFieldCount(Map map)302 int JSObject::GetEmbedderFieldCount(Map map) {
303   int instance_size = map.instance_size();
304   if (instance_size == kVariableSizeSentinel) return 0;
305   // Embedder fields are located after the object header, whereas in-object
306   // properties are located at the end of the object. We don't have to round up
307   // the header size here because division by kEmbedderDataSlotSizeInTaggedSlots
308   // will swallow potential padding in case of (kTaggedSize !=
309   // kSystemPointerSize) anyway.
310   return (((instance_size - GetEmbedderFieldsStartOffset(map)) >>
311            kTaggedSizeLog2) -
312           map.GetInObjectProperties()) /
313          kEmbedderDataSlotSizeInTaggedSlots;
314 }
315 
GetEmbedderFieldCount()316 int JSObject::GetEmbedderFieldCount() const {
317   return GetEmbedderFieldCount(map());
318 }
319 
GetEmbedderFieldOffset(int index)320 int JSObject::GetEmbedderFieldOffset(int index) {
321   DCHECK_LT(static_cast<unsigned>(index),
322             static_cast<unsigned>(GetEmbedderFieldCount()));
323   return GetEmbedderFieldsStartOffset() + (kEmbedderDataSlotSize * index);
324 }
325 
GetEmbedderField(int index)326 Object JSObject::GetEmbedderField(int index) {
327   return EmbedderDataSlot(*this, index).load_tagged();
328 }
329 
SetEmbedderField(int index,Object value)330 void JSObject::SetEmbedderField(int index, Object value) {
331   EmbedderDataSlot::store_tagged(*this, index, value);
332 }
333 
SetEmbedderField(int index,Smi value)334 void JSObject::SetEmbedderField(int index, Smi value) {
335   EmbedderDataSlot(*this, index).store_smi(value);
336 }
337 
IsDroppableApiObject()338 bool JSObject::IsDroppableApiObject() const {
339   auto instance_type = map().instance_type();
340   return InstanceTypeChecker::IsJSApiObject(instance_type) ||
341          instance_type == JS_SPECIAL_API_OBJECT_TYPE;
342 }
343 
344 // Access fast-case object properties at index. The use of these routines
345 // is needed to correctly distinguish between properties stored in-object and
346 // properties stored in the properties array.
RawFastPropertyAt(FieldIndex index)347 Object JSObject::RawFastPropertyAt(FieldIndex index) const {
348   PtrComprCageBase cage_base = GetPtrComprCageBase(*this);
349   return RawFastPropertyAt(cage_base, index);
350 }
351 
RawFastPropertyAt(PtrComprCageBase cage_base,FieldIndex index)352 Object JSObject::RawFastPropertyAt(PtrComprCageBase cage_base,
353                                    FieldIndex index) const {
354   if (index.is_inobject()) {
355     return TaggedField<Object>::Relaxed_Load(cage_base, *this, index.offset());
356   } else {
357     return property_array(cage_base).get(cage_base,
358                                          index.outobject_array_index());
359   }
360 }
361 
362 // The SeqCst versions of RawFastPropertyAt are used for atomically accessing
363 // shared struct fields.
RawFastPropertyAt(FieldIndex index,SeqCstAccessTag tag)364 Object JSObject::RawFastPropertyAt(FieldIndex index,
365                                    SeqCstAccessTag tag) const {
366   PtrComprCageBase cage_base = GetPtrComprCageBase(*this);
367   return RawFastPropertyAt(cage_base, index, tag);
368 }
369 
RawFastPropertyAt(PtrComprCageBase cage_base,FieldIndex index,SeqCstAccessTag tag)370 Object JSObject::RawFastPropertyAt(PtrComprCageBase cage_base, FieldIndex index,
371                                    SeqCstAccessTag tag) const {
372   if (index.is_inobject()) {
373     return TaggedField<Object>::SeqCst_Load(cage_base, *this, index.offset());
374   } else {
375     return property_array(cage_base).get(cage_base,
376                                          index.outobject_array_index(), tag);
377   }
378 }
379 
RawInobjectPropertyAt(PtrComprCageBase cage_base,Map original_map,FieldIndex index)380 base::Optional<Object> JSObject::RawInobjectPropertyAt(
381     PtrComprCageBase cage_base, Map original_map, FieldIndex index) const {
382   CHECK(index.is_inobject());
383 
384   // This method implements a "snapshot" protocol to protect against reading out
385   // of bounds of an object. It's used to access a fast in-object property from
386   // a background thread with no locking. That caller does have the guarantee
387   // that a garbage collection cannot happen during its query. However, it must
388   // contend with the main thread altering the object in heavy ways through
389   // object migration. Specifically, the object can get smaller. Initially, this
390   // may seem benign, because object migration fills the freed-up space with
391   // FillerMap words which, even though they offer wrong values, are at
392   // least tagged values.
393 
394   // However, there is an additional danger. Sweeper threads may discover the
395   // filler words and offer that space to the main thread for allocation. Should
396   // a HeapNumber be allocated into that space while we're reading a property at
397   // that location (from our out-of-date information), we risk interpreting a
398   // double value as a pointer. This must be prevented.
399   //
400   // We do this by:
401   //
402   // a) Reading the map first
403   // b) Reading the property with acquire semantics (but do not inspect it!)
404   // c) Re-read the map with acquire semantics.
405   //
406   // Only if the maps match can the property be inspected. It may have a "wrong"
407   // value, but it will be within the bounds of the objects instance size as
408   // given by the map and it will be a valid Smi or object pointer.
409   Object maybe_tagged_object =
410       TaggedField<Object>::Acquire_Load(cage_base, *this, index.offset());
411   if (original_map != map(cage_base, kAcquireLoad)) return {};
412   return maybe_tagged_object;
413 }
414 
RawFastInobjectPropertyAtPut(FieldIndex index,Object value,WriteBarrierMode mode)415 void JSObject::RawFastInobjectPropertyAtPut(FieldIndex index, Object value,
416                                             WriteBarrierMode mode) {
417   DCHECK(index.is_inobject());
418   int offset = index.offset();
419   RELAXED_WRITE_FIELD(*this, offset, value);
420   CONDITIONAL_WRITE_BARRIER(*this, offset, value, mode);
421 }
422 
RawFastInobjectPropertyAtPut(FieldIndex index,Object value,SeqCstAccessTag tag)423 void JSObject::RawFastInobjectPropertyAtPut(FieldIndex index, Object value,
424                                             SeqCstAccessTag tag) {
425   DCHECK(index.is_inobject());
426   DCHECK(value.IsShared());
427   SEQ_CST_WRITE_FIELD(*this, index.offset(), value);
428   // JSSharedStructs are allocated in the shared old space, which is currently
429   // collected by stopping the world, so the incremental write barrier is not
430   // needed. They can only store Smis and other HeapObjects in the shared old
431   // space, so the generational write barrier is also not needed.
432 }
433 
FastPropertyAtPut(FieldIndex index,Object value,WriteBarrierMode mode)434 void JSObject::FastPropertyAtPut(FieldIndex index, Object value,
435                                  WriteBarrierMode mode) {
436   if (index.is_inobject()) {
437     RawFastInobjectPropertyAtPut(index, value, mode);
438   } else {
439     DCHECK_EQ(UPDATE_WRITE_BARRIER, mode);
440     property_array().set(index.outobject_array_index(), value);
441   }
442 }
443 
FastPropertyAtPut(FieldIndex index,Object value,SeqCstAccessTag tag)444 void JSObject::FastPropertyAtPut(FieldIndex index, Object value,
445                                  SeqCstAccessTag tag) {
446   if (index.is_inobject()) {
447     RawFastInobjectPropertyAtPut(index, value, tag);
448   } else {
449     property_array().set(index.outobject_array_index(), value, tag);
450   }
451 }
452 
WriteToField(InternalIndex descriptor,PropertyDetails details,Object value)453 void JSObject::WriteToField(InternalIndex descriptor, PropertyDetails details,
454                             Object value) {
455   DCHECK_EQ(PropertyLocation::kField, details.location());
456   DCHECK_EQ(PropertyKind::kData, details.kind());
457   DisallowGarbageCollection no_gc;
458   FieldIndex index = FieldIndex::ForDescriptor(map(), descriptor);
459   if (details.representation().IsDouble()) {
460     // Manipulating the signaling NaN used for the hole and uninitialized
461     // double field sentinel in C++, e.g. with bit_cast or value()/set_value(),
462     // will change its value on ia32 (the x87 stack is used to return values
463     // and stores to the stack silently clear the signalling bit).
464     uint64_t bits;
465     if (value.IsSmi()) {
466       bits = bit_cast<uint64_t>(static_cast<double>(Smi::ToInt(value)));
467     } else if (value.IsUninitialized()) {
468       bits = kHoleNanInt64;
469     } else {
470       DCHECK(value.IsHeapNumber());
471       bits = HeapNumber::cast(value).value_as_bits(kRelaxedLoad);
472     }
473     auto box = HeapNumber::cast(RawFastPropertyAt(index));
474     box.set_value_as_bits(bits, kRelaxedStore);
475   } else {
476     FastPropertyAtPut(index, value);
477   }
478 }
479 
RawFastPropertyAtSwap(FieldIndex index,Object value,SeqCstAccessTag tag)480 Object JSObject::RawFastPropertyAtSwap(FieldIndex index, Object value,
481                                        SeqCstAccessTag tag) {
482   PtrComprCageBase cage_base = GetPtrComprCageBase(*this);
483   return RawFastPropertyAtSwap(cage_base, index, value, tag);
484 }
485 
RawFastPropertyAtSwap(PtrComprCageBase cage_base,FieldIndex index,Object value,SeqCstAccessTag tag)486 Object JSObject::RawFastPropertyAtSwap(PtrComprCageBase cage_base,
487                                        FieldIndex index, Object value,
488                                        SeqCstAccessTag tag) {
489   if (index.is_inobject()) {
490     return TaggedField<Object>::SeqCst_Swap(cage_base, *this, index.offset(),
491                                             value);
492   }
493   return property_array().Swap(cage_base, index.outobject_array_index(), value,
494                                tag);
495 }
496 
GetInObjectPropertyOffset(int index)497 int JSObject::GetInObjectPropertyOffset(int index) {
498   return map().GetInObjectPropertyOffset(index);
499 }
500 
InObjectPropertyAt(int index)501 Object JSObject::InObjectPropertyAt(int index) {
502   int offset = GetInObjectPropertyOffset(index);
503   return TaggedField<Object>::load(*this, offset);
504 }
505 
InObjectPropertyAtPut(int index,Object value,WriteBarrierMode mode)506 Object JSObject::InObjectPropertyAtPut(int index, Object value,
507                                        WriteBarrierMode mode) {
508   // Adjust for the number of properties stored in the object.
509   int offset = GetInObjectPropertyOffset(index);
510   WRITE_FIELD(*this, offset, value);
511   CONDITIONAL_WRITE_BARRIER(*this, offset, value, mode);
512   return value;
513 }
514 
InitializeBody(Map map,int start_offset,bool is_slack_tracking_in_progress,MapWord filler_map,Object undefined_filler)515 void JSObject::InitializeBody(Map map, int start_offset,
516                               bool is_slack_tracking_in_progress,
517                               MapWord filler_map, Object undefined_filler) {
518   int size = map.instance_size();
519   int offset = start_offset;
520 
521   // embedder data slots need to be initialized separately
522   if (MayHaveEmbedderFields(map)) {
523     int embedder_field_start = GetEmbedderFieldsStartOffset(map);
524     int embedder_field_count = GetEmbedderFieldCount(map);
525 
526     // fill start with references to the undefined value object
527     DCHECK_LE(offset, embedder_field_start);
528     while (offset < embedder_field_start) {
529       WRITE_FIELD(*this, offset, undefined_filler);
530       offset += kTaggedSize;
531     }
532 
533     // initialize embedder data slots
534     DCHECK_EQ(offset, embedder_field_start);
535     for (int i = 0; i < embedder_field_count; i++) {
536       // TODO(v8): consider initializing embedded data slots with Smi::zero().
537       EmbedderDataSlot(*this, i).Initialize(undefined_filler);
538       offset += kEmbedderDataSlotSize;
539     }
540   } else {
541     DCHECK_EQ(0, GetEmbedderFieldCount(map));
542   }
543 
544   DCHECK_LE(offset, size);
545   if (is_slack_tracking_in_progress) {
546     int end_of_pre_allocated_offset =
547         size - (map.UnusedPropertyFields() * kTaggedSize);
548     DCHECK_LE(kHeaderSize, end_of_pre_allocated_offset);
549     DCHECK_LE(offset, end_of_pre_allocated_offset);
550     // fill pre allocated slots with references to the undefined value object
551     while (offset < end_of_pre_allocated_offset) {
552       WRITE_FIELD(*this, offset, undefined_filler);
553       offset += kTaggedSize;
554     }
555     // fill the remainder with one word filler objects (ie just a map word)
556     while (offset < size) {
557       Object fm = Object(filler_map.ptr());
558       WRITE_FIELD(*this, offset, fm);
559       offset += kTaggedSize;
560     }
561   } else {
562     while (offset < size) {
563       // fill everything with references to the undefined value object
564       WRITE_FIELD(*this, offset, undefined_filler);
565       offset += kTaggedSize;
566     }
567   }
568 }
569 
570 TQ_OBJECT_CONSTRUCTORS_IMPL(JSExternalObject)
571 
DEF_GETTER(JSExternalObject,value,void *)572 DEF_GETTER(JSExternalObject, value, void*) {
573   Isolate* isolate = GetIsolateForSandbox(*this);
574   return reinterpret_cast<void*>(
575       ReadExternalPointerField(kValueOffset, isolate, kExternalObjectValueTag));
576 }
577 
AllocateExternalPointerEntries(Isolate * isolate)578 void JSExternalObject::AllocateExternalPointerEntries(Isolate* isolate) {
579   InitExternalPointerField(kValueOffset, isolate, kExternalObjectValueTag);
580 }
581 
set_value(Isolate * isolate,void * value)582 void JSExternalObject::set_value(Isolate* isolate, void* value) {
583   WriteExternalPointerField(kValueOffset, isolate,
584                             reinterpret_cast<Address>(value),
585                             kExternalObjectValueTag);
586 }
587 
DEF_GETTER(JSGlobalObject,native_context_unchecked,Object)588 DEF_GETTER(JSGlobalObject, native_context_unchecked, Object) {
589   return TaggedField<Object, kNativeContextOffset>::Relaxed_Load(cage_base,
590                                                                  *this);
591 }
592 
DidEnsureSourcePositionsAvailable()593 bool JSMessageObject::DidEnsureSourcePositionsAvailable() const {
594   return shared_info().IsUndefined();
595 }
596 
GetStartPosition()597 int JSMessageObject::GetStartPosition() const {
598   DCHECK(DidEnsureSourcePositionsAvailable());
599   return start_position();
600 }
601 
GetEndPosition()602 int JSMessageObject::GetEndPosition() const {
603   DCHECK(DidEnsureSourcePositionsAvailable());
604   return end_position();
605 }
606 
type()607 MessageTemplate JSMessageObject::type() const {
608   return MessageTemplateFromInt(raw_type());
609 }
610 
set_type(MessageTemplate value)611 void JSMessageObject::set_type(MessageTemplate value) {
612   set_raw_type(static_cast<int>(value));
613 }
614 
ACCESSORS(JSMessageObject,shared_info,HeapObject,kSharedInfoOffset)615 ACCESSORS(JSMessageObject, shared_info, HeapObject, kSharedInfoOffset)
616 ACCESSORS(JSMessageObject, bytecode_offset, Smi, kBytecodeOffsetOffset)
617 SMI_ACCESSORS(JSMessageObject, start_position, kStartPositionOffset)
618 SMI_ACCESSORS(JSMessageObject, end_position, kEndPositionOffset)
619 SMI_ACCESSORS(JSMessageObject, error_level, kErrorLevelOffset)
620 SMI_ACCESSORS(JSMessageObject, raw_type, kMessageTypeOffset)
621 
622 DEF_GETTER(JSObject, GetElementsKind, ElementsKind) {
623   ElementsKind kind = map(cage_base).elements_kind();
624 #if VERIFY_HEAP && DEBUG
625   FixedArrayBase fixed_array = FixedArrayBase::unchecked_cast(
626       TaggedField<HeapObject, kElementsOffset>::load(cage_base, *this));
627 
628   // If a GC was caused while constructing this object, the elements
629   // pointer may point to a one pointer filler map.
630   if (ElementsAreSafeToExamine(cage_base)) {
631     Map map = fixed_array.map(cage_base);
632     if (IsSmiOrObjectElementsKind(kind)) {
633       DCHECK(map == GetReadOnlyRoots(cage_base).fixed_array_map() ||
634              map == GetReadOnlyRoots(cage_base).fixed_cow_array_map());
635     } else if (IsDoubleElementsKind(kind)) {
636       DCHECK(fixed_array.IsFixedDoubleArray(cage_base) ||
637              fixed_array == GetReadOnlyRoots(cage_base).empty_fixed_array());
638     } else if (kind == DICTIONARY_ELEMENTS) {
639       DCHECK(fixed_array.IsFixedArray(cage_base));
640       DCHECK(fixed_array.IsNumberDictionary(cage_base));
641     } else {
642       DCHECK(kind > DICTIONARY_ELEMENTS ||
643              IsAnyNonextensibleElementsKind(kind));
644     }
645     DCHECK(!IsSloppyArgumentsElementsKind(kind) ||
646            elements(cage_base).IsSloppyArgumentsElements());
647   }
648 #endif
649   return kind;
650 }
651 
DEF_GETTER(JSObject,GetElementsAccessor,ElementsAccessor *)652 DEF_GETTER(JSObject, GetElementsAccessor, ElementsAccessor*) {
653   return ElementsAccessor::ForKind(GetElementsKind(cage_base));
654 }
655 
DEF_GETTER(JSObject,HasObjectElements,bool)656 DEF_GETTER(JSObject, HasObjectElements, bool) {
657   return IsObjectElementsKind(GetElementsKind(cage_base));
658 }
659 
DEF_GETTER(JSObject,HasSmiElements,bool)660 DEF_GETTER(JSObject, HasSmiElements, bool) {
661   return IsSmiElementsKind(GetElementsKind(cage_base));
662 }
663 
DEF_GETTER(JSObject,HasSmiOrObjectElements,bool)664 DEF_GETTER(JSObject, HasSmiOrObjectElements, bool) {
665   return IsSmiOrObjectElementsKind(GetElementsKind(cage_base));
666 }
667 
DEF_GETTER(JSObject,HasDoubleElements,bool)668 DEF_GETTER(JSObject, HasDoubleElements, bool) {
669   return IsDoubleElementsKind(GetElementsKind(cage_base));
670 }
671 
DEF_GETTER(JSObject,HasHoleyElements,bool)672 DEF_GETTER(JSObject, HasHoleyElements, bool) {
673   return IsHoleyElementsKind(GetElementsKind(cage_base));
674 }
675 
DEF_GETTER(JSObject,HasFastElements,bool)676 DEF_GETTER(JSObject, HasFastElements, bool) {
677   return IsFastElementsKind(GetElementsKind(cage_base));
678 }
679 
DEF_GETTER(JSObject,HasFastPackedElements,bool)680 DEF_GETTER(JSObject, HasFastPackedElements, bool) {
681   return IsFastPackedElementsKind(GetElementsKind(cage_base));
682 }
683 
DEF_GETTER(JSObject,HasDictionaryElements,bool)684 DEF_GETTER(JSObject, HasDictionaryElements, bool) {
685   return IsDictionaryElementsKind(GetElementsKind(cage_base));
686 }
687 
DEF_GETTER(JSObject,HasPackedElements,bool)688 DEF_GETTER(JSObject, HasPackedElements, bool) {
689   return GetElementsKind(cage_base) == PACKED_ELEMENTS;
690 }
691 
DEF_GETTER(JSObject,HasAnyNonextensibleElements,bool)692 DEF_GETTER(JSObject, HasAnyNonextensibleElements, bool) {
693   return IsAnyNonextensibleElementsKind(GetElementsKind(cage_base));
694 }
695 
DEF_GETTER(JSObject,HasSealedElements,bool)696 DEF_GETTER(JSObject, HasSealedElements, bool) {
697   return IsSealedElementsKind(GetElementsKind(cage_base));
698 }
699 
DEF_GETTER(JSObject,HasNonextensibleElements,bool)700 DEF_GETTER(JSObject, HasNonextensibleElements, bool) {
701   return IsNonextensibleElementsKind(GetElementsKind(cage_base));
702 }
703 
DEF_GETTER(JSObject,HasFastArgumentsElements,bool)704 DEF_GETTER(JSObject, HasFastArgumentsElements, bool) {
705   return IsFastArgumentsElementsKind(GetElementsKind(cage_base));
706 }
707 
DEF_GETTER(JSObject,HasSlowArgumentsElements,bool)708 DEF_GETTER(JSObject, HasSlowArgumentsElements, bool) {
709   return IsSlowArgumentsElementsKind(GetElementsKind(cage_base));
710 }
711 
DEF_GETTER(JSObject,HasSloppyArgumentsElements,bool)712 DEF_GETTER(JSObject, HasSloppyArgumentsElements, bool) {
713   return IsSloppyArgumentsElementsKind(GetElementsKind(cage_base));
714 }
715 
DEF_GETTER(JSObject,HasStringWrapperElements,bool)716 DEF_GETTER(JSObject, HasStringWrapperElements, bool) {
717   return IsStringWrapperElementsKind(GetElementsKind(cage_base));
718 }
719 
DEF_GETTER(JSObject,HasFastStringWrapperElements,bool)720 DEF_GETTER(JSObject, HasFastStringWrapperElements, bool) {
721   return GetElementsKind(cage_base) == FAST_STRING_WRAPPER_ELEMENTS;
722 }
723 
DEF_GETTER(JSObject,HasSlowStringWrapperElements,bool)724 DEF_GETTER(JSObject, HasSlowStringWrapperElements, bool) {
725   return GetElementsKind(cage_base) == SLOW_STRING_WRAPPER_ELEMENTS;
726 }
727 
DEF_GETTER(JSObject,HasTypedArrayOrRabGsabTypedArrayElements,bool)728 DEF_GETTER(JSObject, HasTypedArrayOrRabGsabTypedArrayElements, bool) {
729   DCHECK(!elements(cage_base).is_null());
730   return map(cage_base).has_typed_array_or_rab_gsab_typed_array_elements();
731 }
732 
733 #define FIXED_TYPED_ELEMENTS_CHECK(Type, type, TYPE, ctype)   \
734   DEF_GETTER(JSObject, HasFixed##Type##Elements, bool) {      \
735     return map(cage_base).elements_kind() == TYPE##_ELEMENTS; \
736   }
737 
738 TYPED_ARRAYS(FIXED_TYPED_ELEMENTS_CHECK)
739 
740 #undef FIXED_TYPED_ELEMENTS_CHECK
741 
DEF_GETTER(JSObject,HasNamedInterceptor,bool)742 DEF_GETTER(JSObject, HasNamedInterceptor, bool) {
743   return map(cage_base).has_named_interceptor();
744 }
745 
DEF_GETTER(JSObject,HasIndexedInterceptor,bool)746 DEF_GETTER(JSObject, HasIndexedInterceptor, bool) {
747   return map(cage_base).has_indexed_interceptor();
748 }
749 
750 RELEASE_ACQUIRE_ACCESSORS_CHECKED2(JSGlobalObject, global_dictionary,
751                                    GlobalDictionary, kPropertiesOrHashOffset,
752                                    !HasFastProperties(cage_base), true)
753 
DEF_GETTER(JSObject,element_dictionary,NumberDictionary)754 DEF_GETTER(JSObject, element_dictionary, NumberDictionary) {
755   DCHECK(HasDictionaryElements(cage_base) ||
756          HasSlowStringWrapperElements(cage_base));
757   return NumberDictionary::cast(elements(cage_base));
758 }
759 
initialize_properties(Isolate * isolate)760 void JSReceiver::initialize_properties(Isolate* isolate) {
761   ReadOnlyRoots roots(isolate);
762   DCHECK(!ObjectInYoungGeneration(roots.empty_fixed_array()));
763   DCHECK(!ObjectInYoungGeneration(roots.empty_property_dictionary()));
764   DCHECK(!ObjectInYoungGeneration(roots.empty_ordered_property_dictionary()));
765   if (map(isolate).is_dictionary_map()) {
766     if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
767       WRITE_FIELD(*this, kPropertiesOrHashOffset,
768                   roots.empty_swiss_property_dictionary());
769     } else {
770       WRITE_FIELD(*this, kPropertiesOrHashOffset,
771                   roots.empty_property_dictionary());
772     }
773   } else {
774     WRITE_FIELD(*this, kPropertiesOrHashOffset, roots.empty_fixed_array());
775   }
776 }
777 
DEF_GETTER(JSReceiver,HasFastProperties,bool)778 DEF_GETTER(JSReceiver, HasFastProperties, bool) {
779   DCHECK(raw_properties_or_hash(cage_base).IsSmi() ||
780          ((raw_properties_or_hash(cage_base).IsGlobalDictionary(cage_base) ||
781            raw_properties_or_hash(cage_base).IsNameDictionary(cage_base) ||
782            raw_properties_or_hash(cage_base).IsSwissNameDictionary(
783                cage_base)) == map(cage_base).is_dictionary_map()));
784   return !map(cage_base).is_dictionary_map();
785 }
786 
DEF_GETTER(JSReceiver,property_dictionary,NameDictionary)787 DEF_GETTER(JSReceiver, property_dictionary, NameDictionary) {
788   DCHECK(!IsJSGlobalObject(cage_base));
789   DCHECK(!HasFastProperties(cage_base));
790   DCHECK(!V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL);
791 
792   Object prop = raw_properties_or_hash(cage_base);
793   if (prop.IsSmi()) {
794     return GetReadOnlyRoots(cage_base).empty_property_dictionary();
795   }
796   return NameDictionary::cast(prop);
797 }
798 
DEF_GETTER(JSReceiver,property_dictionary_swiss,SwissNameDictionary)799 DEF_GETTER(JSReceiver, property_dictionary_swiss, SwissNameDictionary) {
800   DCHECK(!IsJSGlobalObject(cage_base));
801   DCHECK(!HasFastProperties(cage_base));
802   DCHECK(V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL);
803 
804   Object prop = raw_properties_or_hash(cage_base);
805   if (prop.IsSmi()) {
806     return GetReadOnlyRoots(cage_base).empty_swiss_property_dictionary();
807   }
808   return SwissNameDictionary::cast(prop);
809 }
810 
811 // TODO(gsathya): Pass isolate directly to this function and access
812 // the heap from this.
DEF_GETTER(JSReceiver,property_array,PropertyArray)813 DEF_GETTER(JSReceiver, property_array, PropertyArray) {
814   DCHECK(HasFastProperties(cage_base));
815   Object prop = raw_properties_or_hash(cage_base);
816   if (prop.IsSmi() || prop == GetReadOnlyRoots(cage_base).empty_fixed_array()) {
817     return GetReadOnlyRoots(cage_base).empty_property_array();
818   }
819   return PropertyArray::cast(prop);
820 }
821 
HasProperty(Isolate * isolate,Handle<JSReceiver> object,Handle<Name> name)822 Maybe<bool> JSReceiver::HasProperty(Isolate* isolate, Handle<JSReceiver> object,
823                                     Handle<Name> name) {
824   PropertyKey key(isolate, name);
825   LookupIterator it(isolate, object, key, object);
826   return HasProperty(&it);
827 }
828 
HasOwnProperty(Isolate * isolate,Handle<JSReceiver> object,uint32_t index)829 Maybe<bool> JSReceiver::HasOwnProperty(Isolate* isolate,
830                                        Handle<JSReceiver> object,
831                                        uint32_t index) {
832   if (object->IsJSObject()) {  // Shortcut.
833     LookupIterator it(isolate, object, index, object, LookupIterator::OWN);
834     return HasProperty(&it);
835   }
836 
837   Maybe<PropertyAttributes> attributes =
838       JSReceiver::GetOwnPropertyAttributes(object, index);
839   MAYBE_RETURN(attributes, Nothing<bool>());
840   return Just(attributes.FromJust() != ABSENT);
841 }
842 
GetPropertyAttributes(Handle<JSReceiver> object,Handle<Name> name)843 Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
844     Handle<JSReceiver> object, Handle<Name> name) {
845   Isolate* isolate = object->GetIsolate();
846   PropertyKey key(isolate, name);
847   LookupIterator it(isolate, object, key, object);
848   return GetPropertyAttributes(&it);
849 }
850 
GetOwnPropertyAttributes(Handle<JSReceiver> object,Handle<Name> name)851 Maybe<PropertyAttributes> JSReceiver::GetOwnPropertyAttributes(
852     Handle<JSReceiver> object, Handle<Name> name) {
853   Isolate* isolate = object->GetIsolate();
854   PropertyKey key(isolate, name);
855   LookupIterator it(isolate, object, key, object, LookupIterator::OWN);
856   return GetPropertyAttributes(&it);
857 }
858 
GetOwnPropertyAttributes(Handle<JSReceiver> object,uint32_t index)859 Maybe<PropertyAttributes> JSReceiver::GetOwnPropertyAttributes(
860     Handle<JSReceiver> object, uint32_t index) {
861   LookupIterator it(object->GetIsolate(), object, index, object,
862                     LookupIterator::OWN);
863   return GetPropertyAttributes(&it);
864 }
865 
HasElement(Isolate * isolate,Handle<JSReceiver> object,uint32_t index)866 Maybe<bool> JSReceiver::HasElement(Isolate* isolate, Handle<JSReceiver> object,
867                                    uint32_t index) {
868   LookupIterator it(isolate, object, index, object);
869   return HasProperty(&it);
870 }
871 
GetElementAttributes(Handle<JSReceiver> object,uint32_t index)872 Maybe<PropertyAttributes> JSReceiver::GetElementAttributes(
873     Handle<JSReceiver> object, uint32_t index) {
874   Isolate* isolate = object->GetIsolate();
875   LookupIterator it(isolate, object, index, object);
876   return GetPropertyAttributes(&it);
877 }
878 
GetOwnElementAttributes(Handle<JSReceiver> object,uint32_t index)879 Maybe<PropertyAttributes> JSReceiver::GetOwnElementAttributes(
880     Handle<JSReceiver> object, uint32_t index) {
881   Isolate* isolate = object->GetIsolate();
882   LookupIterator it(isolate, object, index, object, LookupIterator::OWN);
883   return GetPropertyAttributes(&it);
884 }
885 
IsDetached()886 bool JSGlobalObject::IsDetached() {
887   return global_proxy().IsDetachedFrom(*this);
888 }
889 
IsDetachedFrom(JSGlobalObject global)890 bool JSGlobalProxy::IsDetachedFrom(JSGlobalObject global) const {
891   const PrototypeIterator iter(this->GetIsolate(), *this);
892   return iter.GetCurrent() != global;
893 }
894 
SizeWithEmbedderFields(int embedder_field_count)895 inline int JSGlobalProxy::SizeWithEmbedderFields(int embedder_field_count) {
896   DCHECK_GE(embedder_field_count, 0);
897   return kHeaderSize + embedder_field_count * kEmbedderDataSlotSize;
898 }
899 
ACCESSORS(JSIteratorResult,value,Object,kValueOffset)900 ACCESSORS(JSIteratorResult, value, Object, kValueOffset)
901 ACCESSORS(JSIteratorResult, done, Object, kDoneOffset)
902 
903 // If the fast-case backing storage takes up much more memory than a dictionary
904 // backing storage would, the object should have slow elements.
905 // static
906 static inline bool ShouldConvertToSlowElements(uint32_t used_elements,
907                                                uint32_t new_capacity) {
908   uint32_t size_threshold = NumberDictionary::kPreferFastElementsSizeFactor *
909                             NumberDictionary::ComputeCapacity(used_elements) *
910                             NumberDictionary::kEntrySize;
911   return size_threshold <= new_capacity;
912 }
913 
ShouldConvertToSlowElements(JSObject object,uint32_t capacity,uint32_t index,uint32_t * new_capacity)914 static inline bool ShouldConvertToSlowElements(JSObject object,
915                                                uint32_t capacity,
916                                                uint32_t index,
917                                                uint32_t* new_capacity) {
918   STATIC_ASSERT(JSObject::kMaxUncheckedOldFastElementsLength <=
919                 JSObject::kMaxUncheckedFastElementsLength);
920   if (index < capacity) {
921     *new_capacity = capacity;
922     return false;
923   }
924   if (index - capacity >= JSObject::kMaxGap) return true;
925   *new_capacity = JSObject::NewElementsCapacity(index + 1);
926   DCHECK_LT(index, *new_capacity);
927   if (*new_capacity <= JSObject::kMaxUncheckedOldFastElementsLength ||
928       (*new_capacity <= JSObject::kMaxUncheckedFastElementsLength &&
929        ObjectInYoungGeneration(object))) {
930     return false;
931   }
932   return ShouldConvertToSlowElements(object.GetFastElementsUsage(),
933                                      *new_capacity);
934 }
935 
936 }  // namespace internal
937 }  // namespace v8
938 
939 #include "src/objects/object-macros-undef.h"
940 
941 #endif  // V8_OBJECTS_JS_OBJECTS_INL_H_
942