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