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