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