V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
js-objects-inl.h
1 // Copyright 2018 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef V8_OBJECTS_JS_OBJECTS_INL_H_
6 #define V8_OBJECTS_JS_OBJECTS_INL_H_
7 
8 #include "src/objects/js-objects.h"
9 
10 #include "src/feedback-vector.h"
11 #include "src/heap/heap-write-barrier.h"
12 #include "src/keys.h"
13 #include "src/lookup-inl.h"
14 #include "src/objects/embedder-data-slot-inl.h"
15 #include "src/objects/property-array-inl.h"
16 #include "src/objects/shared-function-info.h"
17 #include "src/objects/slots.h"
18 #include "src/objects/smi-inl.h"
19 #include "src/prototype.h"
20 
21 // Has to be the last include (doesn't have include guards):
22 #include "src/objects/object-macros.h"
23 
24 namespace v8 {
25 namespace internal {
26 
27 CAST_ACCESSOR(JSAsyncFromSyncIterator)
28 CAST_ACCESSOR(JSBoundFunction)
29 CAST_ACCESSOR(JSDataView)
30 CAST_ACCESSOR(JSDate)
31 CAST_ACCESSOR(JSFunction)
32 CAST_ACCESSOR(JSGlobalObject)
33 CAST_ACCESSOR(JSGlobalProxy)
34 CAST_ACCESSOR(JSMessageObject)
35 CAST_ACCESSOR(JSObject)
36 CAST_ACCESSOR(JSReceiver)
37 CAST_ACCESSOR(JSStringIterator)
38 CAST_ACCESSOR(JSValue)
39 
40 MaybeHandle<Object> JSReceiver::GetProperty(Isolate* isolate,
41  Handle<JSReceiver> receiver,
42  Handle<Name> name) {
43  LookupIterator it(isolate, receiver, name, receiver);
44  if (!it.IsFound()) return it.factory()->undefined_value();
45  return Object::GetProperty(&it);
46 }
47 
48 MaybeHandle<Object> JSReceiver::GetElement(Isolate* isolate,
49  Handle<JSReceiver> receiver,
50  uint32_t index) {
51  LookupIterator it(isolate, receiver, index, receiver);
52  if (!it.IsFound()) return it.factory()->undefined_value();
53  return Object::GetProperty(&it);
54 }
55 
56 Handle<Object> JSReceiver::GetDataProperty(Handle<JSReceiver> object,
57  Handle<Name> name) {
58  LookupIterator it(object, name, object,
59  LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
60  if (!it.IsFound()) return it.factory()->undefined_value();
61  return GetDataProperty(&it);
62 }
63 
64 MaybeHandle<Object> JSReceiver::GetPrototype(Isolate* isolate,
65  Handle<JSReceiver> receiver) {
66  // We don't expect access checks to be needed on JSProxy objects.
67  DCHECK(!receiver->IsAccessCheckNeeded() || receiver->IsJSObject());
68  PrototypeIterator iter(isolate, receiver, kStartAtReceiver,
69  PrototypeIterator::END_AT_NON_HIDDEN);
70  do {
71  if (!iter.AdvanceFollowingProxies()) return MaybeHandle<Object>();
72  } while (!iter.IsAtEnd());
73  return PrototypeIterator::GetCurrent(iter);
74 }
75 
76 MaybeHandle<Object> JSReceiver::GetProperty(Isolate* isolate,
77  Handle<JSReceiver> receiver,
78  const char* name) {
79  Handle<String> str = isolate->factory()->InternalizeUtf8String(name);
80  return GetProperty(isolate, receiver, str);
81 }
82 
83 // static
84 V8_WARN_UNUSED_RESULT MaybeHandle<FixedArray> JSReceiver::OwnPropertyKeys(
85  Handle<JSReceiver> object) {
86  return KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly,
87  ALL_PROPERTIES,
88  GetKeysConversion::kConvertToString);
89 }
90 
91 bool JSObject::PrototypeHasNoElements(Isolate* isolate, JSObject* object) {
92  DisallowHeapAllocation no_gc;
93  HeapObject* prototype = HeapObject::cast(object->map()->prototype());
94  ReadOnlyRoots roots(isolate);
95  HeapObject* null = roots.null_value();
96  FixedArrayBase empty_fixed_array = roots.empty_fixed_array();
97  FixedArrayBase empty_slow_element_dictionary =
98  roots.empty_slow_element_dictionary();
99  while (prototype != null) {
100  Map map = prototype->map();
101  if (map->IsCustomElementsReceiverMap()) return false;
102  FixedArrayBase elements = JSObject::cast(prototype)->elements();
103  if (elements != empty_fixed_array &&
104  elements != empty_slow_element_dictionary) {
105  return false;
106  }
107  prototype = HeapObject::cast(map->prototype());
108  }
109  return true;
110 }
111 
112 ACCESSORS(JSReceiver, raw_properties_or_hash, Object, kPropertiesOrHashOffset)
113 
114 FixedArrayBase JSObject::elements() const {
115  Object* array = READ_FIELD(this, kElementsOffset);
116  return FixedArrayBase::cast(array);
117 }
118 
119 void JSObject::EnsureCanContainHeapObjectElements(Handle<JSObject> object) {
120  JSObject::ValidateElements(*object);
121  ElementsKind elements_kind = object->map()->elements_kind();
122  if (!IsObjectElementsKind(elements_kind)) {
123  if (IsHoleyElementsKind(elements_kind)) {
124  TransitionElementsKind(object, HOLEY_ELEMENTS);
125  } else {
126  TransitionElementsKind(object, PACKED_ELEMENTS);
127  }
128  }
129 }
130 
131 void JSObject::EnsureCanContainElements(Handle<JSObject> object,
132  ObjectSlot objects, uint32_t count,
133  EnsureElementsMode mode) {
134  ElementsKind current_kind = object->GetElementsKind();
135  ElementsKind target_kind = current_kind;
136  {
137  DisallowHeapAllocation no_allocation;
138  DCHECK(mode != ALLOW_COPIED_DOUBLE_ELEMENTS);
139  bool is_holey = IsHoleyElementsKind(current_kind);
140  if (current_kind == HOLEY_ELEMENTS) return;
141  Object* the_hole = object->GetReadOnlyRoots().the_hole_value();
142  for (uint32_t i = 0; i < count; ++i, ++objects) {
143  Object* current = *objects;
144  if (current == the_hole) {
145  is_holey = true;
146  target_kind = GetHoleyElementsKind(target_kind);
147  } else if (!current->IsSmi()) {
148  if (mode == ALLOW_CONVERTED_DOUBLE_ELEMENTS && current->IsNumber()) {
149  if (IsSmiElementsKind(target_kind)) {
150  if (is_holey) {
151  target_kind = HOLEY_DOUBLE_ELEMENTS;
152  } else {
153  target_kind = PACKED_DOUBLE_ELEMENTS;
154  }
155  }
156  } else if (is_holey) {
157  target_kind = HOLEY_ELEMENTS;
158  break;
159  } else {
160  target_kind = PACKED_ELEMENTS;
161  }
162  }
163  }
164  }
165  if (target_kind != current_kind) {
166  TransitionElementsKind(object, target_kind);
167  }
168 }
169 
170 void JSObject::EnsureCanContainElements(Handle<JSObject> object,
171  Handle<FixedArrayBase> elements,
172  uint32_t length,
173  EnsureElementsMode mode) {
174  ReadOnlyRoots roots = object->GetReadOnlyRoots();
175  if (elements->map() != roots.fixed_double_array_map()) {
176  DCHECK(elements->map() == roots.fixed_array_map() ||
177  elements->map() == roots.fixed_cow_array_map());
178  if (mode == ALLOW_COPIED_DOUBLE_ELEMENTS) {
179  mode = DONT_ALLOW_DOUBLE_ELEMENTS;
180  }
181  ObjectSlot objects =
182  Handle<FixedArray>::cast(elements)->GetFirstElementAddress();
183  EnsureCanContainElements(object, objects, length, mode);
184  return;
185  }
186 
187  DCHECK(mode == ALLOW_COPIED_DOUBLE_ELEMENTS);
188  if (object->GetElementsKind() == HOLEY_SMI_ELEMENTS) {
189  TransitionElementsKind(object, HOLEY_DOUBLE_ELEMENTS);
190  } else if (object->GetElementsKind() == PACKED_SMI_ELEMENTS) {
191  Handle<FixedDoubleArray> double_array =
192  Handle<FixedDoubleArray>::cast(elements);
193  for (uint32_t i = 0; i < length; ++i) {
194  if (double_array->is_the_hole(i)) {
195  TransitionElementsKind(object, HOLEY_DOUBLE_ELEMENTS);
196  return;
197  }
198  }
199  TransitionElementsKind(object, PACKED_DOUBLE_ELEMENTS);
200  }
201 }
202 
203 void JSObject::SetMapAndElements(Handle<JSObject> object, Handle<Map> new_map,
204  Handle<FixedArrayBase> value) {
205  JSObject::MigrateToMap(object, new_map);
206  DCHECK((object->map()->has_fast_smi_or_object_elements() ||
207  (*value == object->GetReadOnlyRoots().empty_fixed_array()) ||
208  object->map()->has_fast_string_wrapper_elements()) ==
209  (value->map() == object->GetReadOnlyRoots().fixed_array_map() ||
210  value->map() == object->GetReadOnlyRoots().fixed_cow_array_map()));
211  DCHECK((*value == object->GetReadOnlyRoots().empty_fixed_array()) ||
212  (object->map()->has_fast_double_elements() ==
213  value->IsFixedDoubleArray()));
214  object->set_elements(*value);
215 }
216 
217 void JSObject::set_elements(FixedArrayBase value, WriteBarrierMode mode) {
218  WRITE_FIELD(this, kElementsOffset, value);
219  CONDITIONAL_WRITE_BARRIER(this, kElementsOffset, value, mode);
220 }
221 
222 void JSObject::initialize_elements() {
223  FixedArrayBase elements = map()->GetInitialElements();
224  WRITE_FIELD(this, kElementsOffset, elements);
225 }
226 
227 InterceptorInfo* JSObject::GetIndexedInterceptor() {
228  return map()->GetIndexedInterceptor();
229 }
230 
231 InterceptorInfo* JSObject::GetNamedInterceptor() {
232  return map()->GetNamedInterceptor();
233 }
234 
235 int JSObject::GetHeaderSize() const { return GetHeaderSize(map()); }
236 
237 int JSObject::GetHeaderSize(const Map map) {
238  // Check for the most common kind of JavaScript object before
239  // falling into the generic switch. This speeds up the internal
240  // field operations considerably on average.
241  InstanceType instance_type = map->instance_type();
242  return instance_type == JS_OBJECT_TYPE
243  ? JSObject::kHeaderSize
244  : GetHeaderSize(instance_type, map->has_prototype_slot());
245 }
246 
247 // static
248 int JSObject::GetEmbedderFieldCount(const Map map) {
249  int instance_size = map->instance_size();
250  if (instance_size == kVariableSizeSentinel) return 0;
251  // Internal objects do follow immediately after the header, whereas in-object
252  // properties are at the end of the object. Therefore there is no need
253  // to adjust the index here.
254  return (((instance_size - GetHeaderSize(map)) >> kTaggedSizeLog2) -
255  map->GetInObjectProperties()) /
256  kEmbedderDataSlotSizeInTaggedSlots;
257 }
258 
259 int JSObject::GetEmbedderFieldCount() const {
260  return GetEmbedderFieldCount(map());
261 }
262 
263 int JSObject::GetEmbedderFieldOffset(int index) {
264  DCHECK(index < GetEmbedderFieldCount() && index >= 0);
265  // Internal objects do follow immediately after the header, whereas in-object
266  // properties are at the end of the object. Therefore there is no need
267  // to adjust the index here.
268  return GetHeaderSize() + (kEmbedderDataSlotSize * index);
269 }
270 
271 Object* JSObject::GetEmbedderField(int index) {
272  return EmbedderDataSlot(this, index).load_tagged();
273 }
274 
275 void JSObject::SetEmbedderField(int index, Object* value) {
276  EmbedderDataSlot::store_tagged(this, index, value);
277 }
278 
279 void JSObject::SetEmbedderField(int index, Smi value) {
280  EmbedderDataSlot(this, index).store_smi(value);
281 }
282 
283 bool JSObject::IsUnboxedDoubleField(FieldIndex index) {
284  if (!FLAG_unbox_double_fields) return false;
285  return map()->IsUnboxedDoubleField(index);
286 }
287 
288 // Access fast-case object properties at index. The use of these routines
289 // is needed to correctly distinguish between properties stored in-object and
290 // properties stored in the properties array.
291 Object* JSObject::RawFastPropertyAt(FieldIndex index) {
292  DCHECK(!IsUnboxedDoubleField(index));
293  if (index.is_inobject()) {
294  return READ_FIELD(this, index.offset());
295  } else {
296  return property_array()->get(index.outobject_array_index());
297  }
298 }
299 
300 double JSObject::RawFastDoublePropertyAt(FieldIndex index) {
301  DCHECK(IsUnboxedDoubleField(index));
302  return READ_DOUBLE_FIELD(this, index.offset());
303 }
304 
305 uint64_t JSObject::RawFastDoublePropertyAsBitsAt(FieldIndex index) {
306  DCHECK(IsUnboxedDoubleField(index));
307  return READ_UINT64_FIELD(this, index.offset());
308 }
309 
310 void JSObject::RawFastPropertyAtPut(FieldIndex index, Object* value) {
311  if (index.is_inobject()) {
312  int offset = index.offset();
313  WRITE_FIELD(this, offset, value);
314  WRITE_BARRIER(this, offset, value);
315  } else {
316  property_array()->set(index.outobject_array_index(), value);
317  }
318 }
319 
320 void JSObject::RawFastDoublePropertyAsBitsAtPut(FieldIndex index,
321  uint64_t bits) {
322  // Double unboxing is enabled only on 64-bit platforms without pointer
323  // compression.
324  DCHECK_EQ(kDoubleSize, kTaggedSize);
325  Address field_addr = FIELD_ADDR(this, index.offset());
326  base::Relaxed_Store(reinterpret_cast<base::AtomicWord*>(field_addr),
327  static_cast<base::AtomicWord>(bits));
328 }
329 
330 void JSObject::FastPropertyAtPut(FieldIndex index, Object* value) {
331  if (IsUnboxedDoubleField(index)) {
332  DCHECK(value->IsMutableHeapNumber());
333  // Ensure that all bits of the double value are preserved.
334  RawFastDoublePropertyAsBitsAtPut(
335  index, MutableHeapNumber::cast(value)->value_as_bits());
336  } else {
337  RawFastPropertyAtPut(index, value);
338  }
339 }
340 
341 void JSObject::WriteToField(int descriptor, PropertyDetails details,
342  Object* value) {
343  DCHECK_EQ(kField, details.location());
344  DCHECK_EQ(kData, details.kind());
345  DisallowHeapAllocation no_gc;
346  FieldIndex index = FieldIndex::ForDescriptor(map(), descriptor);
347  if (details.representation().IsDouble()) {
348  // Nothing more to be done.
349  if (value->IsUninitialized()) {
350  return;
351  }
352  // Manipulating the signaling NaN used for the hole and uninitialized
353  // double field sentinel in C++, e.g. with bit_cast or value()/set_value(),
354  // will change its value on ia32 (the x87 stack is used to return values
355  // and stores to the stack silently clear the signalling bit).
356  uint64_t bits;
357  if (value->IsSmi()) {
358  bits = bit_cast<uint64_t>(static_cast<double>(Smi::ToInt(value)));
359  } else {
360  DCHECK(value->IsHeapNumber());
361  bits = HeapNumber::cast(value)->value_as_bits();
362  }
363  if (IsUnboxedDoubleField(index)) {
364  RawFastDoublePropertyAsBitsAtPut(index, bits);
365  } else {
366  auto box = MutableHeapNumber::cast(RawFastPropertyAt(index));
367  box->set_value_as_bits(bits);
368  }
369  } else {
370  RawFastPropertyAtPut(index, value);
371  }
372 }
373 
374 int JSObject::GetInObjectPropertyOffset(int index) {
375  return map()->GetInObjectPropertyOffset(index);
376 }
377 
378 Object* JSObject::InObjectPropertyAt(int index) {
379  int offset = GetInObjectPropertyOffset(index);
380  return READ_FIELD(this, offset);
381 }
382 
383 Object* JSObject::InObjectPropertyAtPut(int index, Object* value,
384  WriteBarrierMode mode) {
385  // Adjust for the number of properties stored in the object.
386  int offset = GetInObjectPropertyOffset(index);
387  WRITE_FIELD(this, offset, value);
388  CONDITIONAL_WRITE_BARRIER(this, offset, value, mode);
389  return value;
390 }
391 
392 void JSObject::InitializeBody(Map map, int start_offset,
393  Object* pre_allocated_value,
394  Object* filler_value) {
395  DCHECK(!filler_value->IsHeapObject() || !Heap::InNewSpace(filler_value));
396  DCHECK(!pre_allocated_value->IsHeapObject() ||
397  !Heap::InNewSpace(pre_allocated_value));
398  int size = map->instance_size();
399  int offset = start_offset;
400  if (filler_value != pre_allocated_value) {
401  int end_of_pre_allocated_offset =
402  size - (map->UnusedPropertyFields() * kTaggedSize);
403  DCHECK_LE(kHeaderSize, end_of_pre_allocated_offset);
404  while (offset < end_of_pre_allocated_offset) {
405  WRITE_FIELD(this, offset, pre_allocated_value);
406  offset += kTaggedSize;
407  }
408  }
409  while (offset < size) {
410  WRITE_FIELD(this, offset, filler_value);
411  offset += kTaggedSize;
412  }
413 }
414 
415 Object* JSBoundFunction::raw_bound_target_function() const {
416  return READ_FIELD(this, kBoundTargetFunctionOffset);
417 }
418 
419 ACCESSORS(JSBoundFunction, bound_target_function, JSReceiver,
420  kBoundTargetFunctionOffset)
421 ACCESSORS(JSBoundFunction, bound_this, Object, kBoundThisOffset)
422 ACCESSORS2(JSBoundFunction, bound_arguments, FixedArray, kBoundArgumentsOffset)
423 
424 ACCESSORS(JSFunction, shared, SharedFunctionInfo, kSharedFunctionInfoOffset)
425 ACCESSORS(JSFunction, feedback_cell, FeedbackCell, kFeedbackCellOffset)
426 
427 ACCESSORS2(JSGlobalObject, native_context, Context, kNativeContextOffset)
428 ACCESSORS(JSGlobalObject, global_proxy, JSObject, kGlobalProxyOffset)
429 
430 ACCESSORS(JSGlobalProxy, native_context, Object, kNativeContextOffset)
431 
432 FeedbackVector* JSFunction::feedback_vector() const {
433  DCHECK(has_feedback_vector());
434  return FeedbackVector::cast(feedback_cell()->value());
435 }
436 
437 // Code objects that are marked for deoptimization are not considered to be
438 // optimized. This is because the JSFunction might have been already
439 // deoptimized but its code() still needs to be unlinked, which will happen on
440 // its next activation.
441 // TODO(jupvfranco): rename this function. Maybe RunOptimizedCode,
442 // or IsValidOptimizedCode.
443 bool JSFunction::IsOptimized() {
444  return code()->kind() == Code::OPTIMIZED_FUNCTION &&
445  !code()->marked_for_deoptimization();
446 }
447 
448 bool JSFunction::HasOptimizedCode() {
449  return IsOptimized() ||
450  (has_feedback_vector() && feedback_vector()->has_optimized_code() &&
451  !feedback_vector()->optimized_code()->marked_for_deoptimization());
452 }
453 
454 bool JSFunction::HasOptimizationMarker() {
455  return has_feedback_vector() && feedback_vector()->has_optimization_marker();
456 }
457 
458 void JSFunction::ClearOptimizationMarker() {
459  DCHECK(has_feedback_vector());
460  feedback_vector()->ClearOptimizationMarker();
461 }
462 
463 // Optimized code marked for deoptimization will tier back down to running
464 // interpreted on its next activation, and already doesn't count as IsOptimized.
465 bool JSFunction::IsInterpreted() {
466  return code()->is_interpreter_trampoline_builtin() ||
467  (code()->kind() == Code::OPTIMIZED_FUNCTION &&
468  code()->marked_for_deoptimization());
469 }
470 
471 bool JSFunction::ChecksOptimizationMarker() {
472  return code()->checks_optimization_marker();
473 }
474 
475 bool JSFunction::IsMarkedForOptimization() {
476  return has_feedback_vector() && feedback_vector()->optimization_marker() ==
477  OptimizationMarker::kCompileOptimized;
478 }
479 
480 bool JSFunction::IsMarkedForConcurrentOptimization() {
481  return has_feedback_vector() &&
482  feedback_vector()->optimization_marker() ==
483  OptimizationMarker::kCompileOptimizedConcurrent;
484 }
485 
486 bool JSFunction::IsInOptimizationQueue() {
487  return has_feedback_vector() && feedback_vector()->optimization_marker() ==
488  OptimizationMarker::kInOptimizationQueue;
489 }
490 
491 void JSFunction::CompleteInobjectSlackTrackingIfActive() {
492  if (!has_prototype_slot()) return;
493  if (has_initial_map() && initial_map()->IsInobjectSlackTrackingInProgress()) {
494  initial_map()->CompleteInobjectSlackTracking(GetIsolate());
495  }
496 }
497 
498 AbstractCode JSFunction::abstract_code() {
499  if (IsInterpreted()) {
500  return AbstractCode::cast(shared()->GetBytecodeArray());
501  } else {
502  return AbstractCode::cast(code());
503  }
504 }
505 
506 Code JSFunction::code() { return Code::cast(READ_FIELD(this, kCodeOffset)); }
507 
508 void JSFunction::set_code(Code value) {
509  DCHECK(!Heap::InNewSpace(value));
510  WRITE_FIELD(this, kCodeOffset, value);
511  MarkingBarrier(this, HeapObject::RawField(this, kCodeOffset), value);
512 }
513 
514 void JSFunction::set_code_no_write_barrier(Code value) {
515  DCHECK(!Heap::InNewSpace(value));
516  WRITE_FIELD(this, kCodeOffset, value);
517 }
518 
519 void JSFunction::ClearOptimizedCodeSlot(const char* reason) {
520  if (has_feedback_vector() && feedback_vector()->has_optimized_code()) {
521  if (FLAG_trace_opt) {
522  PrintF("[evicting entry from optimizing code feedback slot (%s) for ",
523  reason);
524  ShortPrint();
525  PrintF("]\n");
526  }
527  feedback_vector()->ClearOptimizedCode();
528  }
529 }
530 
531 void JSFunction::SetOptimizationMarker(OptimizationMarker marker) {
532  DCHECK(has_feedback_vector());
533  DCHECK(ChecksOptimizationMarker());
534  DCHECK(!HasOptimizedCode());
535 
536  feedback_vector()->SetOptimizationMarker(marker);
537 }
538 
539 bool JSFunction::has_feedback_vector() const {
540  return !feedback_cell()->value()->IsUndefined();
541 }
542 
543 Context JSFunction::context() {
544  return Context::cast(READ_FIELD(this, kContextOffset));
545 }
546 
547 bool JSFunction::has_context() const {
548  return READ_FIELD(this, kContextOffset)->IsContext();
549 }
550 
551 JSGlobalProxy* JSFunction::global_proxy() { return context()->global_proxy(); }
552 
553 Context JSFunction::native_context() { return context()->native_context(); }
554 
555 void JSFunction::set_context(Object* value) {
556  DCHECK(value->IsUndefined() || value->IsContext());
557  WRITE_FIELD(this, kContextOffset, value);
558  WRITE_BARRIER(this, kContextOffset, value);
559 }
560 
561 ACCESSORS_CHECKED(JSFunction, prototype_or_initial_map, Object,
562  kPrototypeOrInitialMapOffset, map()->has_prototype_slot())
563 
564 bool JSFunction::has_prototype_slot() const {
565  return map()->has_prototype_slot();
566 }
567 
568 Map JSFunction::initial_map() { return Map::cast(prototype_or_initial_map()); }
569 
570 bool JSFunction::has_initial_map() {
571  DCHECK(has_prototype_slot());
572  return prototype_or_initial_map()->IsMap();
573 }
574 
575 bool JSFunction::has_instance_prototype() {
576  DCHECK(has_prototype_slot());
577  return has_initial_map() || !prototype_or_initial_map()->IsTheHole();
578 }
579 
580 bool JSFunction::has_prototype() {
581  DCHECK(has_prototype_slot());
582  return map()->has_non_instance_prototype() || has_instance_prototype();
583 }
584 
585 bool JSFunction::has_prototype_property() {
586  return (has_prototype_slot() && IsConstructor()) ||
587  IsGeneratorFunction(shared()->kind());
588 }
589 
590 bool JSFunction::PrototypeRequiresRuntimeLookup() {
591  return !has_prototype_property() || map()->has_non_instance_prototype();
592 }
593 
594 Object* JSFunction::instance_prototype() {
595  DCHECK(has_instance_prototype());
596  if (has_initial_map()) return initial_map()->prototype();
597  // When there is no initial map and the prototype is a JSReceiver, the
598  // initial map field is used for the prototype field.
599  return prototype_or_initial_map();
600 }
601 
602 Object* JSFunction::prototype() {
603  DCHECK(has_prototype());
604  // If the function's prototype property has been set to a non-JSReceiver
605  // value, that value is stored in the constructor field of the map.
606  if (map()->has_non_instance_prototype()) {
607  Object* prototype = map()->GetConstructor();
608  // The map must have a prototype in that field, not a back pointer.
609  DCHECK(!prototype->IsMap());
610  DCHECK(!prototype->IsFunctionTemplateInfo());
611  return prototype;
612  }
613  return instance_prototype();
614 }
615 
616 bool JSFunction::is_compiled() {
617  return code()->builtin_index() != Builtins::kCompileLazy;
618 }
619 
620 ACCESSORS(JSValue, value, Object, kValueOffset)
621 
622 ACCESSORS(JSDate, value, Object, kValueOffset)
623 ACCESSORS(JSDate, cache_stamp, Object, kCacheStampOffset)
624 ACCESSORS(JSDate, year, Object, kYearOffset)
625 ACCESSORS(JSDate, month, Object, kMonthOffset)
626 ACCESSORS(JSDate, day, Object, kDayOffset)
627 ACCESSORS(JSDate, weekday, Object, kWeekdayOffset)
628 ACCESSORS(JSDate, hour, Object, kHourOffset)
629 ACCESSORS(JSDate, min, Object, kMinOffset)
630 ACCESSORS(JSDate, sec, Object, kSecOffset)
631 
632 MessageTemplate JSMessageObject::type() const {
633  Object* value = READ_FIELD(this, kTypeOffset);
634  return MessageTemplateFromInt(Smi::ToInt(value));
635 }
636 void JSMessageObject::set_type(MessageTemplate value) {
637  WRITE_FIELD(this, kTypeOffset, Smi::FromInt(static_cast<int>(value)));
638 }
639 ACCESSORS(JSMessageObject, argument, Object, kArgumentsOffset)
640 ACCESSORS(JSMessageObject, script, Script, kScriptOffset)
641 ACCESSORS(JSMessageObject, stack_frames, Object, kStackFramesOffset)
642 SMI_ACCESSORS(JSMessageObject, start_position, kStartPositionOffset)
643 SMI_ACCESSORS(JSMessageObject, end_position, kEndPositionOffset)
644 SMI_ACCESSORS(JSMessageObject, error_level, kErrorLevelOffset)
645 
646 ElementsKind JSObject::GetElementsKind() const {
647  ElementsKind kind = map()->elements_kind();
648 #if VERIFY_HEAP && DEBUG
649  FixedArrayBase fixed_array =
650  FixedArrayBase::unchecked_cast(READ_FIELD(this, kElementsOffset));
651 
652  // If a GC was caused while constructing this object, the elements
653  // pointer may point to a one pointer filler map.
654  if (ElementsAreSafeToExamine()) {
655  Map map = fixed_array->map();
656  if (IsSmiOrObjectElementsKind(kind)) {
657  DCHECK(map == GetReadOnlyRoots().fixed_array_map() ||
658  map == GetReadOnlyRoots().fixed_cow_array_map());
659  } else if (IsDoubleElementsKind(kind)) {
660  DCHECK(fixed_array->IsFixedDoubleArray() ||
661  fixed_array == GetReadOnlyRoots().empty_fixed_array());
662  } else if (kind == DICTIONARY_ELEMENTS) {
663  DCHECK(fixed_array->IsFixedArray());
664  DCHECK(fixed_array->IsDictionary());
665  } else {
666  DCHECK(kind > DICTIONARY_ELEMENTS);
667  }
668  DCHECK(!IsSloppyArgumentsElementsKind(kind) ||
669  (elements()->IsFixedArray() && elements()->length() >= 2));
670  }
671 #endif
672  return kind;
673 }
674 
675 bool JSObject::HasObjectElements() {
676  return IsObjectElementsKind(GetElementsKind());
677 }
678 
679 bool JSObject::HasSmiElements() { return IsSmiElementsKind(GetElementsKind()); }
680 
681 bool JSObject::HasSmiOrObjectElements() {
682  return IsSmiOrObjectElementsKind(GetElementsKind());
683 }
684 
685 bool JSObject::HasDoubleElements() {
686  return IsDoubleElementsKind(GetElementsKind());
687 }
688 
689 bool JSObject::HasHoleyElements() {
690  return IsHoleyElementsKind(GetElementsKind());
691 }
692 
693 bool JSObject::HasFastElements() {
694  return IsFastElementsKind(GetElementsKind());
695 }
696 
697 bool JSObject::HasFastPackedElements() {
698  return IsFastPackedElementsKind(GetElementsKind());
699 }
700 
701 bool JSObject::HasDictionaryElements() {
702  return GetElementsKind() == DICTIONARY_ELEMENTS;
703 }
704 
705 bool JSObject::HasFastArgumentsElements() {
706  return GetElementsKind() == FAST_SLOPPY_ARGUMENTS_ELEMENTS;
707 }
708 
709 bool JSObject::HasSlowArgumentsElements() {
710  return GetElementsKind() == SLOW_SLOPPY_ARGUMENTS_ELEMENTS;
711 }
712 
713 bool JSObject::HasSloppyArgumentsElements() {
714  return IsSloppyArgumentsElementsKind(GetElementsKind());
715 }
716 
717 bool JSObject::HasStringWrapperElements() {
718  return IsStringWrapperElementsKind(GetElementsKind());
719 }
720 
721 bool JSObject::HasFastStringWrapperElements() {
722  return GetElementsKind() == FAST_STRING_WRAPPER_ELEMENTS;
723 }
724 
725 bool JSObject::HasSlowStringWrapperElements() {
726  return GetElementsKind() == SLOW_STRING_WRAPPER_ELEMENTS;
727 }
728 
729 bool JSObject::HasFixedTypedArrayElements() {
730  DCHECK(!elements().is_null());
731  return map()->has_fixed_typed_array_elements();
732 }
733 
734 #define FIXED_TYPED_ELEMENTS_CHECK(Type, type, TYPE, ctype) \
735  bool JSObject::HasFixed##Type##Elements() { \
736  FixedArrayBase array = elements(); \
737  return array->map()->instance_type() == FIXED_##TYPE##_ARRAY_TYPE; \
738  }
739 
740 TYPED_ARRAYS(FIXED_TYPED_ELEMENTS_CHECK)
741 
742 #undef FIXED_TYPED_ELEMENTS_CHECK
743 
744 bool JSObject::HasNamedInterceptor() { return map()->has_named_interceptor(); }
745 
746 bool JSObject::HasIndexedInterceptor() {
747  return map()->has_indexed_interceptor();
748 }
749 
750 void JSGlobalObject::set_global_dictionary(GlobalDictionary dictionary) {
751  DCHECK(IsJSGlobalObject());
752  set_raw_properties_or_hash(dictionary);
753 }
754 
755 GlobalDictionary JSGlobalObject::global_dictionary() {
756  DCHECK(!HasFastProperties());
757  DCHECK(IsJSGlobalObject());
758  return GlobalDictionary::cast(raw_properties_or_hash());
759 }
760 
761 NumberDictionary JSObject::element_dictionary() {
762  DCHECK(HasDictionaryElements() || HasSlowStringWrapperElements());
763  return NumberDictionary::cast(elements());
764 }
765 
766 void JSReceiver::initialize_properties() {
767  ReadOnlyRoots roots = GetReadOnlyRoots();
768  DCHECK(!Heap::InNewSpace(roots.empty_fixed_array()));
769  DCHECK(!Heap::InNewSpace(roots.empty_property_dictionary()));
770  if (map()->is_dictionary_map()) {
771  WRITE_FIELD(this, kPropertiesOrHashOffset,
772  roots.empty_property_dictionary());
773  } else {
774  WRITE_FIELD(this, kPropertiesOrHashOffset, roots.empty_fixed_array());
775  }
776 }
777 
778 bool JSReceiver::HasFastProperties() const {
779  DCHECK(
780  raw_properties_or_hash()->IsSmi() ||
781  (raw_properties_or_hash()->IsDictionary() == map()->is_dictionary_map()));
782  return !map()->is_dictionary_map();
783 }
784 
785 NameDictionary JSReceiver::property_dictionary() const {
786  DCHECK(!IsJSGlobalObject());
787  DCHECK(!HasFastProperties());
788 
789  Object* prop = raw_properties_or_hash();
790  if (prop->IsSmi()) {
791  return GetReadOnlyRoots().empty_property_dictionary();
792  }
793 
794  return NameDictionary::cast(prop);
795 }
796 
797 // TODO(gsathya): Pass isolate directly to this function and access
798 // the heap from this.
799 PropertyArray JSReceiver::property_array() const {
800  DCHECK(HasFastProperties());
801 
802  Object* prop = raw_properties_or_hash();
803  if (prop->IsSmi() || prop == GetReadOnlyRoots().empty_fixed_array()) {
804  return GetReadOnlyRoots().empty_property_array();
805  }
806 
807  return PropertyArray::cast(prop);
808 }
809 
810 Maybe<bool> JSReceiver::HasProperty(Handle<JSReceiver> object,
811  Handle<Name> name) {
812  LookupIterator it = LookupIterator::PropertyOrElement(object->GetIsolate(),
813  object, name, object);
814  return HasProperty(&it);
815 }
816 
817 Maybe<bool> JSReceiver::HasOwnProperty(Handle<JSReceiver> object,
818  uint32_t index) {
819  if (object->IsJSModuleNamespace()) return Just(false);
820 
821  if (object->IsJSObject()) { // Shortcut.
822  LookupIterator it(object->GetIsolate(), object, index, object,
823  LookupIterator::OWN);
824  return HasProperty(&it);
825  }
826 
827  Maybe<PropertyAttributes> attributes =
828  JSReceiver::GetOwnPropertyAttributes(object, index);
829  MAYBE_RETURN(attributes, Nothing<bool>());
830  return Just(attributes.FromJust() != ABSENT);
831 }
832 
833 Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
834  Handle<JSReceiver> object, Handle<Name> name) {
835  LookupIterator it = LookupIterator::PropertyOrElement(object->GetIsolate(),
836  object, name, object);
837  return GetPropertyAttributes(&it);
838 }
839 
840 Maybe<PropertyAttributes> JSReceiver::GetOwnPropertyAttributes(
841  Handle<JSReceiver> object, Handle<Name> name) {
842  LookupIterator it = LookupIterator::PropertyOrElement(
843  object->GetIsolate(), object, name, object, LookupIterator::OWN);
844  return GetPropertyAttributes(&it);
845 }
846 
847 Maybe<PropertyAttributes> JSReceiver::GetOwnPropertyAttributes(
848  Handle<JSReceiver> object, uint32_t index) {
849  LookupIterator it(object->GetIsolate(), object, index, object,
850  LookupIterator::OWN);
851  return GetPropertyAttributes(&it);
852 }
853 
854 Maybe<bool> JSReceiver::HasElement(Handle<JSReceiver> object, uint32_t index) {
855  LookupIterator it(object->GetIsolate(), object, index, object);
856  return HasProperty(&it);
857 }
858 
859 Maybe<PropertyAttributes> JSReceiver::GetElementAttributes(
860  Handle<JSReceiver> object, uint32_t index) {
861  Isolate* isolate = object->GetIsolate();
862  LookupIterator it(isolate, object, index, object);
863  return GetPropertyAttributes(&it);
864 }
865 
866 Maybe<PropertyAttributes> JSReceiver::GetOwnElementAttributes(
867  Handle<JSReceiver> object, uint32_t index) {
868  Isolate* isolate = object->GetIsolate();
869  LookupIterator it(isolate, object, index, object, LookupIterator::OWN);
870  return GetPropertyAttributes(&it);
871 }
872 
873 bool JSGlobalObject::IsDetached() {
874  return JSGlobalProxy::cast(global_proxy())->IsDetachedFrom(this);
875 }
876 
877 bool JSGlobalProxy::IsDetachedFrom(JSGlobalObject* global) const {
878  const PrototypeIterator iter(this->GetIsolate(),
879  const_cast<JSGlobalProxy*>(this));
880  return iter.GetCurrent() != global;
881 }
882 
883 inline int JSGlobalProxy::SizeWithEmbedderFields(int embedder_field_count) {
884  DCHECK_GE(embedder_field_count, 0);
885  return kSize + embedder_field_count * kEmbedderDataSlotSize;
886 }
887 
888 ACCESSORS(JSIteratorResult, value, Object, kValueOffset)
889 ACCESSORS(JSIteratorResult, done, Object, kDoneOffset)
890 
891 ACCESSORS(JSAsyncFromSyncIterator, sync_iterator, JSReceiver,
892  kSyncIteratorOffset)
893 ACCESSORS(JSAsyncFromSyncIterator, next, Object, kNextOffset)
894 
895 ACCESSORS2(JSStringIterator, string, String, kStringOffset)
896 SMI_ACCESSORS(JSStringIterator, index, kNextIndexOffset)
897 
898 } // namespace internal
899 } // namespace v8
900 
901 #include "src/objects/object-macros-undef.h"
902 
903 #endif // V8_OBJECTS_JS_OBJECTS_INL_H_
Definition: libplatform.h:13