V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
builtins-object-gen.cc
1 // Copyright 2017 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 #include "src/builtins/builtins-object-gen.h"
6 
7 #include "src/builtins/builtins-utils-gen.h"
8 #include "src/builtins/builtins.h"
9 #include "src/code-stub-assembler.h"
10 #include "src/heap/factory-inl.h"
11 #include "src/ic/accessor-assembler.h"
12 #include "src/ic/keyed-store-generic.h"
13 #include "src/objects/js-generator.h"
14 #include "src/objects/property-descriptor-object.h"
15 #include "src/objects/shared-function-info.h"
16 #include "src/property-details.h"
17 
18 namespace v8 {
19 namespace internal {
20 
21 // -----------------------------------------------------------------------------
22 // ES6 section 19.1 Object Objects
23 
24 typedef compiler::Node Node;
25 template <class T>
26 using TNode = CodeStubAssembler::TNode<T>;
27 
29  public:
31  : CodeStubAssembler(state) {}
32 
33  protected:
34  void ReturnToStringFormat(Node* context, Node* string);
35  void AddToDictionaryIf(TNode<BoolT> condition,
36  TNode<NameDictionary> name_dictionary,
37  Handle<Name> name, TNode<Object> value,
38  Label* bailout);
39  Node* FromPropertyDescriptor(Node* context, Node* desc);
40  Node* FromPropertyDetails(Node* context, Node* raw_value, Node* details,
41  Label* if_bailout);
42  Node* ConstructAccessorDescriptor(Node* context, Node* getter, Node* setter,
43  Node* enumerable, Node* configurable);
44  Node* ConstructDataDescriptor(Node* context, Node* value, Node* writable,
45  Node* enumerable, Node* configurable);
46  Node* GetAccessorOrUndefined(Node* accessor, Label* if_bailout);
47 
48  Node* IsSpecialReceiverMap(SloppyTNode<Map> map);
49 
50  TNode<Word32T> IsStringWrapperElementsKind(TNode<Map> map);
51 
52  void ObjectAssignFast(TNode<Context> context, TNode<JSReceiver> to,
53  TNode<Object> from, Label* slow);
54 };
55 
57  public:
60  : ObjectBuiltinsAssembler(state) {}
61 
62  protected:
63  enum CollectType { kEntries, kValues };
64 
65  TNode<BoolT> IsPropertyEnumerable(TNode<Uint32T> details);
66 
67  TNode<BoolT> IsPropertyKindAccessor(TNode<Uint32T> kind);
68 
69  TNode<BoolT> IsPropertyKindData(TNode<Uint32T> kind);
70 
71  TNode<Uint32T> HasHiddenPrototype(TNode<Map> map);
72 
73  TNode<Uint32T> LoadPropertyKind(TNode<Uint32T> details) {
74  return DecodeWord32<PropertyDetails::KindField>(details);
75  }
76 
77  void GetOwnValuesOrEntries(TNode<Context> context, TNode<Object> maybe_object,
78  CollectType collect_type);
79 
80  void GotoIfMapHasSlowProperties(TNode<Map> map, Label* if_slow);
81 
82  TNode<JSArray> FastGetOwnValuesOrEntries(
83  TNode<Context> context, TNode<JSObject> object,
84  Label* if_call_runtime_with_fast_path, Label* if_no_properties,
85  CollectType collect_type);
86 
87  TNode<JSArray> FinalizeValuesOrEntriesJSArray(
88  TNode<Context> context, TNode<FixedArray> values_or_entries,
89  TNode<IntPtrT> size, TNode<Map> array_map, Label* if_empty);
90 };
91 
92 void ObjectBuiltinsAssembler::ReturnToStringFormat(Node* context,
93  Node* string) {
94  Node* lhs = StringConstant("[object ");
95  Node* rhs = StringConstant("]");
96 
97  Callable callable = CodeFactory::StringAdd(isolate(), STRING_ADD_CHECK_NONE);
98 
99  Return(CallStub(callable, context, CallStub(callable, context, lhs, string),
100  rhs));
101 }
102 
103 Node* ObjectBuiltinsAssembler::ConstructAccessorDescriptor(Node* context,
104  Node* getter,
105  Node* setter,
106  Node* enumerable,
107  Node* configurable) {
108  Node* native_context = LoadNativeContext(context);
109  Node* map = LoadContextElement(
110  native_context, Context::ACCESSOR_PROPERTY_DESCRIPTOR_MAP_INDEX);
111  Node* js_desc = AllocateJSObjectFromMap(map);
112 
113  StoreObjectFieldNoWriteBarrier(
114  js_desc, JSAccessorPropertyDescriptor::kGetOffset, getter);
115  StoreObjectFieldNoWriteBarrier(
116  js_desc, JSAccessorPropertyDescriptor::kSetOffset, setter);
117  StoreObjectFieldNoWriteBarrier(
118  js_desc, JSAccessorPropertyDescriptor::kEnumerableOffset,
119  SelectBooleanConstant(enumerable));
120  StoreObjectFieldNoWriteBarrier(
121  js_desc, JSAccessorPropertyDescriptor::kConfigurableOffset,
122  SelectBooleanConstant(configurable));
123 
124  return js_desc;
125 }
126 
127 Node* ObjectBuiltinsAssembler::ConstructDataDescriptor(Node* context,
128  Node* value,
129  Node* writable,
130  Node* enumerable,
131  Node* configurable) {
132  Node* native_context = LoadNativeContext(context);
133  Node* map = LoadContextElement(native_context,
134  Context::DATA_PROPERTY_DESCRIPTOR_MAP_INDEX);
135  Node* js_desc = AllocateJSObjectFromMap(map);
136 
137  StoreObjectFieldNoWriteBarrier(js_desc,
138  JSDataPropertyDescriptor::kValueOffset, value);
139  StoreObjectFieldNoWriteBarrier(js_desc,
140  JSDataPropertyDescriptor::kWritableOffset,
141  SelectBooleanConstant(writable));
142  StoreObjectFieldNoWriteBarrier(js_desc,
143  JSDataPropertyDescriptor::kEnumerableOffset,
144  SelectBooleanConstant(enumerable));
145  StoreObjectFieldNoWriteBarrier(js_desc,
146  JSDataPropertyDescriptor::kConfigurableOffset,
147  SelectBooleanConstant(configurable));
148 
149  return js_desc;
150 }
151 
152 Node* ObjectBuiltinsAssembler::IsSpecialReceiverMap(SloppyTNode<Map> map) {
153  CSA_SLOW_ASSERT(this, IsMap(map));
154  TNode<BoolT> is_special =
155  IsSpecialReceiverInstanceType(LoadMapInstanceType(map));
156  uint32_t mask =
157  Map::HasNamedInterceptorBit::kMask | Map::IsAccessCheckNeededBit::kMask;
158  USE(mask);
159  // Interceptors or access checks imply special receiver.
160  CSA_ASSERT(this,
161  SelectConstant<BoolT>(IsSetWord32(LoadMapBitField(map), mask),
162  is_special, Int32TrueConstant()));
163  return is_special;
164 }
165 
166 TNode<Word32T> ObjectBuiltinsAssembler::IsStringWrapperElementsKind(
167  TNode<Map> map) {
168  Node* kind = LoadMapElementsKind(map);
169  return Word32Or(
170  Word32Equal(kind, Int32Constant(FAST_STRING_WRAPPER_ELEMENTS)),
171  Word32Equal(kind, Int32Constant(SLOW_STRING_WRAPPER_ELEMENTS)));
172 }
173 
174 TNode<BoolT> ObjectEntriesValuesBuiltinsAssembler::IsPropertyEnumerable(
175  TNode<Uint32T> details) {
176  TNode<Uint32T> attributes =
177  DecodeWord32<PropertyDetails::AttributesField>(details);
178  return IsNotSetWord32(attributes, PropertyAttributes::DONT_ENUM);
179 }
180 
181 TNode<BoolT> ObjectEntriesValuesBuiltinsAssembler::IsPropertyKindAccessor(
182  TNode<Uint32T> kind) {
183  return Word32Equal(kind, Int32Constant(PropertyKind::kAccessor));
184 }
185 
186 TNode<BoolT> ObjectEntriesValuesBuiltinsAssembler::IsPropertyKindData(
187  TNode<Uint32T> kind) {
188  return Word32Equal(kind, Int32Constant(PropertyKind::kData));
189 }
190 
191 TNode<Uint32T> ObjectEntriesValuesBuiltinsAssembler::HasHiddenPrototype(
192  TNode<Map> map) {
193  TNode<Uint32T> bit_field3 = LoadMapBitField3(map);
194  return DecodeWord32<Map::HasHiddenPrototypeBit>(bit_field3);
195 }
196 
197 void ObjectEntriesValuesBuiltinsAssembler::GetOwnValuesOrEntries(
198  TNode<Context> context, TNode<Object> maybe_object,
199  CollectType collect_type) {
200  TNode<JSReceiver> receiver = ToObject_Inline(context, maybe_object);
201 
202  Label if_call_runtime_with_fast_path(this, Label::kDeferred),
203  if_call_runtime(this, Label::kDeferred),
204  if_no_properties(this, Label::kDeferred);
205 
206  TNode<Map> map = LoadMap(receiver);
207  GotoIfNot(IsJSObjectMap(map), &if_call_runtime);
208  GotoIfMapHasSlowProperties(map, &if_call_runtime);
209 
210  TNode<JSObject> object = CAST(receiver);
211  TNode<FixedArrayBase> elements = LoadElements(object);
212  // If the object has elements, we treat it as slow case.
213  // So, we go to runtime call.
214  GotoIfNot(IsEmptyFixedArray(elements), &if_call_runtime_with_fast_path);
215 
216  TNode<JSArray> result = FastGetOwnValuesOrEntries(
217  context, object, &if_call_runtime_with_fast_path, &if_no_properties,
218  collect_type);
219  Return(result);
220 
221  BIND(&if_no_properties);
222  {
223  Node* native_context = LoadNativeContext(context);
224  TNode<Map> array_map =
225  LoadJSArrayElementsMap(PACKED_ELEMENTS, native_context);
226  TNode<JSArray> empty_array = AllocateJSArray(
227  PACKED_ELEMENTS, array_map, IntPtrConstant(0), SmiConstant(0));
228  Return(empty_array);
229  }
230 
231  BIND(&if_call_runtime_with_fast_path);
232  {
233  // In slow case, we simply call runtime.
234  if (collect_type == CollectType::kEntries) {
235  Return(CallRuntime(Runtime::kObjectEntries, context, object));
236  } else {
237  DCHECK(collect_type == CollectType::kValues);
238  Return(CallRuntime(Runtime::kObjectValues, context, object));
239  }
240  }
241 
242  BIND(&if_call_runtime);
243  {
244  // In slow case, we simply call runtime.
245  if (collect_type == CollectType::kEntries) {
246  Return(
247  CallRuntime(Runtime::kObjectEntriesSkipFastPath, context, receiver));
248  } else {
249  DCHECK(collect_type == CollectType::kValues);
250  Return(
251  CallRuntime(Runtime::kObjectValuesSkipFastPath, context, receiver));
252  }
253  }
254 }
255 
256 void ObjectEntriesValuesBuiltinsAssembler::GotoIfMapHasSlowProperties(
257  TNode<Map> map, Label* if_slow) {
258  GotoIf(IsStringWrapperElementsKind(map), if_slow);
259  GotoIf(IsSpecialReceiverMap(map), if_slow);
260  GotoIf(HasHiddenPrototype(map), if_slow);
261  GotoIf(IsDictionaryMap(map), if_slow);
262 }
263 
264 TNode<JSArray> ObjectEntriesValuesBuiltinsAssembler::FastGetOwnValuesOrEntries(
265  TNode<Context> context, TNode<JSObject> object,
266  Label* if_call_runtime_with_fast_path, Label* if_no_properties,
267  CollectType collect_type) {
268  TNode<Context> native_context = LoadNativeContext(context);
269  TNode<Map> array_map =
270  LoadJSArrayElementsMap(PACKED_ELEMENTS, native_context);
271  TNode<Map> map = LoadMap(object);
272  TNode<Uint32T> bit_field3 = LoadMapBitField3(map);
273 
274  Label if_has_enum_cache(this), if_not_has_enum_cache(this),
275  collect_entries(this);
276  TNode<IntPtrT> object_enum_length =
277  Signed(DecodeWordFromWord32<Map::EnumLengthBits>(bit_field3));
278  TNode<BoolT> has_enum_cache = WordNotEqual(
279  object_enum_length, IntPtrConstant(kInvalidEnumCacheSentinel));
280 
281  // In case, we found enum_cache in object,
282  // we use it as array_length because it has same size for
283  // Object.(entries/values) result array object length.
284  // So object_enum_length use less memory space than
285  // NumberOfOwnDescriptorsBits value.
286  // And in case, if enum_cache_not_found,
287  // we call runtime and initialize enum_cache for subsequent call of
288  // CSA fast path.
289  Branch(has_enum_cache, &if_has_enum_cache, if_call_runtime_with_fast_path);
290 
291  BIND(&if_has_enum_cache);
292  {
293  GotoIf(WordEqual(object_enum_length, IntPtrConstant(0)), if_no_properties);
294  TNode<FixedArray> values_or_entries = CAST(AllocateFixedArray(
295  PACKED_ELEMENTS, object_enum_length, kAllowLargeObjectAllocation));
296 
297  // If in case we have enum_cache,
298  // we can't detect accessor of object until loop through descriptors.
299  // So if object might have accessor,
300  // we will remain invalid addresses of FixedArray.
301  // Because in that case, we need to jump to runtime call.
302  // So the array filled by the-hole even if enum_cache exists.
303  FillFixedArrayWithValue(PACKED_ELEMENTS, values_or_entries,
304  IntPtrConstant(0), object_enum_length,
305  RootIndex::kTheHoleValue);
306 
307  TVARIABLE(IntPtrT, var_result_index, IntPtrConstant(0));
308  TVARIABLE(IntPtrT, var_descriptor_number, IntPtrConstant(0));
309  Variable* vars[] = {&var_descriptor_number, &var_result_index};
310  // Let desc be ? O.[[GetOwnProperty]](key).
311  TNode<DescriptorArray> descriptors = LoadMapDescriptors(map);
312  Label loop(this, 2, vars), after_loop(this), next_descriptor(this);
313  Branch(IntPtrEqual(var_descriptor_number.value(), object_enum_length),
314  &after_loop, &loop);
315 
316  // We dont use BuildFastLoop.
317  // Instead, we use hand-written loop
318  // because of we need to use 'continue' functionality.
319  BIND(&loop);
320  {
321  // Currently, we will not invoke getters,
322  // so, map will not be changed.
323  CSA_ASSERT(this, WordEqual(map, LoadMap(object)));
324  TNode<IntPtrT> descriptor_entry = var_descriptor_number.value();
325  Node* next_key = LoadKeyByDescriptorEntry(descriptors, descriptor_entry);
326 
327  // Skip Symbols.
328  GotoIf(IsSymbol(next_key), &next_descriptor);
329 
330  TNode<Uint32T> details =
331  LoadDetailsByDescriptorEntry(descriptors, descriptor_entry);
332 
333  TNode<Uint32T> kind = LoadPropertyKind(details);
334 
335  // If property is accessor, we escape fast path and call runtime.
336  GotoIf(IsPropertyKindAccessor(kind), if_call_runtime_with_fast_path);
337  CSA_ASSERT(this, IsPropertyKindData(kind));
338 
339  // If desc is not undefined and desc.[[Enumerable]] is true, then skip to
340  // the next descriptor.
341  GotoIfNot(IsPropertyEnumerable(details), &next_descriptor);
342 
343  TVARIABLE(Object, var_property_value, UndefinedConstant());
344  TNode<IntPtrT> descriptor_name_index = ToKeyIndex<DescriptorArray>(
345  Unsigned(TruncateIntPtrToInt32(var_descriptor_number.value())));
346 
347  // Let value be ? Get(O, key).
348  LoadPropertyFromFastObject(object, map, descriptors,
349  descriptor_name_index, details,
350  &var_property_value);
351 
352  // If kind is "value", append value to properties.
353  TNode<Object> value = var_property_value.value();
354 
355  if (collect_type == CollectType::kEntries) {
356  // Let entry be CreateArrayFromList(« key, value »).
357  Node* array = nullptr;
358  Node* elements = nullptr;
359  std::tie(array, elements) = AllocateUninitializedJSArrayWithElements(
360  PACKED_ELEMENTS, array_map, SmiConstant(2), nullptr,
361  IntPtrConstant(2));
362  StoreFixedArrayElement(CAST(elements), 0, next_key, SKIP_WRITE_BARRIER);
363  StoreFixedArrayElement(CAST(elements), 1, value, SKIP_WRITE_BARRIER);
364  value = TNode<JSArray>::UncheckedCast(array);
365  }
366 
367  StoreFixedArrayElement(values_or_entries, var_result_index.value(),
368  value);
369  Increment(&var_result_index, 1);
370  Goto(&next_descriptor);
371 
372  BIND(&next_descriptor);
373  {
374  Increment(&var_descriptor_number, 1);
375  Branch(IntPtrEqual(var_result_index.value(), object_enum_length),
376  &after_loop, &loop);
377  }
378  }
379  BIND(&after_loop);
380  return FinalizeValuesOrEntriesJSArray(context, values_or_entries,
381  var_result_index.value(), array_map,
382  if_no_properties);
383  }
384 }
385 
386 TNode<JSArray>
387 ObjectEntriesValuesBuiltinsAssembler::FinalizeValuesOrEntriesJSArray(
388  TNode<Context> context, TNode<FixedArray> result, TNode<IntPtrT> size,
389  TNode<Map> array_map, Label* if_empty) {
390  CSA_ASSERT(this, IsJSArrayMap(array_map));
391 
392  GotoIf(IntPtrEqual(size, IntPtrConstant(0)), if_empty);
393  Node* array = AllocateUninitializedJSArrayWithoutElements(
394  array_map, SmiTag(size), nullptr);
395  StoreObjectField(array, JSArray::kElementsOffset, result);
396  return TNode<JSArray>::UncheckedCast(array);
397 }
398 
399 TF_BUILTIN(ObjectPrototypeToLocaleString, CodeStubAssembler) {
400  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
401  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
402 
403  Label if_null_or_undefined(this, Label::kDeferred);
404  GotoIf(IsNullOrUndefined(receiver), &if_null_or_undefined);
405 
406  TNode<Object> method =
407  GetProperty(context, receiver, factory()->toString_string());
408  Return(CallJS(CodeFactory::Call(isolate()), context, method, receiver));
409 
410  BIND(&if_null_or_undefined);
411  ThrowTypeError(context, MessageTemplate::kCalledOnNullOrUndefined,
412  "Object.prototype.toLocaleString");
413 }
414 
415 TF_BUILTIN(ObjectPrototypeHasOwnProperty, ObjectBuiltinsAssembler) {
416  Node* object = Parameter(Descriptor::kReceiver);
417  Node* key = Parameter(Descriptor::kKey);
418  Node* context = Parameter(Descriptor::kContext);
419 
420  Label call_runtime(this), return_true(this), return_false(this),
421  to_primitive(this);
422 
423  // Smi receivers do not have own properties, just perform ToPrimitive on the
424  // key.
425  Label if_objectisnotsmi(this);
426  Branch(TaggedIsSmi(object), &to_primitive, &if_objectisnotsmi);
427  BIND(&if_objectisnotsmi);
428 
429  Node* map = LoadMap(object);
430  TNode<Int32T> instance_type = LoadMapInstanceType(map);
431 
432  {
433  VARIABLE(var_index, MachineType::PointerRepresentation());
434  VARIABLE(var_unique, MachineRepresentation::kTagged);
435 
436  Label if_index(this), if_unique_name(this), if_notunique_name(this);
437  TryToName(key, &if_index, &var_index, &if_unique_name, &var_unique,
438  &call_runtime, &if_notunique_name);
439 
440  BIND(&if_unique_name);
441  TryHasOwnProperty(object, map, instance_type, var_unique.value(),
442  &return_true, &return_false, &call_runtime);
443 
444  BIND(&if_index);
445  {
446  // Handle negative keys in the runtime.
447  GotoIf(IntPtrLessThan(var_index.value(), IntPtrConstant(0)),
448  &call_runtime);
449  TryLookupElement(object, map, instance_type, var_index.value(),
450  &return_true, &return_false, &return_false,
451  &call_runtime);
452  }
453 
454  BIND(&if_notunique_name);
455  {
456  Label not_in_string_table(this);
457  TryInternalizeString(key, &if_index, &var_index, &if_unique_name,
458  &var_unique, &not_in_string_table, &call_runtime);
459 
460  BIND(&not_in_string_table);
461  {
462  // If the string was not found in the string table, then no regular
463  // object can have a property with that name, so return |false|.
464  // "Special API objects" with interceptors must take the slow path.
465  Branch(IsSpecialReceiverInstanceType(instance_type), &call_runtime,
466  &return_false);
467  }
468  }
469  }
470  BIND(&to_primitive);
471  GotoIf(IsNumber(key), &return_false);
472  Branch(IsName(key), &return_false, &call_runtime);
473 
474  BIND(&return_true);
475  Return(TrueConstant());
476 
477  BIND(&return_false);
478  Return(FalseConstant());
479 
480  BIND(&call_runtime);
481  Return(CallRuntime(Runtime::kObjectHasOwnProperty, context, object, key));
482 }
483 
484 // ES #sec-object.assign
485 TF_BUILTIN(ObjectAssign, ObjectBuiltinsAssembler) {
486  TNode<IntPtrT> argc =
487  ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
488  CodeStubArguments args(this, argc);
489 
490  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
491  TNode<Object> target = args.GetOptionalArgumentValue(0);
492 
493  // 1. Let to be ? ToObject(target).
494  TNode<JSReceiver> to = ToObject_Inline(context, target);
495 
496  Label done(this);
497  // 2. If only one argument was passed, return to.
498  GotoIf(UintPtrLessThanOrEqual(argc, IntPtrConstant(1)), &done);
499 
500  // 3. Let sources be the List of argument values starting with the
501  // second argument.
502  // 4. For each element nextSource of sources, in ascending index order,
503  args.ForEach(
504  [=](Node* next_source_) {
505  TNode<Object> next_source = CAST(next_source_);
506  Label slow(this), cont(this);
507  ObjectAssignFast(context, to, next_source, &slow);
508  Goto(&cont);
509 
510  BIND(&slow);
511  {
512  CallRuntime(Runtime::kSetDataProperties, context, to, next_source);
513  Goto(&cont);
514  }
515  BIND(&cont);
516  },
517  IntPtrConstant(1));
518  Goto(&done);
519 
520  // 5. Return to.
521  BIND(&done);
522  args.PopAndReturn(to);
523 }
524 
525 // This function mimics what FastAssign() function does for C++ implementation.
526 void ObjectBuiltinsAssembler::ObjectAssignFast(TNode<Context> context,
527  TNode<JSReceiver> to,
528  TNode<Object> from,
529  Label* slow) {
530  Label done(this);
531 
532  // Non-empty strings are the only non-JSReceivers that need to be handled
533  // explicitly by Object.assign.
534  GotoIf(TaggedIsSmi(from), &done);
535  TNode<Map> from_map = LoadMap(CAST(from));
536  TNode<Int32T> from_instance_type = LoadMapInstanceType(from_map);
537  {
538  Label cont(this);
539  GotoIf(IsJSReceiverInstanceType(from_instance_type), &cont);
540  GotoIfNot(IsStringInstanceType(from_instance_type), &done);
541  {
542  Branch(
543  Word32Equal(LoadStringLengthAsWord32(CAST(from)), Int32Constant(0)),
544  &done, slow);
545  }
546  BIND(&cont);
547  }
548 
549  // If the target is deprecated, the object will be updated on first store. If
550  // the source for that store equals the target, this will invalidate the
551  // cached representation of the source. Handle this case in runtime.
552  TNode<Map> to_map = LoadMap(to);
553  GotoIf(IsDeprecatedMap(to_map), slow);
554  TNode<BoolT> to_is_simple_receiver = IsSimpleObjectMap(to_map);
555 
556  GotoIfNot(IsJSObjectInstanceType(from_instance_type), slow);
557  GotoIfNot(IsEmptyFixedArray(LoadElements(CAST(from))), slow);
558 
559  ForEachEnumerableOwnProperty(context, from_map, CAST(from),
560  [=](TNode<Name> key, TNode<Object> value) {
561  KeyedStoreGenericGenerator::SetProperty(
562  state(), context, to,
563  to_is_simple_receiver, key, value,
564  LanguageMode::kStrict);
565  },
566  slow);
567 
568  Goto(&done);
569  BIND(&done);
570 }
571 
572 // ES #sec-object.keys
573 TF_BUILTIN(ObjectKeys, ObjectBuiltinsAssembler) {
574  Node* object = Parameter(Descriptor::kObject);
575  Node* context = Parameter(Descriptor::kContext);
576 
577  VARIABLE(var_length, MachineRepresentation::kTagged);
578  VARIABLE(var_elements, MachineRepresentation::kTagged);
579  Label if_empty(this, Label::kDeferred), if_empty_elements(this),
580  if_fast(this), if_slow(this, Label::kDeferred), if_join(this);
581 
582  // Check if the {object} has a usable enum cache.
583  GotoIf(TaggedIsSmi(object), &if_slow);
584  Node* object_map = LoadMap(object);
585  Node* object_bit_field3 = LoadMapBitField3(object_map);
586  Node* object_enum_length =
587  DecodeWordFromWord32<Map::EnumLengthBits>(object_bit_field3);
588  GotoIf(
589  WordEqual(object_enum_length, IntPtrConstant(kInvalidEnumCacheSentinel)),
590  &if_slow);
591 
592  // Ensure that the {object} doesn't have any elements.
593  CSA_ASSERT(this, IsJSObjectMap(object_map));
594  Node* object_elements = LoadElements(object);
595  GotoIf(IsEmptyFixedArray(object_elements), &if_empty_elements);
596  Branch(IsEmptySlowElementDictionary(object_elements), &if_empty_elements,
597  &if_slow);
598 
599  // Check whether there are enumerable properties.
600  BIND(&if_empty_elements);
601  Branch(WordEqual(object_enum_length, IntPtrConstant(0)), &if_empty, &if_fast);
602 
603  BIND(&if_fast);
604  {
605  // The {object} has a usable enum cache, use that.
606  Node* object_descriptors = LoadMapDescriptors(object_map);
607  Node* object_enum_cache =
608  LoadObjectField(object_descriptors, DescriptorArray::kEnumCacheOffset);
609  Node* object_enum_keys =
610  LoadObjectField(object_enum_cache, EnumCache::kKeysOffset);
611 
612  // Allocate a JSArray and copy the elements from the {object_enum_keys}.
613  Node* array = nullptr;
614  Node* elements = nullptr;
615  Node* native_context = LoadNativeContext(context);
616  TNode<Map> array_map =
617  LoadJSArrayElementsMap(PACKED_ELEMENTS, native_context);
618  TNode<Smi> array_length = SmiTag(object_enum_length);
619  std::tie(array, elements) = AllocateUninitializedJSArrayWithElements(
620  PACKED_ELEMENTS, array_map, array_length, nullptr, object_enum_length,
621  INTPTR_PARAMETERS);
622  CopyFixedArrayElements(PACKED_ELEMENTS, object_enum_keys, elements,
623  object_enum_length, SKIP_WRITE_BARRIER);
624  Return(array);
625  }
626 
627  BIND(&if_empty);
628  {
629  // The {object} doesn't have any enumerable keys.
630  var_length.Bind(SmiConstant(0));
631  var_elements.Bind(EmptyFixedArrayConstant());
632  Goto(&if_join);
633  }
634 
635  BIND(&if_slow);
636  {
637  // Let the runtime compute the elements.
638  Node* elements = CallRuntime(Runtime::kObjectKeys, context, object);
639  var_length.Bind(LoadObjectField(elements, FixedArray::kLengthOffset));
640  var_elements.Bind(elements);
641  Goto(&if_join);
642  }
643 
644  BIND(&if_join);
645  {
646  // Wrap the elements into a proper JSArray and return that.
647  Node* native_context = LoadNativeContext(context);
648  TNode<Map> array_map =
649  LoadJSArrayElementsMap(PACKED_ELEMENTS, native_context);
650  TNode<JSArray> array = AllocateUninitializedJSArrayWithoutElements(
651  array_map, CAST(var_length.value()), nullptr);
652  StoreObjectFieldNoWriteBarrier(array, JSArray::kElementsOffset,
653  var_elements.value());
654  Return(array);
655  }
656 }
657 
658 // ES #sec-object.getOwnPropertyNames
659 TF_BUILTIN(ObjectGetOwnPropertyNames, ObjectBuiltinsAssembler) {
660  Node* object = Parameter(Descriptor::kObject);
661  Node* context = Parameter(Descriptor::kContext);
662 
663  VARIABLE(var_length, MachineRepresentation::kTagged);
664  VARIABLE(var_elements, MachineRepresentation::kTagged);
665  Label if_empty(this, Label::kDeferred), if_empty_elements(this),
666  if_fast(this), try_fast(this, Label::kDeferred),
667  if_slow(this, Label::kDeferred), if_join(this);
668 
669  // Check if the {object} has a usable enum cache.
670  GotoIf(TaggedIsSmi(object), &if_slow);
671  Node* object_map = LoadMap(object);
672  Node* object_bit_field3 = LoadMapBitField3(object_map);
673  Node* object_enum_length =
674  DecodeWordFromWord32<Map::EnumLengthBits>(object_bit_field3);
675  GotoIf(
676  WordEqual(object_enum_length, IntPtrConstant(kInvalidEnumCacheSentinel)),
677  &try_fast);
678 
679  // Ensure that the {object} doesn't have any elements.
680  CSA_ASSERT(this, IsJSObjectMap(object_map));
681  Node* object_elements = LoadElements(object);
682  GotoIf(IsEmptyFixedArray(object_elements), &if_empty_elements);
683  Branch(IsEmptySlowElementDictionary(object_elements), &if_empty_elements,
684  &if_slow);
685 
686  // Check whether all own properties are enumerable.
687  BIND(&if_empty_elements);
688  Node* number_descriptors =
689  DecodeWordFromWord32<Map::NumberOfOwnDescriptorsBits>(object_bit_field3);
690  GotoIfNot(WordEqual(object_enum_length, number_descriptors), &if_slow);
691 
692  // Check whether there are enumerable properties.
693  Branch(WordEqual(object_enum_length, IntPtrConstant(0)), &if_empty, &if_fast);
694 
695  BIND(&if_fast);
696  {
697  // The {object} has a usable enum cache and all own properties are
698  // enumerable, use that.
699  Node* object_descriptors = LoadMapDescriptors(object_map);
700  Node* object_enum_cache =
701  LoadObjectField(object_descriptors, DescriptorArray::kEnumCacheOffset);
702  Node* object_enum_keys =
703  LoadObjectField(object_enum_cache, EnumCache::kKeysOffset);
704 
705  // Allocate a JSArray and copy the elements from the {object_enum_keys}.
706  Node* array = nullptr;
707  Node* elements = nullptr;
708  Node* native_context = LoadNativeContext(context);
709  TNode<Map> array_map =
710  LoadJSArrayElementsMap(PACKED_ELEMENTS, native_context);
711  TNode<Smi> array_length = SmiTag(object_enum_length);
712  std::tie(array, elements) = AllocateUninitializedJSArrayWithElements(
713  PACKED_ELEMENTS, array_map, array_length, nullptr, object_enum_length,
714  INTPTR_PARAMETERS);
715  CopyFixedArrayElements(PACKED_ELEMENTS, object_enum_keys, elements,
716  object_enum_length, SKIP_WRITE_BARRIER);
717  Return(array);
718  }
719 
720  BIND(&try_fast);
721  {
722  // Let the runtime compute the elements and try initializing enum cache.
723  Node* elements = CallRuntime(Runtime::kObjectGetOwnPropertyNamesTryFast,
724  context, object);
725  var_length.Bind(LoadObjectField(elements, FixedArray::kLengthOffset));
726  var_elements.Bind(elements);
727  Goto(&if_join);
728  }
729 
730  BIND(&if_empty);
731  {
732  // The {object} doesn't have any enumerable keys.
733  var_length.Bind(SmiConstant(0));
734  var_elements.Bind(EmptyFixedArrayConstant());
735  Goto(&if_join);
736  }
737 
738  BIND(&if_slow);
739  {
740  // Let the runtime compute the elements.
741  Node* elements =
742  CallRuntime(Runtime::kObjectGetOwnPropertyNames, context, object);
743  var_length.Bind(LoadObjectField(elements, FixedArray::kLengthOffset));
744  var_elements.Bind(elements);
745  Goto(&if_join);
746  }
747 
748  BIND(&if_join);
749  {
750  // Wrap the elements into a proper JSArray and return that.
751  Node* native_context = LoadNativeContext(context);
752  TNode<Map> array_map =
753  LoadJSArrayElementsMap(PACKED_ELEMENTS, native_context);
754  TNode<JSArray> array = AllocateUninitializedJSArrayWithoutElements(
755  array_map, CAST(var_length.value()), nullptr);
756  StoreObjectFieldNoWriteBarrier(array, JSArray::kElementsOffset,
757  var_elements.value());
758  Return(array);
759  }
760 }
761 
762 TF_BUILTIN(ObjectValues, ObjectEntriesValuesBuiltinsAssembler) {
763  TNode<JSObject> object =
764  TNode<JSObject>::UncheckedCast(Parameter(Descriptor::kObject));
765  TNode<Context> context =
766  TNode<Context>::UncheckedCast(Parameter(Descriptor::kContext));
767  GetOwnValuesOrEntries(context, object, CollectType::kValues);
768 }
769 
770 TF_BUILTIN(ObjectEntries, ObjectEntriesValuesBuiltinsAssembler) {
771  TNode<JSObject> object =
772  TNode<JSObject>::UncheckedCast(Parameter(Descriptor::kObject));
773  TNode<Context> context =
774  TNode<Context>::UncheckedCast(Parameter(Descriptor::kContext));
775  GetOwnValuesOrEntries(context, object, CollectType::kEntries);
776 }
777 
778 // ES #sec-object.prototype.isprototypeof
779 TF_BUILTIN(ObjectPrototypeIsPrototypeOf, ObjectBuiltinsAssembler) {
780  Node* receiver = Parameter(Descriptor::kReceiver);
781  Node* value = Parameter(Descriptor::kValue);
782  Node* context = Parameter(Descriptor::kContext);
783  Label if_receiverisnullorundefined(this, Label::kDeferred),
784  if_valueisnotreceiver(this, Label::kDeferred);
785 
786  // We only check whether {value} is a Smi here, so that the
787  // prototype chain walk below can safely access the {value}s
788  // map. We don't rule out Primitive {value}s, since all of
789  // them have null as their prototype, so the chain walk below
790  // immediately aborts and returns false anyways.
791  GotoIf(TaggedIsSmi(value), &if_valueisnotreceiver);
792 
793  // Check if {receiver} is either null or undefined and in that case,
794  // invoke the ToObject builtin, which raises the appropriate error.
795  // Otherwise we don't need to invoke ToObject, since {receiver} is
796  // either already a JSReceiver, in which case ToObject is a no-op,
797  // or it's a Primitive and ToObject would allocate a fresh JSValue
798  // wrapper, which wouldn't be identical to any existing JSReceiver
799  // found in the prototype chain of {value}, hence it will return
800  // false no matter if we search for the Primitive {receiver} or
801  // a newly allocated JSValue wrapper for {receiver}.
802  GotoIf(IsNull(receiver), &if_receiverisnullorundefined);
803  GotoIf(IsUndefined(receiver), &if_receiverisnullorundefined);
804 
805  // Loop through the prototype chain looking for the {receiver}.
806  Return(HasInPrototypeChain(context, value, receiver));
807 
808  BIND(&if_receiverisnullorundefined);
809  {
810  // If {value} is a primitive HeapObject, we need to return
811  // false instead of throwing an exception per order of the
812  // steps in the specification, so check that first here.
813  GotoIfNot(IsJSReceiver(value), &if_valueisnotreceiver);
814 
815  // Simulate the ToObject invocation on {receiver}.
816  ToObject(context, receiver);
817  Unreachable();
818  }
819 
820  BIND(&if_valueisnotreceiver);
821  Return(FalseConstant());
822 }
823 
824 // ES #sec-object.prototype.tostring
825 TF_BUILTIN(ObjectPrototypeToString, CodeStubAssembler) {
826  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
827  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
828  Return(CallBuiltin(Builtins::kObjectToString, context, receiver));
829 }
830 
831 TF_BUILTIN(ObjectToString, ObjectBuiltinsAssembler) {
832  Label checkstringtag(this), if_apiobject(this, Label::kDeferred),
833  if_arguments(this), if_array(this), if_boolean(this), if_date(this),
834  if_error(this), if_function(this), if_number(this, Label::kDeferred),
835  if_object(this), if_primitive(this), if_proxy(this, Label::kDeferred),
836  if_regexp(this), if_string(this), if_symbol(this, Label::kDeferred),
837  if_value(this), if_bigint(this, Label::kDeferred);
838 
839  Node* receiver = Parameter(Descriptor::kReceiver);
840  Node* context = Parameter(Descriptor::kContext);
841 
842  // This is arranged to check the likely cases first.
843  VARIABLE(var_default, MachineRepresentation::kTagged);
844  VARIABLE(var_holder, MachineRepresentation::kTagged, receiver);
845  GotoIf(TaggedIsSmi(receiver), &if_number);
846  Node* receiver_map = LoadMap(receiver);
847  Node* receiver_instance_type = LoadMapInstanceType(receiver_map);
848  GotoIf(IsPrimitiveInstanceType(receiver_instance_type), &if_primitive);
849  const struct {
850  InstanceType value;
851  Label* label;
852  } kJumpTable[] = {{JS_OBJECT_TYPE, &if_object},
853  {JS_ARRAY_TYPE, &if_array},
854  {JS_FUNCTION_TYPE, &if_function},
855  {JS_REGEXP_TYPE, &if_regexp},
856  {JS_ARGUMENTS_TYPE, &if_arguments},
857  {JS_DATE_TYPE, &if_date},
858  {JS_BOUND_FUNCTION_TYPE, &if_function},
859  {JS_API_OBJECT_TYPE, &if_apiobject},
860  {JS_SPECIAL_API_OBJECT_TYPE, &if_apiobject},
861  {JS_PROXY_TYPE, &if_proxy},
862  {JS_ERROR_TYPE, &if_error},
863  {JS_VALUE_TYPE, &if_value}};
864  size_t const kNumCases = arraysize(kJumpTable);
865  Label* case_labels[kNumCases];
866  int32_t case_values[kNumCases];
867  for (size_t i = 0; i < kNumCases; ++i) {
868  case_labels[i] = kJumpTable[i].label;
869  case_values[i] = kJumpTable[i].value;
870  }
871  Switch(receiver_instance_type, &if_object, case_values, case_labels,
872  arraysize(case_values));
873 
874  BIND(&if_apiobject);
875  {
876  // Lookup the @@toStringTag property on the {receiver}.
877  VARIABLE(var_tag, MachineRepresentation::kTagged,
878  GetProperty(context, receiver,
879  isolate()->factory()->to_string_tag_symbol()));
880  Label if_tagisnotstring(this), if_tagisstring(this);
881  GotoIf(TaggedIsSmi(var_tag.value()), &if_tagisnotstring);
882  Branch(IsString(var_tag.value()), &if_tagisstring, &if_tagisnotstring);
883  BIND(&if_tagisnotstring);
884  {
885  var_tag.Bind(CallRuntime(Runtime::kClassOf, context, receiver));
886  Goto(&if_tagisstring);
887  }
888  BIND(&if_tagisstring);
889  ReturnToStringFormat(context, var_tag.value());
890  }
891 
892  BIND(&if_arguments);
893  {
894  var_default.Bind(LoadRoot(RootIndex::karguments_to_string));
895  Goto(&checkstringtag);
896  }
897 
898  BIND(&if_array);
899  {
900  var_default.Bind(LoadRoot(RootIndex::karray_to_string));
901  Goto(&checkstringtag);
902  }
903 
904  BIND(&if_boolean);
905  {
906  Node* native_context = LoadNativeContext(context);
907  Node* boolean_constructor =
908  LoadContextElement(native_context, Context::BOOLEAN_FUNCTION_INDEX);
909  Node* boolean_initial_map = LoadObjectField(
910  boolean_constructor, JSFunction::kPrototypeOrInitialMapOffset);
911  Node* boolean_prototype =
912  LoadObjectField(boolean_initial_map, Map::kPrototypeOffset);
913  var_default.Bind(LoadRoot(RootIndex::kboolean_to_string));
914  var_holder.Bind(boolean_prototype);
915  Goto(&checkstringtag);
916  }
917 
918  BIND(&if_date);
919  {
920  var_default.Bind(LoadRoot(RootIndex::kdate_to_string));
921  Goto(&checkstringtag);
922  }
923 
924  BIND(&if_error);
925  {
926  var_default.Bind(LoadRoot(RootIndex::kerror_to_string));
927  Goto(&checkstringtag);
928  }
929 
930  BIND(&if_function);
931  {
932  var_default.Bind(LoadRoot(RootIndex::kfunction_to_string));
933  Goto(&checkstringtag);
934  }
935 
936  BIND(&if_number);
937  {
938  Node* native_context = LoadNativeContext(context);
939  Node* number_constructor =
940  LoadContextElement(native_context, Context::NUMBER_FUNCTION_INDEX);
941  Node* number_initial_map = LoadObjectField(
942  number_constructor, JSFunction::kPrototypeOrInitialMapOffset);
943  Node* number_prototype =
944  LoadObjectField(number_initial_map, Map::kPrototypeOffset);
945  var_default.Bind(LoadRoot(RootIndex::knumber_to_string));
946  var_holder.Bind(number_prototype);
947  Goto(&checkstringtag);
948  }
949 
950  BIND(&if_object);
951  {
952  CSA_ASSERT(this, IsJSReceiver(receiver));
953  var_default.Bind(LoadRoot(RootIndex::kobject_to_string));
954  Goto(&checkstringtag);
955  }
956 
957  BIND(&if_primitive);
958  {
959  Label return_undefined(this);
960 
961  GotoIf(IsStringInstanceType(receiver_instance_type), &if_string);
962  GotoIf(IsBigIntInstanceType(receiver_instance_type), &if_bigint);
963  GotoIf(IsBooleanMap(receiver_map), &if_boolean);
964  GotoIf(IsHeapNumberMap(receiver_map), &if_number);
965  GotoIf(IsSymbolMap(receiver_map), &if_symbol);
966  GotoIf(IsUndefined(receiver), &return_undefined);
967  CSA_ASSERT(this, IsNull(receiver));
968  Return(LoadRoot(RootIndex::knull_to_string));
969 
970  BIND(&return_undefined);
971  Return(LoadRoot(RootIndex::kundefined_to_string));
972  }
973 
974  BIND(&if_proxy);
975  {
976  // If {receiver} is a proxy for a JSArray, we default to "[object Array]",
977  // otherwise we default to "[object Object]" or "[object Function]" here,
978  // depending on whether the {receiver} is callable. The order matters here,
979  // i.e. we need to execute the %ArrayIsArray check before the [[Get]] below,
980  // as the exception is observable.
981  Node* receiver_is_array =
982  CallRuntime(Runtime::kArrayIsArray, context, receiver);
983  TNode<String> builtin_tag = Select<String>(
984  IsTrue(receiver_is_array),
985  [=] { return CAST(LoadRoot(RootIndex::kArray_string)); },
986  [=] {
987  return Select<String>(
988  IsCallableMap(receiver_map),
989  [=] { return CAST(LoadRoot(RootIndex::kFunction_string)); },
990  [=] { return CAST(LoadRoot(RootIndex::kObject_string)); });
991  });
992 
993  // Lookup the @@toStringTag property on the {receiver}.
994  VARIABLE(var_tag, MachineRepresentation::kTagged,
995  GetProperty(context, receiver,
996  isolate()->factory()->to_string_tag_symbol()));
997  Label if_tagisnotstring(this), if_tagisstring(this);
998  GotoIf(TaggedIsSmi(var_tag.value()), &if_tagisnotstring);
999  Branch(IsString(var_tag.value()), &if_tagisstring, &if_tagisnotstring);
1000  BIND(&if_tagisnotstring);
1001  {
1002  var_tag.Bind(builtin_tag);
1003  Goto(&if_tagisstring);
1004  }
1005  BIND(&if_tagisstring);
1006  ReturnToStringFormat(context, var_tag.value());
1007  }
1008 
1009  BIND(&if_regexp);
1010  {
1011  var_default.Bind(LoadRoot(RootIndex::kregexp_to_string));
1012  Goto(&checkstringtag);
1013  }
1014 
1015  BIND(&if_string);
1016  {
1017  Node* native_context = LoadNativeContext(context);
1018  Node* string_constructor =
1019  LoadContextElement(native_context, Context::STRING_FUNCTION_INDEX);
1020  Node* string_initial_map = LoadObjectField(
1021  string_constructor, JSFunction::kPrototypeOrInitialMapOffset);
1022  Node* string_prototype =
1023  LoadObjectField(string_initial_map, Map::kPrototypeOffset);
1024  var_default.Bind(LoadRoot(RootIndex::kstring_to_string));
1025  var_holder.Bind(string_prototype);
1026  Goto(&checkstringtag);
1027  }
1028 
1029  BIND(&if_symbol);
1030  {
1031  Node* native_context = LoadNativeContext(context);
1032  Node* symbol_constructor =
1033  LoadContextElement(native_context, Context::SYMBOL_FUNCTION_INDEX);
1034  Node* symbol_initial_map = LoadObjectField(
1035  symbol_constructor, JSFunction::kPrototypeOrInitialMapOffset);
1036  Node* symbol_prototype =
1037  LoadObjectField(symbol_initial_map, Map::kPrototypeOffset);
1038  var_default.Bind(LoadRoot(RootIndex::kobject_to_string));
1039  var_holder.Bind(symbol_prototype);
1040  Goto(&checkstringtag);
1041  }
1042 
1043  BIND(&if_bigint);
1044  {
1045  Node* native_context = LoadNativeContext(context);
1046  Node* bigint_constructor =
1047  LoadContextElement(native_context, Context::BIGINT_FUNCTION_INDEX);
1048  Node* bigint_initial_map = LoadObjectField(
1049  bigint_constructor, JSFunction::kPrototypeOrInitialMapOffset);
1050  Node* bigint_prototype =
1051  LoadObjectField(bigint_initial_map, Map::kPrototypeOffset);
1052  var_default.Bind(LoadRoot(RootIndex::kobject_to_string));
1053  var_holder.Bind(bigint_prototype);
1054  Goto(&checkstringtag);
1055  }
1056 
1057  BIND(&if_value);
1058  {
1059  Node* receiver_value = LoadJSValueValue(receiver);
1060  GotoIf(TaggedIsSmi(receiver_value), &if_number);
1061  Node* receiver_value_map = LoadMap(receiver_value);
1062  GotoIf(IsHeapNumberMap(receiver_value_map), &if_number);
1063  GotoIf(IsBooleanMap(receiver_value_map), &if_boolean);
1064  GotoIf(IsSymbolMap(receiver_value_map), &if_symbol);
1065  Node* receiver_value_instance_type =
1066  LoadMapInstanceType(receiver_value_map);
1067  GotoIf(IsBigIntInstanceType(receiver_value_instance_type), &if_bigint);
1068  CSA_ASSERT(this, IsStringInstanceType(receiver_value_instance_type));
1069  Goto(&if_string);
1070  }
1071 
1072  BIND(&checkstringtag);
1073  {
1074  // Check if all relevant maps (including the prototype maps) don't
1075  // have any interesting symbols (i.e. that none of them have the
1076  // @@toStringTag property).
1077  Label loop(this, &var_holder), return_default(this),
1078  return_generic(this, Label::kDeferred);
1079  Goto(&loop);
1080  BIND(&loop);
1081  {
1082  Node* holder = var_holder.value();
1083  GotoIf(IsNull(holder), &return_default);
1084  Node* holder_map = LoadMap(holder);
1085  Node* holder_bit_field3 = LoadMapBitField3(holder_map);
1086  GotoIf(IsSetWord32<Map::MayHaveInterestingSymbolsBit>(holder_bit_field3),
1087  &return_generic);
1088  var_holder.Bind(LoadMapPrototype(holder_map));
1089  Goto(&loop);
1090  }
1091 
1092  BIND(&return_generic);
1093  {
1094  Node* tag = GetProperty(context, ToObject(context, receiver),
1095  LoadRoot(RootIndex::kto_string_tag_symbol));
1096  GotoIf(TaggedIsSmi(tag), &return_default);
1097  GotoIfNot(IsString(tag), &return_default);
1098  ReturnToStringFormat(context, tag);
1099  }
1100 
1101  BIND(&return_default);
1102  Return(var_default.value());
1103  }
1104 }
1105 
1106 // ES6 #sec-object.prototype.valueof
1107 TF_BUILTIN(ObjectPrototypeValueOf, CodeStubAssembler) {
1108  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
1109  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
1110 
1111  Return(ToObject_Inline(context, receiver));
1112 }
1113 
1114 // ES #sec-object.create
1115 TF_BUILTIN(CreateObjectWithoutProperties, ObjectBuiltinsAssembler) {
1116  Node* const prototype = Parameter(Descriptor::kPrototypeArg);
1117  Node* const context = Parameter(Descriptor::kContext);
1118  Node* const native_context = LoadNativeContext(context);
1119  Label call_runtime(this, Label::kDeferred), prototype_null(this),
1120  prototype_jsreceiver(this);
1121  {
1122  Comment("Argument check: prototype");
1123  GotoIf(IsNull(prototype), &prototype_null);
1124  BranchIfJSReceiver(prototype, &prototype_jsreceiver, &call_runtime);
1125  }
1126 
1127  VARIABLE(map, MachineRepresentation::kTagged);
1128  VARIABLE(properties, MachineRepresentation::kTagged);
1129  Label instantiate_map(this);
1130 
1131  BIND(&prototype_null);
1132  {
1133  Comment("Prototype is null");
1134  map.Bind(LoadContextElement(native_context,
1135  Context::SLOW_OBJECT_WITH_NULL_PROTOTYPE_MAP));
1136  properties.Bind(AllocateNameDictionary(NameDictionary::kInitialCapacity));
1137  Goto(&instantiate_map);
1138  }
1139 
1140  BIND(&prototype_jsreceiver);
1141  {
1142  Comment("Prototype is JSReceiver");
1143  properties.Bind(EmptyFixedArrayConstant());
1144  Node* object_function =
1145  LoadContextElement(native_context, Context::OBJECT_FUNCTION_INDEX);
1146  Node* object_function_map = LoadObjectField(
1147  object_function, JSFunction::kPrototypeOrInitialMapOffset);
1148  map.Bind(object_function_map);
1149  GotoIf(WordEqual(prototype, LoadMapPrototype(map.value())),
1150  &instantiate_map);
1151  Comment("Try loading the prototype info");
1152  Node* prototype_info =
1153  LoadMapPrototypeInfo(LoadMap(prototype), &call_runtime);
1154  TNode<MaybeObject> maybe_map = LoadMaybeWeakObjectField(
1155  prototype_info, PrototypeInfo::kObjectCreateMapOffset);
1156  GotoIf(IsStrongReferenceTo(maybe_map, UndefinedConstant()), &call_runtime);
1157  map.Bind(GetHeapObjectAssumeWeak(maybe_map, &call_runtime));
1158  Goto(&instantiate_map);
1159  }
1160 
1161  BIND(&instantiate_map);
1162  {
1163  Comment("Instantiate map");
1164  Node* instance = AllocateJSObjectFromMap(map.value(), properties.value());
1165  Return(instance);
1166  }
1167 
1168  BIND(&call_runtime);
1169  {
1170  Comment("Call Runtime (prototype is not null/jsreceiver)");
1171  Node* result = CallRuntime(Runtime::kObjectCreate, context, prototype,
1172  UndefinedConstant());
1173  Return(result);
1174  }
1175 }
1176 
1177 // ES #sec-object.create
1178 TF_BUILTIN(ObjectCreate, ObjectBuiltinsAssembler) {
1179  int const kPrototypeArg = 0;
1180  int const kPropertiesArg = 1;
1181 
1182  Node* argc =
1183  ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
1184  CodeStubArguments args(this, argc);
1185 
1186  Node* prototype = args.GetOptionalArgumentValue(kPrototypeArg);
1187  Node* properties = args.GetOptionalArgumentValue(kPropertiesArg);
1188  Node* context = Parameter(Descriptor::kContext);
1189 
1190  Label call_runtime(this, Label::kDeferred), prototype_valid(this),
1191  no_properties(this);
1192  {
1193  Comment("Argument 1 check: prototype");
1194  GotoIf(IsNull(prototype), &prototype_valid);
1195  BranchIfJSReceiver(prototype, &prototype_valid, &call_runtime);
1196  }
1197 
1198  BIND(&prototype_valid);
1199  {
1200  Comment("Argument 2 check: properties");
1201  // Check that we have a simple object
1202  GotoIf(TaggedIsSmi(properties), &call_runtime);
1203  // Undefined implies no properties.
1204  GotoIf(IsUndefined(properties), &no_properties);
1205  Node* properties_map = LoadMap(properties);
1206  GotoIf(IsSpecialReceiverMap(properties_map), &call_runtime);
1207  // Stay on the fast path only if there are no elements.
1208  GotoIfNot(WordEqual(LoadElements(properties),
1209  LoadRoot(RootIndex::kEmptyFixedArray)),
1210  &call_runtime);
1211  // Handle dictionary objects or fast objects with properties in runtime.
1212  Node* bit_field3 = LoadMapBitField3(properties_map);
1213  GotoIf(IsSetWord32<Map::IsDictionaryMapBit>(bit_field3), &call_runtime);
1214  Branch(IsSetWord32<Map::NumberOfOwnDescriptorsBits>(bit_field3),
1215  &call_runtime, &no_properties);
1216  }
1217 
1218  // Create a new object with the given prototype.
1219  BIND(&no_properties);
1220  {
1221  VARIABLE(map, MachineRepresentation::kTagged);
1222  VARIABLE(properties, MachineRepresentation::kTagged);
1223  Label non_null_proto(this), instantiate_map(this), good(this);
1224 
1225  Branch(IsNull(prototype), &good, &non_null_proto);
1226 
1227  BIND(&good);
1228  {
1229  map.Bind(LoadContextElement(
1230  context, Context::SLOW_OBJECT_WITH_NULL_PROTOTYPE_MAP));
1231  properties.Bind(AllocateNameDictionary(NameDictionary::kInitialCapacity));
1232  Goto(&instantiate_map);
1233  }
1234 
1235  BIND(&non_null_proto);
1236  {
1237  properties.Bind(EmptyFixedArrayConstant());
1238  Node* object_function =
1239  LoadContextElement(context, Context::OBJECT_FUNCTION_INDEX);
1240  Node* object_function_map = LoadObjectField(
1241  object_function, JSFunction::kPrototypeOrInitialMapOffset);
1242  map.Bind(object_function_map);
1243  GotoIf(WordEqual(prototype, LoadMapPrototype(map.value())),
1244  &instantiate_map);
1245  // Try loading the prototype info.
1246  Node* prototype_info =
1247  LoadMapPrototypeInfo(LoadMap(prototype), &call_runtime);
1248  Comment("Load ObjectCreateMap from PrototypeInfo");
1249  TNode<MaybeObject> maybe_map = LoadMaybeWeakObjectField(
1250  prototype_info, PrototypeInfo::kObjectCreateMapOffset);
1251  GotoIf(IsStrongReferenceTo(maybe_map, UndefinedConstant()),
1252  &call_runtime);
1253  map.Bind(GetHeapObjectAssumeWeak(maybe_map, &call_runtime));
1254  Goto(&instantiate_map);
1255  }
1256 
1257  BIND(&instantiate_map);
1258  {
1259  Node* instance = AllocateJSObjectFromMap(map.value(), properties.value());
1260  args.PopAndReturn(instance);
1261  }
1262  }
1263 
1264  BIND(&call_runtime);
1265  {
1266  Node* result =
1267  CallRuntime(Runtime::kObjectCreate, context, prototype, properties);
1268  args.PopAndReturn(result);
1269  }
1270 }
1271 
1272 // ES #sec-object.is
1273 TF_BUILTIN(ObjectIs, ObjectBuiltinsAssembler) {
1274  Node* const left = Parameter(Descriptor::kLeft);
1275  Node* const right = Parameter(Descriptor::kRight);
1276 
1277  Label return_true(this), return_false(this);
1278  BranchIfSameValue(left, right, &return_true, &return_false);
1279 
1280  BIND(&return_true);
1281  Return(TrueConstant());
1282 
1283  BIND(&return_false);
1284  Return(FalseConstant());
1285 }
1286 
1287 TF_BUILTIN(CreateIterResultObject, ObjectBuiltinsAssembler) {
1288  Node* const value = Parameter(Descriptor::kValue);
1289  Node* const done = Parameter(Descriptor::kDone);
1290  Node* const context = Parameter(Descriptor::kContext);
1291 
1292  Node* const native_context = LoadNativeContext(context);
1293  Node* const map =
1294  LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX);
1295 
1296  Node* const result = AllocateJSObjectFromMap(map);
1297 
1298  StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kValueOffset, value);
1299  StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kDoneOffset, done);
1300 
1301  Return(result);
1302 }
1303 
1304 TF_BUILTIN(HasProperty, ObjectBuiltinsAssembler) {
1305  Node* key = Parameter(Descriptor::kKey);
1306  Node* object = Parameter(Descriptor::kObject);
1307  Node* context = Parameter(Descriptor::kContext);
1308 
1309  Return(HasProperty(context, object, key, kHasProperty));
1310 }
1311 
1312 TF_BUILTIN(InstanceOf, ObjectBuiltinsAssembler) {
1313  Node* object = Parameter(Descriptor::kLeft);
1314  Node* callable = Parameter(Descriptor::kRight);
1315  Node* context = Parameter(Descriptor::kContext);
1316 
1317  Return(InstanceOf(object, callable, context));
1318 }
1319 
1320 // ES6 section 7.3.19 OrdinaryHasInstance ( C, O )
1321 TF_BUILTIN(OrdinaryHasInstance, ObjectBuiltinsAssembler) {
1322  Node* constructor = Parameter(Descriptor::kLeft);
1323  Node* object = Parameter(Descriptor::kRight);
1324  Node* context = Parameter(Descriptor::kContext);
1325 
1326  Return(OrdinaryHasInstance(context, constructor, object));
1327 }
1328 
1329 TF_BUILTIN(GetSuperConstructor, ObjectBuiltinsAssembler) {
1330  Node* object = Parameter(Descriptor::kObject);
1331  Node* context = Parameter(Descriptor::kContext);
1332 
1333  Return(GetSuperConstructor(context, object));
1334 }
1335 
1336 TF_BUILTIN(CreateGeneratorObject, ObjectBuiltinsAssembler) {
1337  Node* closure = Parameter(Descriptor::kClosure);
1338  Node* receiver = Parameter(Descriptor::kReceiver);
1339  Node* context = Parameter(Descriptor::kContext);
1340 
1341  // Get the initial map from the function, jumping to the runtime if we don't
1342  // have one.
1343  Label done(this), runtime(this);
1344  GotoIfNot(IsFunctionWithPrototypeSlotMap(LoadMap(closure)), &runtime);
1345  Node* maybe_map =
1346  LoadObjectField(closure, JSFunction::kPrototypeOrInitialMapOffset);
1347  GotoIf(DoesntHaveInstanceType(maybe_map, MAP_TYPE), &runtime);
1348 
1349  Node* shared =
1350  LoadObjectField(closure, JSFunction::kSharedFunctionInfoOffset);
1351  Node* bytecode_array = LoadSharedFunctionInfoBytecodeArray(shared);
1352 
1353  Node* formal_parameter_count = ChangeInt32ToIntPtr(
1354  LoadObjectField(shared, SharedFunctionInfo::kFormalParameterCountOffset,
1355  MachineType::Uint16()));
1356  Node* frame_size = ChangeInt32ToIntPtr(LoadObjectField(
1357  bytecode_array, BytecodeArray::kFrameSizeOffset, MachineType::Int32()));
1358  Node* size = IntPtrAdd(WordSar(frame_size, IntPtrConstant(kPointerSizeLog2)),
1359  formal_parameter_count);
1360  Node* parameters_and_registers = AllocateFixedArray(HOLEY_ELEMENTS, size);
1361  FillFixedArrayWithValue(HOLEY_ELEMENTS, parameters_and_registers,
1362  IntPtrConstant(0), size, RootIndex::kUndefinedValue);
1363  // TODO(cbruni): support start_offset to avoid double initialization.
1364  Node* result = AllocateJSObjectFromMap(maybe_map, nullptr, nullptr, kNone,
1365  kWithSlackTracking);
1366  StoreObjectFieldNoWriteBarrier(result, JSGeneratorObject::kFunctionOffset,
1367  closure);
1368  StoreObjectFieldNoWriteBarrier(result, JSGeneratorObject::kContextOffset,
1369  context);
1370  StoreObjectFieldNoWriteBarrier(result, JSGeneratorObject::kReceiverOffset,
1371  receiver);
1372  StoreObjectFieldNoWriteBarrier(
1373  result, JSGeneratorObject::kParametersAndRegistersOffset,
1374  parameters_and_registers);
1375  Node* executing = SmiConstant(JSGeneratorObject::kGeneratorExecuting);
1376  StoreObjectFieldNoWriteBarrier(result, JSGeneratorObject::kContinuationOffset,
1377  executing);
1378  GotoIfNot(HasInstanceType(maybe_map, JS_ASYNC_GENERATOR_OBJECT_TYPE), &done);
1379  StoreObjectFieldNoWriteBarrier(
1380  result, JSAsyncGeneratorObject::kIsAwaitingOffset, SmiConstant(0));
1381  Goto(&done);
1382 
1383  BIND(&done);
1384  { Return(result); }
1385 
1386  BIND(&runtime);
1387  {
1388  Return(CallRuntime(Runtime::kCreateJSGeneratorObject, context, closure,
1389  receiver));
1390  }
1391 }
1392 
1393 // ES6 section 19.1.2.7 Object.getOwnPropertyDescriptor ( O, P )
1394 TF_BUILTIN(ObjectGetOwnPropertyDescriptor, ObjectBuiltinsAssembler) {
1395  Node* argc = Parameter(Descriptor::kJSActualArgumentsCount);
1396  Node* context = Parameter(Descriptor::kContext);
1397  CSA_ASSERT(this, IsUndefined(Parameter(Descriptor::kJSNewTarget)));
1398 
1399  CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
1400  Node* object = args.GetOptionalArgumentValue(0);
1401  Node* key = args.GetOptionalArgumentValue(1);
1402 
1403  // 1. Let obj be ? ToObject(O).
1404  object = ToObject_Inline(CAST(context), CAST(object));
1405 
1406  // 2. Let key be ? ToPropertyKey(P).
1407  key = CallBuiltin(Builtins::kToName, context, key);
1408 
1409  // 3. Let desc be ? obj.[[GetOwnProperty]](key).
1410  Label if_keyisindex(this), if_iskeyunique(this),
1411  call_runtime(this, Label::kDeferred),
1412  return_undefined(this, Label::kDeferred), if_notunique_name(this);
1413  Node* map = LoadMap(object);
1414  TNode<Int32T> instance_type = LoadMapInstanceType(map);
1415  GotoIf(IsSpecialReceiverInstanceType(instance_type), &call_runtime);
1416  {
1417  VARIABLE(var_index, MachineType::PointerRepresentation(),
1418  IntPtrConstant(0));
1419  VARIABLE(var_name, MachineRepresentation::kTagged);
1420 
1421  TryToName(key, &if_keyisindex, &var_index, &if_iskeyunique, &var_name,
1422  &call_runtime, &if_notunique_name);
1423 
1424  BIND(&if_notunique_name);
1425  {
1426  Label not_in_string_table(this);
1427  TryInternalizeString(key, &if_keyisindex, &var_index, &if_iskeyunique,
1428  &var_name, &not_in_string_table, &call_runtime);
1429 
1430  BIND(&not_in_string_table);
1431  {
1432  // If the string was not found in the string table, then no regular
1433  // object can have a property with that name, so return |undefined|.
1434  Goto(&return_undefined);
1435  }
1436  }
1437 
1438  BIND(&if_iskeyunique);
1439  {
1440  Label if_found_value(this), return_empty(this), if_not_found(this);
1441 
1442  VARIABLE(var_value, MachineRepresentation::kTagged);
1443  VARIABLE(var_details, MachineRepresentation::kWord32);
1444  VARIABLE(var_raw_value, MachineRepresentation::kTagged);
1445 
1446  TryGetOwnProperty(context, object, object, map, instance_type,
1447  var_name.value(), &if_found_value, &var_value,
1448  &var_details, &var_raw_value, &return_empty,
1449  &if_not_found, kReturnAccessorPair);
1450 
1451  BIND(&if_found_value);
1452  // 4. Return FromPropertyDescriptor(desc).
1453  Node* js_desc = FromPropertyDetails(context, var_value.value(),
1454  var_details.value(), &call_runtime);
1455  args.PopAndReturn(js_desc);
1456 
1457  BIND(&return_empty);
1458  var_value.Bind(UndefinedConstant());
1459  args.PopAndReturn(UndefinedConstant());
1460 
1461  BIND(&if_not_found);
1462  Goto(&call_runtime);
1463  }
1464  }
1465 
1466  BIND(&if_keyisindex);
1467  Goto(&call_runtime);
1468 
1469  BIND(&call_runtime);
1470  {
1471  Node* desc =
1472  CallRuntime(Runtime::kGetOwnPropertyDescriptor, context, object, key);
1473 
1474  GotoIf(IsUndefined(desc), &return_undefined);
1475 
1476  CSA_ASSERT(this, IsFixedArray(desc));
1477 
1478  // 4. Return FromPropertyDescriptor(desc).
1479  Node* js_desc = FromPropertyDescriptor(context, desc);
1480  args.PopAndReturn(js_desc);
1481  }
1482  BIND(&return_undefined);
1483  args.PopAndReturn(UndefinedConstant());
1484 }
1485 
1486 void ObjectBuiltinsAssembler::AddToDictionaryIf(
1487  TNode<BoolT> condition, TNode<NameDictionary> name_dictionary,
1488  Handle<Name> name, TNode<Object> value, Label* bailout) {
1489  Label done(this);
1490  GotoIfNot(condition, &done);
1491 
1492  Add<NameDictionary>(name_dictionary, HeapConstant(name), value, bailout);
1493  Goto(&done);
1494 
1495  BIND(&done);
1496 }
1497 
1498 Node* ObjectBuiltinsAssembler::FromPropertyDescriptor(Node* context,
1499  Node* desc) {
1500  VARIABLE(js_descriptor, MachineRepresentation::kTagged);
1501 
1502  Node* flags = LoadAndUntagToWord32ObjectField(
1503  desc, PropertyDescriptorObject::kFlagsOffset);
1504 
1505  Node* has_flags =
1506  Word32And(flags, Int32Constant(PropertyDescriptorObject::kHasMask));
1507 
1508  Label if_accessor_desc(this), if_data_desc(this), if_generic_desc(this),
1509  return_desc(this);
1510  GotoIf(
1511  Word32Equal(has_flags,
1512  Int32Constant(
1513  PropertyDescriptorObject::kRegularAccessorPropertyBits)),
1514  &if_accessor_desc);
1515  GotoIf(Word32Equal(
1516  has_flags,
1517  Int32Constant(PropertyDescriptorObject::kRegularDataPropertyBits)),
1518  &if_data_desc);
1519  Goto(&if_generic_desc);
1520 
1521  BIND(&if_accessor_desc);
1522  {
1523  js_descriptor.Bind(ConstructAccessorDescriptor(
1524  context, LoadObjectField(desc, PropertyDescriptorObject::kGetOffset),
1525  LoadObjectField(desc, PropertyDescriptorObject::kSetOffset),
1526  IsSetWord32<PropertyDescriptorObject::IsEnumerableBit>(flags),
1527  IsSetWord32<PropertyDescriptorObject::IsConfigurableBit>(flags)));
1528  Goto(&return_desc);
1529  }
1530 
1531  BIND(&if_data_desc);
1532  {
1533  js_descriptor.Bind(ConstructDataDescriptor(
1534  context, LoadObjectField(desc, PropertyDescriptorObject::kValueOffset),
1535  IsSetWord32<PropertyDescriptorObject::IsWritableBit>(flags),
1536  IsSetWord32<PropertyDescriptorObject::IsEnumerableBit>(flags),
1537  IsSetWord32<PropertyDescriptorObject::IsConfigurableBit>(flags)));
1538  Goto(&return_desc);
1539  }
1540 
1541  BIND(&if_generic_desc);
1542  {
1543  Node* native_context = LoadNativeContext(context);
1544  Node* map = LoadContextElement(
1545  native_context, Context::SLOW_OBJECT_WITH_OBJECT_PROTOTYPE_MAP);
1546  // We want to preallocate the slots for value, writable, get, set,
1547  // enumerable and configurable - a total of 6
1548  TNode<NameDictionary> properties = AllocateNameDictionary(6);
1549  Node* js_desc = AllocateJSObjectFromMap(map, properties);
1550 
1551  Label bailout(this, Label::kDeferred);
1552 
1553  Factory* factory = isolate()->factory();
1554  TNode<Object> value =
1555  LoadObjectField(desc, PropertyDescriptorObject::kValueOffset);
1556  AddToDictionaryIf(IsNotTheHole(value), properties, factory->value_string(),
1557  value, &bailout);
1558  AddToDictionaryIf(
1559  IsSetWord32<PropertyDescriptorObject::HasWritableBit>(flags),
1560  properties, factory->writable_string(),
1561  SelectBooleanConstant(
1562  IsSetWord32<PropertyDescriptorObject::IsWritableBit>(flags)),
1563  &bailout);
1564 
1565  TNode<Object> get =
1566  LoadObjectField(desc, PropertyDescriptorObject::kGetOffset);
1567  AddToDictionaryIf(IsNotTheHole(get), properties, factory->get_string(), get,
1568  &bailout);
1569  TNode<Object> set =
1570  LoadObjectField(desc, PropertyDescriptorObject::kSetOffset);
1571  AddToDictionaryIf(IsNotTheHole(set), properties, factory->set_string(), set,
1572  &bailout);
1573 
1574  AddToDictionaryIf(
1575  IsSetWord32<PropertyDescriptorObject::HasEnumerableBit>(flags),
1576  properties, factory->enumerable_string(),
1577  SelectBooleanConstant(
1578  IsSetWord32<PropertyDescriptorObject::IsEnumerableBit>(flags)),
1579  &bailout);
1580  AddToDictionaryIf(
1581  IsSetWord32<PropertyDescriptorObject::HasConfigurableBit>(flags),
1582  properties, factory->configurable_string(),
1583  SelectBooleanConstant(
1584  IsSetWord32<PropertyDescriptorObject::IsConfigurableBit>(flags)),
1585  &bailout);
1586 
1587  js_descriptor.Bind(js_desc);
1588  Goto(&return_desc);
1589 
1590  BIND(&bailout);
1591  CSA_ASSERT(this, Int32Constant(0));
1592  Unreachable();
1593  }
1594 
1595  BIND(&return_desc);
1596  return js_descriptor.value();
1597 }
1598 
1599 Node* ObjectBuiltinsAssembler::FromPropertyDetails(Node* context,
1600  Node* raw_value,
1601  Node* details,
1602  Label* if_bailout) {
1603  VARIABLE(js_descriptor, MachineRepresentation::kTagged);
1604 
1605  Label if_accessor_desc(this), if_data_desc(this), return_desc(this);
1606  BranchIfAccessorPair(raw_value, &if_accessor_desc, &if_data_desc);
1607 
1608  BIND(&if_accessor_desc);
1609  {
1610  Node* getter = LoadObjectField(raw_value, AccessorPair::kGetterOffset);
1611  Node* setter = LoadObjectField(raw_value, AccessorPair::kSetterOffset);
1612  js_descriptor.Bind(ConstructAccessorDescriptor(
1613  context, GetAccessorOrUndefined(getter, if_bailout),
1614  GetAccessorOrUndefined(setter, if_bailout),
1615  IsNotSetWord32(details, PropertyDetails::kAttributesDontEnumMask),
1616  IsNotSetWord32(details, PropertyDetails::kAttributesDontDeleteMask)));
1617  Goto(&return_desc);
1618  }
1619 
1620  BIND(&if_data_desc);
1621  {
1622  js_descriptor.Bind(ConstructDataDescriptor(
1623  context, raw_value,
1624  IsNotSetWord32(details, PropertyDetails::kAttributesReadOnlyMask),
1625  IsNotSetWord32(details, PropertyDetails::kAttributesDontEnumMask),
1626  IsNotSetWord32(details, PropertyDetails::kAttributesDontDeleteMask)));
1627  Goto(&return_desc);
1628  }
1629 
1630  BIND(&return_desc);
1631  return js_descriptor.value();
1632 }
1633 
1634 Node* ObjectBuiltinsAssembler::GetAccessorOrUndefined(Node* accessor,
1635  Label* if_bailout) {
1636  Label bind_undefined(this, Label::kDeferred), return_result(this);
1637  VARIABLE(result, MachineRepresentation::kTagged);
1638 
1639  GotoIf(IsNull(accessor), &bind_undefined);
1640  result.Bind(accessor);
1641  Node* map = LoadMap(accessor);
1642  // TODO(ishell): probe template instantiations cache.
1643  GotoIf(IsFunctionTemplateInfoMap(map), if_bailout);
1644  Goto(&return_result);
1645 
1646  BIND(&bind_undefined);
1647  result.Bind(UndefinedConstant());
1648  Goto(&return_result);
1649 
1650  BIND(&return_result);
1651  return result.value();
1652 }
1653 } // namespace internal
1654 } // namespace v8
Definition: libplatform.h:13