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, ¬_in_string_table, &call_runtime);
462
463 BIND(¬_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, ¬_in_string_table, &call_runtime);
1440
1441 BIND(¬_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