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