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 : 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 : 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 : 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 : Node* map = LoadContextElement(
110 224 : 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 : Node* map = LoadContextElement(native_context,
134 224 : 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 224 : Word32Equal(kind, Int32Constant(FAST_STRING_WRAPPER_ELEMENTS)),
171 560 : 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 112 : 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 : Return(
247 56 : CallRuntime(Runtime::kObjectEntriesSkipFastPath, context, receiver));
248 : } else {
249 : DCHECK(collect_type == CollectType::kValues);
250 : Return(
251 56 : CallRuntime(Runtime::kObjectValuesSkipFastPath, context, receiver));
252 : }
253 112 : }
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 : IntPtrConstant(0), object_enum_length,
305 224 : 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 112 : Branch(IntPtrEqual(var_descriptor_number.value(), object_enum_length),
314 224 : &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 : 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 112 : Branch(IntPtrEqual(var_result_index.value(), object_enum_length),
376 224 : &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 112 : }
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 : Node* array = AllocateUninitializedJSArrayWithoutElements(
394 224 : array_map, SmiTag(size), nullptr);
395 112 : StoreObjectField(array, JSArray::kElementsOffset, result);
396 112 : return TNode<JSArray>::UncheckedCast(array);
397 : }
398 :
399 168 : TF_BUILTIN(ObjectPrototypeToLocaleString, CodeStubAssembler) {
400 : TNode<Context> context = CAST(Parameter(Descriptor::kContext));
401 : TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
402 :
403 : Label if_null_or_undefined(this, Label::kDeferred);
404 112 : GotoIf(IsNullOrUndefined(receiver), &if_null_or_undefined);
405 :
406 : TNode<Object> method =
407 112 : GetProperty(context, receiver, factory()->toString_string());
408 168 : Return(CallJS(CodeFactory::Call(isolate()), context, method, receiver));
409 :
410 56 : BIND(&if_null_or_undefined);
411 : ThrowTypeError(context, MessageTemplate::kCalledOnNullOrUndefined,
412 56 : "Object.prototype.toLocaleString");
413 56 : }
414 :
415 224 : TF_BUILTIN(ObjectPrototypeHasOwnProperty, ObjectBuiltinsAssembler) {
416 : Node* object = Parameter(Descriptor::kReceiver);
417 : Node* key = Parameter(Descriptor::kKey);
418 : Node* context = Parameter(Descriptor::kContext);
419 :
420 56 : Label call_runtime(this), return_true(this), return_false(this),
421 56 : to_primitive(this);
422 :
423 : // Smi receivers do not have own properties, just perform ToPrimitive on the
424 : // key.
425 56 : Label if_objectisnotsmi(this);
426 112 : Branch(TaggedIsSmi(object), &to_primitive, &if_objectisnotsmi);
427 56 : BIND(&if_objectisnotsmi);
428 :
429 112 : Node* map = LoadMap(object);
430 56 : TNode<Int32T> instance_type = LoadMapInstanceType(map);
431 :
432 : {
433 56 : VARIABLE(var_index, MachineType::PointerRepresentation());
434 112 : VARIABLE(var_unique, MachineRepresentation::kTagged);
435 :
436 56 : Label if_index(this), if_unique_name(this), if_notunique_name(this);
437 : TryToName(key, &if_index, &var_index, &if_unique_name, &var_unique,
438 56 : &call_runtime, &if_notunique_name);
439 :
440 56 : BIND(&if_unique_name);
441 : TryHasOwnProperty(object, map, instance_type, var_unique.value(),
442 112 : &return_true, &return_false, &call_runtime);
443 :
444 56 : BIND(&if_index);
445 : {
446 : // Handle negative keys in the runtime.
447 168 : GotoIf(IntPtrLessThan(var_index.value(), IntPtrConstant(0)),
448 112 : &call_runtime);
449 : TryLookupElement(object, map, instance_type, var_index.value(),
450 : &return_true, &return_false, &return_false,
451 112 : &call_runtime);
452 : }
453 :
454 56 : BIND(&if_notunique_name);
455 : {
456 : Label not_in_string_table(this);
457 : TryInternalizeString(key, &if_index, &var_index, &if_unique_name,
458 56 : &var_unique, ¬_in_string_table, &call_runtime);
459 :
460 56 : BIND(¬_in_string_table);
461 : {
462 : // If the string was not found in the string table, then no regular
463 : // object can have a property with that name, so return |false|.
464 : // "Special API objects" with interceptors must take the slow path.
465 : Branch(IsSpecialReceiverInstanceType(instance_type), &call_runtime,
466 112 : &return_false);
467 56 : }
468 56 : }
469 : }
470 56 : BIND(&to_primitive);
471 112 : GotoIf(IsNumber(key), &return_false);
472 112 : Branch(IsName(key), &return_false, &call_runtime);
473 :
474 56 : BIND(&return_true);
475 112 : Return(TrueConstant());
476 :
477 56 : BIND(&return_false);
478 112 : Return(FalseConstant());
479 :
480 56 : BIND(&call_runtime);
481 56 : Return(CallRuntime(Runtime::kObjectHasOwnProperty, context, object, key));
482 56 : }
483 :
484 : // ES #sec-object.assign
485 280 : TF_BUILTIN(ObjectAssign, ObjectBuiltinsAssembler) {
486 : TNode<IntPtrT> argc =
487 56 : ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
488 56 : CodeStubArguments args(this, argc);
489 :
490 : TNode<Context> context = CAST(Parameter(Descriptor::kContext));
491 56 : TNode<Object> target = args.GetOptionalArgumentValue(0);
492 :
493 : // 1. Let to be ? ToObject(target).
494 56 : TNode<JSReceiver> to = ToObject_Inline(context, target);
495 :
496 : Label done(this);
497 : // 2. If only one argument was passed, return to.
498 168 : GotoIf(UintPtrLessThanOrEqual(argc, IntPtrConstant(1)), &done);
499 :
500 : // 3. Let sources be the List of argument values starting with the
501 : // second argument.
502 : // 4. For each element nextSource of sources, in ascending index order,
503 : args.ForEach(
504 56 : [=](Node* next_source_) {
505 : TNode<Object> next_source = CAST(next_source_);
506 168 : Label slow(this), cont(this);
507 56 : ObjectAssignFast(context, to, next_source, &slow);
508 56 : Goto(&cont);
509 :
510 56 : BIND(&slow);
511 : {
512 56 : CallRuntime(Runtime::kSetDataProperties, context, to, next_source);
513 56 : Goto(&cont);
514 : }
515 56 : BIND(&cont);
516 56 : },
517 224 : IntPtrConstant(1));
518 56 : Goto(&done);
519 :
520 : // 5. Return to.
521 56 : BIND(&done);
522 56 : args.PopAndReturn(to);
523 56 : }
524 :
525 : // This function mimics what FastAssign() function does for C++ implementation.
526 56 : void ObjectBuiltinsAssembler::ObjectAssignFast(TNode<Context> context,
527 : TNode<JSReceiver> to,
528 : TNode<Object> from,
529 : Label* slow) {
530 56 : Label done(this);
531 :
532 : // Non-empty strings are the only non-JSReceivers that need to be handled
533 : // explicitly by Object.assign.
534 112 : GotoIf(TaggedIsSmi(from), &done);
535 56 : TNode<Map> from_map = LoadMap(CAST(from));
536 56 : TNode<Int32T> from_instance_type = LoadMapInstanceType(from_map);
537 : {
538 : Label cont(this);
539 112 : GotoIf(IsJSReceiverInstanceType(from_instance_type), &cont);
540 112 : GotoIfNot(IsStringInstanceType(from_instance_type), &done);
541 : {
542 : Branch(
543 168 : Word32Equal(LoadStringLengthAsWord32(CAST(from)), Int32Constant(0)),
544 112 : &done, slow);
545 : }
546 56 : BIND(&cont);
547 : }
548 :
549 : // If the target is deprecated, the object will be updated on first store. If
550 : // the source for that store equals the target, this will invalidate the
551 : // cached representation of the source. Handle this case in runtime.
552 56 : TNode<Map> to_map = LoadMap(to);
553 112 : GotoIf(IsDeprecatedMap(to_map), slow);
554 56 : TNode<BoolT> to_is_simple_receiver = IsSimpleObjectMap(to_map);
555 :
556 112 : GotoIfNot(IsJSObjectInstanceType(from_instance_type), slow);
557 112 : GotoIfNot(IsEmptyFixedArray(LoadElements(CAST(from))), slow);
558 :
559 : ForEachEnumerableOwnProperty(context, from_map, CAST(from),
560 56 : [=](TNode<Name> key, TNode<Object> value) {
561 : KeyedStoreGenericGenerator::SetProperty(
562 : state(), context, to,
563 : to_is_simple_receiver, key, value,
564 112 : LanguageMode::kStrict);
565 56 : },
566 168 : slow);
567 :
568 56 : Goto(&done);
569 56 : BIND(&done);
570 56 : }
571 :
572 : // ES #sec-object.keys
573 224 : TF_BUILTIN(ObjectKeys, ObjectBuiltinsAssembler) {
574 : Node* object = Parameter(Descriptor::kObject);
575 : Node* context = Parameter(Descriptor::kContext);
576 :
577 56 : VARIABLE(var_length, MachineRepresentation::kTagged);
578 112 : VARIABLE(var_elements, MachineRepresentation::kTagged);
579 56 : Label if_empty(this, Label::kDeferred), if_empty_elements(this),
580 56 : if_fast(this), if_slow(this, Label::kDeferred), if_join(this);
581 :
582 : // Check if the {object} has a usable enum cache.
583 112 : GotoIf(TaggedIsSmi(object), &if_slow);
584 112 : Node* object_map = LoadMap(object);
585 112 : Node* object_bit_field3 = LoadMapBitField3(object_map);
586 : Node* object_enum_length =
587 112 : DecodeWordFromWord32<Map::EnumLengthBits>(object_bit_field3);
588 : GotoIf(
589 112 : WordEqual(object_enum_length, IntPtrConstant(kInvalidEnumCacheSentinel)),
590 112 : &if_slow);
591 :
592 : // Ensure that the {object} doesn't have any elements.
593 : CSA_ASSERT(this, IsJSObjectMap(object_map));
594 : Node* object_elements = LoadElements(object);
595 112 : GotoIf(IsEmptyFixedArray(object_elements), &if_empty_elements);
596 56 : Branch(IsEmptySlowElementDictionary(object_elements), &if_empty_elements,
597 112 : &if_slow);
598 :
599 : // Check whether there are enumerable properties.
600 56 : BIND(&if_empty_elements);
601 168 : Branch(WordEqual(object_enum_length, IntPtrConstant(0)), &if_empty, &if_fast);
602 :
603 56 : BIND(&if_fast);
604 : {
605 : // The {object} has a usable enum cache, use that.
606 112 : Node* object_descriptors = LoadMapDescriptors(object_map);
607 : Node* object_enum_cache =
608 : LoadObjectField(object_descriptors, DescriptorArray::kEnumCacheOffset);
609 : Node* object_enum_keys =
610 : LoadObjectField(object_enum_cache, EnumCache::kKeysOffset);
611 :
612 : // Allocate a JSArray and copy the elements from the {object_enum_keys}.
613 56 : Node* array = nullptr;
614 56 : Node* elements = nullptr;
615 112 : Node* native_context = LoadNativeContext(context);
616 : TNode<Map> array_map =
617 56 : LoadJSArrayElementsMap(PACKED_ELEMENTS, native_context);
618 56 : TNode<Smi> array_length = SmiTag(object_enum_length);
619 112 : std::tie(array, elements) = AllocateUninitializedJSArrayWithElements(
620 : PACKED_ELEMENTS, array_map, array_length, nullptr, object_enum_length,
621 56 : INTPTR_PARAMETERS);
622 : CopyFixedArrayElements(PACKED_ELEMENTS, object_enum_keys, elements,
623 56 : object_enum_length, SKIP_WRITE_BARRIER);
624 56 : Return(array);
625 : }
626 :
627 56 : BIND(&if_empty);
628 : {
629 : // The {object} doesn't have any enumerable keys.
630 112 : var_length.Bind(SmiConstant(0));
631 112 : var_elements.Bind(EmptyFixedArrayConstant());
632 56 : Goto(&if_join);
633 : }
634 :
635 56 : BIND(&if_slow);
636 : {
637 : // Let the runtime compute the elements.
638 : Node* elements = CallRuntime(Runtime::kObjectKeys, context, object);
639 56 : var_length.Bind(LoadObjectField(elements, FixedArray::kLengthOffset));
640 56 : var_elements.Bind(elements);
641 56 : Goto(&if_join);
642 : }
643 :
644 56 : BIND(&if_join);
645 : {
646 : // Wrap the elements into a proper JSArray and return that.
647 112 : Node* native_context = LoadNativeContext(context);
648 : TNode<Map> array_map =
649 56 : LoadJSArrayElementsMap(PACKED_ELEMENTS, native_context);
650 : TNode<JSArray> array = AllocateUninitializedJSArrayWithoutElements(
651 56 : array_map, CAST(var_length.value()), nullptr);
652 : StoreObjectFieldNoWriteBarrier(array, JSArray::kElementsOffset,
653 56 : var_elements.value());
654 56 : Return(array);
655 56 : }
656 56 : }
657 :
658 : // ES #sec-object.getOwnPropertyNames
659 224 : TF_BUILTIN(ObjectGetOwnPropertyNames, ObjectBuiltinsAssembler) {
660 : Node* object = Parameter(Descriptor::kObject);
661 : Node* context = Parameter(Descriptor::kContext);
662 :
663 56 : VARIABLE(var_length, MachineRepresentation::kTagged);
664 112 : VARIABLE(var_elements, MachineRepresentation::kTagged);
665 56 : Label if_empty(this, Label::kDeferred), if_empty_elements(this),
666 56 : if_fast(this), try_fast(this, Label::kDeferred),
667 56 : if_slow(this, Label::kDeferred), if_join(this);
668 :
669 : // Check if the {object} has a usable enum cache.
670 112 : GotoIf(TaggedIsSmi(object), &if_slow);
671 112 : Node* object_map = LoadMap(object);
672 112 : Node* object_bit_field3 = LoadMapBitField3(object_map);
673 : Node* object_enum_length =
674 112 : DecodeWordFromWord32<Map::EnumLengthBits>(object_bit_field3);
675 : GotoIf(
676 112 : WordEqual(object_enum_length, IntPtrConstant(kInvalidEnumCacheSentinel)),
677 112 : &try_fast);
678 :
679 : // Ensure that the {object} doesn't have any elements.
680 : CSA_ASSERT(this, IsJSObjectMap(object_map));
681 : Node* object_elements = LoadElements(object);
682 112 : GotoIf(IsEmptyFixedArray(object_elements), &if_empty_elements);
683 56 : Branch(IsEmptySlowElementDictionary(object_elements), &if_empty_elements,
684 112 : &if_slow);
685 :
686 : // Check whether all own properties are enumerable.
687 56 : BIND(&if_empty_elements);
688 : Node* number_descriptors =
689 112 : DecodeWordFromWord32<Map::NumberOfOwnDescriptorsBits>(object_bit_field3);
690 112 : GotoIfNot(WordEqual(object_enum_length, number_descriptors), &if_slow);
691 :
692 : // Check whether there are enumerable properties.
693 168 : Branch(WordEqual(object_enum_length, IntPtrConstant(0)), &if_empty, &if_fast);
694 :
695 56 : BIND(&if_fast);
696 : {
697 : // The {object} has a usable enum cache and all own properties are
698 : // enumerable, use that.
699 112 : Node* object_descriptors = LoadMapDescriptors(object_map);
700 : Node* object_enum_cache =
701 : LoadObjectField(object_descriptors, DescriptorArray::kEnumCacheOffset);
702 : Node* object_enum_keys =
703 : LoadObjectField(object_enum_cache, EnumCache::kKeysOffset);
704 :
705 : // Allocate a JSArray and copy the elements from the {object_enum_keys}.
706 56 : Node* array = nullptr;
707 56 : Node* elements = nullptr;
708 112 : Node* native_context = LoadNativeContext(context);
709 : TNode<Map> array_map =
710 56 : LoadJSArrayElementsMap(PACKED_ELEMENTS, native_context);
711 56 : TNode<Smi> array_length = SmiTag(object_enum_length);
712 112 : std::tie(array, elements) = AllocateUninitializedJSArrayWithElements(
713 : PACKED_ELEMENTS, array_map, array_length, nullptr, object_enum_length,
714 56 : INTPTR_PARAMETERS);
715 : CopyFixedArrayElements(PACKED_ELEMENTS, object_enum_keys, elements,
716 56 : object_enum_length, SKIP_WRITE_BARRIER);
717 56 : Return(array);
718 : }
719 :
720 56 : BIND(&try_fast);
721 : {
722 : // Let the runtime compute the elements and try initializing enum cache.
723 : Node* elements = CallRuntime(Runtime::kObjectGetOwnPropertyNamesTryFast,
724 : context, object);
725 56 : var_length.Bind(LoadObjectField(elements, FixedArray::kLengthOffset));
726 56 : var_elements.Bind(elements);
727 56 : Goto(&if_join);
728 : }
729 :
730 56 : BIND(&if_empty);
731 : {
732 : // The {object} doesn't have any enumerable keys.
733 112 : var_length.Bind(SmiConstant(0));
734 112 : var_elements.Bind(EmptyFixedArrayConstant());
735 56 : Goto(&if_join);
736 : }
737 :
738 56 : BIND(&if_slow);
739 : {
740 : // Let the runtime compute the elements.
741 : Node* elements =
742 : CallRuntime(Runtime::kObjectGetOwnPropertyNames, context, object);
743 56 : var_length.Bind(LoadObjectField(elements, FixedArray::kLengthOffset));
744 56 : var_elements.Bind(elements);
745 56 : Goto(&if_join);
746 : }
747 :
748 56 : BIND(&if_join);
749 : {
750 : // Wrap the elements into a proper JSArray and return that.
751 112 : Node* native_context = LoadNativeContext(context);
752 : TNode<Map> array_map =
753 56 : LoadJSArrayElementsMap(PACKED_ELEMENTS, native_context);
754 : TNode<JSArray> array = AllocateUninitializedJSArrayWithoutElements(
755 56 : array_map, CAST(var_length.value()), nullptr);
756 : StoreObjectFieldNoWriteBarrier(array, JSArray::kElementsOffset,
757 56 : var_elements.value());
758 56 : Return(array);
759 56 : }
760 56 : }
761 :
762 224 : TF_BUILTIN(ObjectValues, ObjectEntriesValuesBuiltinsAssembler) {
763 : TNode<JSObject> object =
764 : TNode<JSObject>::UncheckedCast(Parameter(Descriptor::kObject));
765 : TNode<Context> context =
766 56 : TNode<Context>::UncheckedCast(Parameter(Descriptor::kContext));
767 56 : GetOwnValuesOrEntries(context, object, CollectType::kValues);
768 56 : }
769 :
770 224 : TF_BUILTIN(ObjectEntries, ObjectEntriesValuesBuiltinsAssembler) {
771 : TNode<JSObject> object =
772 : TNode<JSObject>::UncheckedCast(Parameter(Descriptor::kObject));
773 : TNode<Context> context =
774 56 : TNode<Context>::UncheckedCast(Parameter(Descriptor::kContext));
775 56 : GetOwnValuesOrEntries(context, object, CollectType::kEntries);
776 56 : }
777 :
778 : // ES #sec-object.prototype.isprototypeof
779 224 : TF_BUILTIN(ObjectPrototypeIsPrototypeOf, ObjectBuiltinsAssembler) {
780 : Node* receiver = Parameter(Descriptor::kReceiver);
781 : Node* value = Parameter(Descriptor::kValue);
782 : Node* context = Parameter(Descriptor::kContext);
783 : Label if_receiverisnullorundefined(this, Label::kDeferred),
784 56 : if_valueisnotreceiver(this, Label::kDeferred);
785 :
786 : // We only check whether {value} is a Smi here, so that the
787 : // prototype chain walk below can safely access the {value}s
788 : // map. We don't rule out Primitive {value}s, since all of
789 : // them have null as their prototype, so the chain walk below
790 : // immediately aborts and returns false anyways.
791 112 : GotoIf(TaggedIsSmi(value), &if_valueisnotreceiver);
792 :
793 : // Check if {receiver} is either null or undefined and in that case,
794 : // invoke the ToObject builtin, which raises the appropriate error.
795 : // Otherwise we don't need to invoke ToObject, since {receiver} is
796 : // either already a JSReceiver, in which case ToObject is a no-op,
797 : // or it's a Primitive and ToObject would allocate a fresh JSValue
798 : // wrapper, which wouldn't be identical to any existing JSReceiver
799 : // found in the prototype chain of {value}, hence it will return
800 : // false no matter if we search for the Primitive {receiver} or
801 : // a newly allocated JSValue wrapper for {receiver}.
802 112 : GotoIf(IsNull(receiver), &if_receiverisnullorundefined);
803 112 : GotoIf(IsUndefined(receiver), &if_receiverisnullorundefined);
804 :
805 : // Loop through the prototype chain looking for the {receiver}.
806 112 : Return(HasInPrototypeChain(context, value, receiver));
807 :
808 56 : BIND(&if_receiverisnullorundefined);
809 : {
810 : // If {value} is a primitive HeapObject, we need to return
811 : // false instead of throwing an exception per order of the
812 : // steps in the specification, so check that first here.
813 112 : GotoIfNot(IsJSReceiver(value), &if_valueisnotreceiver);
814 :
815 : // Simulate the ToObject invocation on {receiver}.
816 56 : ToObject(context, receiver);
817 56 : Unreachable();
818 : }
819 :
820 56 : BIND(&if_valueisnotreceiver);
821 168 : Return(FalseConstant());
822 56 : }
823 :
824 : // ES #sec-object.prototype.tostring
825 224 : TF_BUILTIN(ObjectPrototypeToString, CodeStubAssembler) {
826 56 : TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
827 : TNode<Context> context = CAST(Parameter(Descriptor::kContext));
828 112 : Return(CallBuiltin(Builtins::kObjectToString, context, receiver));
829 56 : }
830 :
831 280 : TF_BUILTIN(ObjectToString, ObjectBuiltinsAssembler) {
832 112 : Label checkstringtag(this), if_apiobject(this, Label::kDeferred),
833 56 : if_arguments(this), if_array(this), if_boolean(this), if_date(this),
834 56 : if_error(this), if_function(this), if_number(this, Label::kDeferred),
835 56 : if_object(this), if_primitive(this), if_proxy(this, Label::kDeferred),
836 56 : if_regexp(this), if_string(this), if_symbol(this, Label::kDeferred),
837 56 : if_value(this), if_bigint(this, Label::kDeferred);
838 :
839 : Node* receiver = Parameter(Descriptor::kReceiver);
840 : Node* context = Parameter(Descriptor::kContext);
841 :
842 : // This is arranged to check the likely cases first.
843 112 : VARIABLE(var_default, MachineRepresentation::kTagged);
844 112 : VARIABLE(var_holder, MachineRepresentation::kTagged, receiver);
845 112 : GotoIf(TaggedIsSmi(receiver), &if_number);
846 112 : Node* receiver_map = LoadMap(receiver);
847 112 : Node* receiver_instance_type = LoadMapInstanceType(receiver_map);
848 112 : GotoIf(IsPrimitiveInstanceType(receiver_instance_type), &if_primitive);
849 : const struct {
850 : InstanceType value;
851 : Label* label;
852 : } kJumpTable[] = {{JS_OBJECT_TYPE, &if_object},
853 : {JS_ARRAY_TYPE, &if_array},
854 : {JS_FUNCTION_TYPE, &if_function},
855 : {JS_REGEXP_TYPE, &if_regexp},
856 : {JS_ARGUMENTS_TYPE, &if_arguments},
857 : {JS_DATE_TYPE, &if_date},
858 : {JS_BOUND_FUNCTION_TYPE, &if_function},
859 : {JS_API_OBJECT_TYPE, &if_apiobject},
860 : {JS_SPECIAL_API_OBJECT_TYPE, &if_apiobject},
861 : {JS_PROXY_TYPE, &if_proxy},
862 : {JS_ERROR_TYPE, &if_error},
863 56 : {JS_VALUE_TYPE, &if_value}};
864 : size_t const kNumCases = arraysize(kJumpTable);
865 : Label* case_labels[kNumCases];
866 : int32_t case_values[kNumCases];
867 728 : for (size_t i = 0; i < kNumCases; ++i) {
868 672 : case_labels[i] = kJumpTable[i].label;
869 672 : case_values[i] = kJumpTable[i].value;
870 : }
871 : Switch(receiver_instance_type, &if_object, case_values, case_labels,
872 56 : arraysize(case_values));
873 :
874 56 : BIND(&if_apiobject);
875 : {
876 : // Lookup the @@toStringTag property on the {receiver}.
877 168 : VARIABLE(var_tag, MachineRepresentation::kTagged,
878 : GetProperty(context, receiver,
879 : isolate()->factory()->to_string_tag_symbol()));
880 56 : Label if_tagisnotstring(this), if_tagisstring(this);
881 168 : GotoIf(TaggedIsSmi(var_tag.value()), &if_tagisnotstring);
882 168 : Branch(IsString(var_tag.value()), &if_tagisstring, &if_tagisnotstring);
883 56 : BIND(&if_tagisnotstring);
884 : {
885 56 : var_tag.Bind(CallRuntime(Runtime::kClassOf, context, receiver));
886 56 : Goto(&if_tagisstring);
887 : }
888 56 : BIND(&if_tagisstring);
889 112 : ReturnToStringFormat(context, var_tag.value());
890 : }
891 :
892 56 : BIND(&if_arguments);
893 : {
894 112 : var_default.Bind(LoadRoot(RootIndex::karguments_to_string));
895 56 : Goto(&checkstringtag);
896 : }
897 :
898 56 : BIND(&if_array);
899 : {
900 112 : var_default.Bind(LoadRoot(RootIndex::karray_to_string));
901 56 : Goto(&checkstringtag);
902 : }
903 :
904 56 : BIND(&if_boolean);
905 : {
906 112 : Node* native_context = LoadNativeContext(context);
907 : Node* boolean_constructor =
908 112 : LoadContextElement(native_context, Context::BOOLEAN_FUNCTION_INDEX);
909 : Node* boolean_initial_map = LoadObjectField(
910 : boolean_constructor, JSFunction::kPrototypeOrInitialMapOffset);
911 : Node* boolean_prototype =
912 : LoadObjectField(boolean_initial_map, Map::kPrototypeOffset);
913 112 : var_default.Bind(LoadRoot(RootIndex::kboolean_to_string));
914 56 : var_holder.Bind(boolean_prototype);
915 56 : Goto(&checkstringtag);
916 : }
917 :
918 56 : BIND(&if_date);
919 : {
920 112 : var_default.Bind(LoadRoot(RootIndex::kdate_to_string));
921 56 : Goto(&checkstringtag);
922 : }
923 :
924 56 : BIND(&if_error);
925 : {
926 112 : var_default.Bind(LoadRoot(RootIndex::kerror_to_string));
927 56 : Goto(&checkstringtag);
928 : }
929 :
930 56 : BIND(&if_function);
931 : {
932 112 : var_default.Bind(LoadRoot(RootIndex::kfunction_to_string));
933 56 : Goto(&checkstringtag);
934 : }
935 :
936 56 : BIND(&if_number);
937 : {
938 112 : Node* native_context = LoadNativeContext(context);
939 : Node* number_constructor =
940 112 : LoadContextElement(native_context, Context::NUMBER_FUNCTION_INDEX);
941 : Node* number_initial_map = LoadObjectField(
942 : number_constructor, JSFunction::kPrototypeOrInitialMapOffset);
943 : Node* number_prototype =
944 : LoadObjectField(number_initial_map, Map::kPrototypeOffset);
945 112 : var_default.Bind(LoadRoot(RootIndex::knumber_to_string));
946 56 : var_holder.Bind(number_prototype);
947 56 : Goto(&checkstringtag);
948 : }
949 :
950 56 : BIND(&if_object);
951 : {
952 : CSA_ASSERT(this, IsJSReceiver(receiver));
953 112 : var_default.Bind(LoadRoot(RootIndex::kobject_to_string));
954 56 : Goto(&checkstringtag);
955 : }
956 :
957 56 : BIND(&if_primitive);
958 : {
959 : Label return_undefined(this);
960 :
961 112 : GotoIf(IsStringInstanceType(receiver_instance_type), &if_string);
962 112 : GotoIf(IsBigIntInstanceType(receiver_instance_type), &if_bigint);
963 112 : GotoIf(IsBooleanMap(receiver_map), &if_boolean);
964 112 : GotoIf(IsHeapNumberMap(receiver_map), &if_number);
965 112 : GotoIf(IsSymbolMap(receiver_map), &if_symbol);
966 112 : GotoIf(IsUndefined(receiver), &return_undefined);
967 : CSA_ASSERT(this, IsNull(receiver));
968 112 : Return(LoadRoot(RootIndex::knull_to_string));
969 :
970 56 : BIND(&return_undefined);
971 112 : Return(LoadRoot(RootIndex::kundefined_to_string));
972 : }
973 :
974 56 : BIND(&if_proxy);
975 : {
976 : // If {receiver} is a proxy for a JSArray, we default to "[object Array]",
977 : // otherwise we default to "[object Object]" or "[object Function]" here,
978 : // depending on whether the {receiver} is callable. The order matters here,
979 : // i.e. we need to execute the %ArrayIsArray check before the [[Get]] below,
980 : // as the exception is observable.
981 : Node* receiver_is_array =
982 : CallRuntime(Runtime::kArrayIsArray, context, receiver);
983 : TNode<String> builtin_tag = Select<String>(
984 56 : IsTrue(receiver_is_array),
985 56 : [=] { return CAST(LoadRoot(RootIndex::kArray_string)); },
986 56 : [=] {
987 : return Select<String>(
988 168 : IsCallableMap(receiver_map),
989 56 : [=] { return CAST(LoadRoot(RootIndex::kFunction_string)); },
990 336 : [=] { return CAST(LoadRoot(RootIndex::kObject_string)); });
991 336 : });
992 :
993 : // Lookup the @@toStringTag property on the {receiver}.
994 168 : VARIABLE(var_tag, MachineRepresentation::kTagged,
995 : GetProperty(context, receiver,
996 : isolate()->factory()->to_string_tag_symbol()));
997 56 : Label if_tagisnotstring(this), if_tagisstring(this);
998 168 : GotoIf(TaggedIsSmi(var_tag.value()), &if_tagisnotstring);
999 168 : Branch(IsString(var_tag.value()), &if_tagisstring, &if_tagisnotstring);
1000 56 : BIND(&if_tagisnotstring);
1001 : {
1002 56 : var_tag.Bind(builtin_tag);
1003 56 : Goto(&if_tagisstring);
1004 : }
1005 56 : BIND(&if_tagisstring);
1006 112 : ReturnToStringFormat(context, var_tag.value());
1007 : }
1008 :
1009 56 : BIND(&if_regexp);
1010 : {
1011 112 : var_default.Bind(LoadRoot(RootIndex::kregexp_to_string));
1012 56 : Goto(&checkstringtag);
1013 : }
1014 :
1015 56 : BIND(&if_string);
1016 : {
1017 112 : Node* native_context = LoadNativeContext(context);
1018 : Node* string_constructor =
1019 112 : LoadContextElement(native_context, Context::STRING_FUNCTION_INDEX);
1020 : Node* string_initial_map = LoadObjectField(
1021 : string_constructor, JSFunction::kPrototypeOrInitialMapOffset);
1022 : Node* string_prototype =
1023 : LoadObjectField(string_initial_map, Map::kPrototypeOffset);
1024 112 : var_default.Bind(LoadRoot(RootIndex::kstring_to_string));
1025 56 : var_holder.Bind(string_prototype);
1026 56 : Goto(&checkstringtag);
1027 : }
1028 :
1029 56 : BIND(&if_symbol);
1030 : {
1031 112 : Node* native_context = LoadNativeContext(context);
1032 : Node* symbol_constructor =
1033 112 : LoadContextElement(native_context, Context::SYMBOL_FUNCTION_INDEX);
1034 : Node* symbol_initial_map = LoadObjectField(
1035 : symbol_constructor, JSFunction::kPrototypeOrInitialMapOffset);
1036 : Node* symbol_prototype =
1037 : LoadObjectField(symbol_initial_map, Map::kPrototypeOffset);
1038 112 : var_default.Bind(LoadRoot(RootIndex::kobject_to_string));
1039 56 : var_holder.Bind(symbol_prototype);
1040 56 : Goto(&checkstringtag);
1041 : }
1042 :
1043 56 : BIND(&if_bigint);
1044 : {
1045 112 : Node* native_context = LoadNativeContext(context);
1046 : Node* bigint_constructor =
1047 112 : LoadContextElement(native_context, Context::BIGINT_FUNCTION_INDEX);
1048 : Node* bigint_initial_map = LoadObjectField(
1049 : bigint_constructor, JSFunction::kPrototypeOrInitialMapOffset);
1050 : Node* bigint_prototype =
1051 : LoadObjectField(bigint_initial_map, Map::kPrototypeOffset);
1052 112 : var_default.Bind(LoadRoot(RootIndex::kobject_to_string));
1053 56 : var_holder.Bind(bigint_prototype);
1054 56 : Goto(&checkstringtag);
1055 : }
1056 :
1057 56 : BIND(&if_value);
1058 : {
1059 : Label if_value_is_number(this, Label::kDeferred),
1060 56 : if_value_is_boolean(this, Label::kDeferred),
1061 56 : if_value_is_symbol(this, Label::kDeferred),
1062 56 : if_value_is_bigint(this, Label::kDeferred),
1063 56 : if_value_is_string(this, Label::kDeferred);
1064 :
1065 56 : Node* receiver_value = LoadJSValueValue(receiver);
1066 : // We need to start with the object to see if the value was a subclass
1067 : // which might have interesting properties.
1068 56 : var_holder.Bind(receiver);
1069 112 : GotoIf(TaggedIsSmi(receiver_value), &if_value_is_number);
1070 112 : Node* receiver_value_map = LoadMap(receiver_value);
1071 112 : GotoIf(IsHeapNumberMap(receiver_value_map), &if_value_is_number);
1072 112 : GotoIf(IsBooleanMap(receiver_value_map), &if_value_is_boolean);
1073 112 : GotoIf(IsSymbolMap(receiver_value_map), &if_value_is_symbol);
1074 : Node* receiver_value_instance_type =
1075 112 : LoadMapInstanceType(receiver_value_map);
1076 56 : GotoIf(IsBigIntInstanceType(receiver_value_instance_type),
1077 112 : &if_value_is_bigint);
1078 : CSA_ASSERT(this, IsStringInstanceType(receiver_value_instance_type));
1079 56 : Goto(&if_value_is_string);
1080 :
1081 56 : BIND(&if_value_is_number);
1082 : {
1083 112 : var_default.Bind(LoadRoot(RootIndex::knumber_to_string));
1084 56 : Goto(&checkstringtag);
1085 : }
1086 :
1087 56 : BIND(&if_value_is_boolean);
1088 : {
1089 112 : var_default.Bind(LoadRoot(RootIndex::kboolean_to_string));
1090 56 : Goto(&checkstringtag);
1091 : }
1092 :
1093 56 : BIND(&if_value_is_string);
1094 : {
1095 112 : var_default.Bind(LoadRoot(RootIndex::kstring_to_string));
1096 56 : Goto(&checkstringtag);
1097 : }
1098 :
1099 56 : BIND(&if_value_is_bigint);
1100 : {
1101 112 : var_default.Bind(LoadRoot(RootIndex::kobject_to_string));
1102 56 : Goto(&checkstringtag);
1103 : }
1104 :
1105 56 : BIND(&if_value_is_symbol);
1106 : {
1107 112 : var_default.Bind(LoadRoot(RootIndex::kobject_to_string));
1108 56 : Goto(&checkstringtag);
1109 56 : }
1110 : }
1111 :
1112 56 : BIND(&checkstringtag);
1113 : {
1114 : // Check if all relevant maps (including the prototype maps) don't
1115 : // have any interesting symbols (i.e. that none of them have the
1116 : // @@toStringTag property).
1117 56 : Label loop(this, &var_holder), return_default(this),
1118 56 : return_generic(this, Label::kDeferred);
1119 56 : Goto(&loop);
1120 56 : BIND(&loop);
1121 : {
1122 56 : Node* holder = var_holder.value();
1123 112 : GotoIf(IsNull(holder), &return_default);
1124 112 : Node* holder_map = LoadMap(holder);
1125 112 : Node* holder_bit_field3 = LoadMapBitField3(holder_map);
1126 : GotoIf(IsSetWord32<Map::MayHaveInterestingSymbolsBit>(holder_bit_field3),
1127 56 : &return_generic);
1128 112 : var_holder.Bind(LoadMapPrototype(holder_map));
1129 56 : Goto(&loop);
1130 : }
1131 :
1132 56 : BIND(&return_generic);
1133 : {
1134 56 : Node* tag = GetProperty(context, ToObject(context, receiver),
1135 224 : LoadRoot(RootIndex::kto_string_tag_symbol));
1136 112 : GotoIf(TaggedIsSmi(tag), &return_default);
1137 112 : GotoIfNot(IsString(tag), &return_default);
1138 56 : ReturnToStringFormat(context, tag);
1139 : }
1140 :
1141 56 : BIND(&return_default);
1142 168 : Return(var_default.value());
1143 56 : }
1144 56 : }
1145 :
1146 : // ES6 #sec-object.prototype.valueof
1147 224 : TF_BUILTIN(ObjectPrototypeValueOf, CodeStubAssembler) {
1148 56 : TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
1149 56 : TNode<Context> context = CAST(Parameter(Descriptor::kContext));
1150 :
1151 112 : Return(ToObject_Inline(context, receiver));
1152 56 : }
1153 :
1154 : // ES #sec-object.create
1155 224 : TF_BUILTIN(CreateObjectWithoutProperties, ObjectBuiltinsAssembler) {
1156 : Node* const prototype = Parameter(Descriptor::kPrototypeArg);
1157 : Node* const context = Parameter(Descriptor::kContext);
1158 112 : Node* const native_context = LoadNativeContext(context);
1159 56 : Label call_runtime(this, Label::kDeferred), prototype_null(this),
1160 56 : prototype_jsreceiver(this);
1161 : {
1162 56 : Comment("Argument check: prototype");
1163 112 : GotoIf(IsNull(prototype), &prototype_null);
1164 56 : BranchIfJSReceiver(prototype, &prototype_jsreceiver, &call_runtime);
1165 : }
1166 :
1167 112 : VARIABLE(map, MachineRepresentation::kTagged);
1168 112 : VARIABLE(properties, MachineRepresentation::kTagged);
1169 56 : Label instantiate_map(this);
1170 :
1171 56 : BIND(&prototype_null);
1172 : {
1173 56 : Comment("Prototype is null");
1174 : map.Bind(LoadContextElement(native_context,
1175 112 : Context::SLOW_OBJECT_WITH_NULL_PROTOTYPE_MAP));
1176 112 : properties.Bind(AllocateNameDictionary(NameDictionary::kInitialCapacity));
1177 56 : Goto(&instantiate_map);
1178 : }
1179 :
1180 56 : BIND(&prototype_jsreceiver);
1181 : {
1182 56 : Comment("Prototype is JSReceiver");
1183 112 : properties.Bind(EmptyFixedArrayConstant());
1184 : Node* object_function =
1185 112 : LoadContextElement(native_context, Context::OBJECT_FUNCTION_INDEX);
1186 : Node* object_function_map = LoadObjectField(
1187 : object_function, JSFunction::kPrototypeOrInitialMapOffset);
1188 56 : map.Bind(object_function_map);
1189 168 : GotoIf(WordEqual(prototype, LoadMapPrototype(map.value())),
1190 56 : &instantiate_map);
1191 56 : Comment("Try loading the prototype info");
1192 : Node* prototype_info =
1193 168 : LoadMapPrototypeInfo(LoadMap(prototype), &call_runtime);
1194 : TNode<MaybeObject> maybe_map = LoadMaybeWeakObjectField(
1195 56 : prototype_info, PrototypeInfo::kObjectCreateMapOffset);
1196 168 : GotoIf(IsStrongReferenceTo(maybe_map, UndefinedConstant()), &call_runtime);
1197 112 : map.Bind(GetHeapObjectAssumeWeak(maybe_map, &call_runtime));
1198 56 : Goto(&instantiate_map);
1199 : }
1200 :
1201 56 : BIND(&instantiate_map);
1202 : {
1203 56 : Comment("Instantiate map");
1204 56 : Node* instance = AllocateJSObjectFromMap(map.value(), properties.value());
1205 56 : Return(instance);
1206 : }
1207 :
1208 56 : BIND(&call_runtime);
1209 : {
1210 56 : Comment("Call Runtime (prototype is not null/jsreceiver)");
1211 : Node* result = CallRuntime(Runtime::kObjectCreate, context, prototype,
1212 56 : UndefinedConstant());
1213 56 : Return(result);
1214 56 : }
1215 56 : }
1216 :
1217 : // ES #sec-object.create
1218 280 : TF_BUILTIN(ObjectCreate, ObjectBuiltinsAssembler) {
1219 : int const kPrototypeArg = 0;
1220 : int const kPropertiesArg = 1;
1221 :
1222 : Node* argc =
1223 112 : ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
1224 56 : CodeStubArguments args(this, argc);
1225 :
1226 112 : Node* prototype = args.GetOptionalArgumentValue(kPrototypeArg);
1227 112 : Node* properties = args.GetOptionalArgumentValue(kPropertiesArg);
1228 : Node* context = Parameter(Descriptor::kContext);
1229 :
1230 56 : Label call_runtime(this, Label::kDeferred), prototype_valid(this),
1231 56 : no_properties(this);
1232 : {
1233 56 : Comment("Argument 1 check: prototype");
1234 112 : GotoIf(IsNull(prototype), &prototype_valid);
1235 56 : BranchIfJSReceiver(prototype, &prototype_valid, &call_runtime);
1236 : }
1237 :
1238 56 : BIND(&prototype_valid);
1239 : {
1240 56 : Comment("Argument 2 check: properties");
1241 : // Check that we have a simple object
1242 112 : GotoIf(TaggedIsSmi(properties), &call_runtime);
1243 : // Undefined implies no properties.
1244 112 : GotoIf(IsUndefined(properties), &no_properties);
1245 112 : Node* properties_map = LoadMap(properties);
1246 112 : GotoIf(IsSpecialReceiverMap(properties_map), &call_runtime);
1247 : // Stay on the fast path only if there are no elements.
1248 : GotoIfNot(WordEqual(LoadElements(properties),
1249 56 : LoadRoot(RootIndex::kEmptyFixedArray)),
1250 56 : &call_runtime);
1251 : // Handle dictionary objects or fast objects with properties in runtime.
1252 112 : Node* bit_field3 = LoadMapBitField3(properties_map);
1253 56 : GotoIf(IsSetWord32<Map::IsDictionaryMapBit>(bit_field3), &call_runtime);
1254 : Branch(IsSetWord32<Map::NumberOfOwnDescriptorsBits>(bit_field3),
1255 56 : &call_runtime, &no_properties);
1256 : }
1257 :
1258 : // Create a new object with the given prototype.
1259 56 : BIND(&no_properties);
1260 : {
1261 56 : VARIABLE(map, MachineRepresentation::kTagged);
1262 112 : VARIABLE(properties, MachineRepresentation::kTagged);
1263 56 : Label non_null_proto(this), instantiate_map(this), good(this);
1264 :
1265 112 : Branch(IsNull(prototype), &good, &non_null_proto);
1266 :
1267 56 : BIND(&good);
1268 : {
1269 : map.Bind(LoadContextElement(
1270 112 : context, Context::SLOW_OBJECT_WITH_NULL_PROTOTYPE_MAP));
1271 112 : properties.Bind(AllocateNameDictionary(NameDictionary::kInitialCapacity));
1272 56 : Goto(&instantiate_map);
1273 : }
1274 :
1275 56 : BIND(&non_null_proto);
1276 : {
1277 112 : properties.Bind(EmptyFixedArrayConstant());
1278 : Node* object_function =
1279 112 : LoadContextElement(context, Context::OBJECT_FUNCTION_INDEX);
1280 : Node* object_function_map = LoadObjectField(
1281 : object_function, JSFunction::kPrototypeOrInitialMapOffset);
1282 56 : map.Bind(object_function_map);
1283 168 : GotoIf(WordEqual(prototype, LoadMapPrototype(map.value())),
1284 56 : &instantiate_map);
1285 : // Try loading the prototype info.
1286 : Node* prototype_info =
1287 168 : LoadMapPrototypeInfo(LoadMap(prototype), &call_runtime);
1288 56 : Comment("Load ObjectCreateMap from PrototypeInfo");
1289 : TNode<MaybeObject> maybe_map = LoadMaybeWeakObjectField(
1290 56 : prototype_info, PrototypeInfo::kObjectCreateMapOffset);
1291 112 : GotoIf(IsStrongReferenceTo(maybe_map, UndefinedConstant()),
1292 112 : &call_runtime);
1293 112 : map.Bind(GetHeapObjectAssumeWeak(maybe_map, &call_runtime));
1294 56 : Goto(&instantiate_map);
1295 : }
1296 :
1297 56 : BIND(&instantiate_map);
1298 : {
1299 56 : Node* instance = AllocateJSObjectFromMap(map.value(), properties.value());
1300 56 : args.PopAndReturn(instance);
1301 56 : }
1302 : }
1303 :
1304 56 : BIND(&call_runtime);
1305 : {
1306 : Node* result =
1307 : CallRuntime(Runtime::kObjectCreate, context, prototype, properties);
1308 56 : args.PopAndReturn(result);
1309 56 : }
1310 56 : }
1311 :
1312 : // ES #sec-object.is
1313 224 : TF_BUILTIN(ObjectIs, ObjectBuiltinsAssembler) {
1314 : Node* const left = Parameter(Descriptor::kLeft);
1315 : Node* const right = Parameter(Descriptor::kRight);
1316 :
1317 56 : Label return_true(this), return_false(this);
1318 56 : BranchIfSameValue(left, right, &return_true, &return_false);
1319 :
1320 56 : BIND(&return_true);
1321 112 : Return(TrueConstant());
1322 :
1323 56 : BIND(&return_false);
1324 168 : Return(FalseConstant());
1325 56 : }
1326 :
1327 224 : TF_BUILTIN(CreateIterResultObject, ObjectBuiltinsAssembler) {
1328 : Node* const value = Parameter(Descriptor::kValue);
1329 : Node* const done = Parameter(Descriptor::kDone);
1330 : Node* const context = Parameter(Descriptor::kContext);
1331 :
1332 112 : Node* const native_context = LoadNativeContext(context);
1333 : Node* const map =
1334 112 : LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX);
1335 :
1336 56 : Node* const result = AllocateJSObjectFromMap(map);
1337 :
1338 56 : StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kValueOffset, value);
1339 56 : StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kDoneOffset, done);
1340 :
1341 56 : Return(result);
1342 56 : }
1343 :
1344 224 : TF_BUILTIN(HasProperty, ObjectBuiltinsAssembler) {
1345 : Node* key = Parameter(Descriptor::kKey);
1346 : Node* object = Parameter(Descriptor::kObject);
1347 : Node* context = Parameter(Descriptor::kContext);
1348 :
1349 112 : Return(HasProperty(context, object, key, kHasProperty));
1350 56 : }
1351 :
1352 224 : TF_BUILTIN(InstanceOf, ObjectBuiltinsAssembler) {
1353 : Node* object = Parameter(Descriptor::kLeft);
1354 : Node* callable = Parameter(Descriptor::kRight);
1355 : Node* context = Parameter(Descriptor::kContext);
1356 :
1357 112 : Return(InstanceOf(object, callable, context));
1358 56 : }
1359 :
1360 : // ES6 section 7.3.19 OrdinaryHasInstance ( C, O )
1361 224 : TF_BUILTIN(OrdinaryHasInstance, ObjectBuiltinsAssembler) {
1362 : Node* constructor = Parameter(Descriptor::kLeft);
1363 : Node* object = Parameter(Descriptor::kRight);
1364 : Node* context = Parameter(Descriptor::kContext);
1365 :
1366 112 : Return(OrdinaryHasInstance(context, constructor, object));
1367 56 : }
1368 :
1369 224 : TF_BUILTIN(GetSuperConstructor, ObjectBuiltinsAssembler) {
1370 : Node* object = Parameter(Descriptor::kObject);
1371 : Node* context = Parameter(Descriptor::kContext);
1372 :
1373 112 : Return(GetSuperConstructor(context, object));
1374 56 : }
1375 :
1376 224 : TF_BUILTIN(CreateGeneratorObject, ObjectBuiltinsAssembler) {
1377 : Node* closure = Parameter(Descriptor::kClosure);
1378 : Node* receiver = Parameter(Descriptor::kReceiver);
1379 : Node* context = Parameter(Descriptor::kContext);
1380 :
1381 : // Get the initial map from the function, jumping to the runtime if we don't
1382 : // have one.
1383 56 : Label done(this), runtime(this);
1384 168 : GotoIfNot(IsFunctionWithPrototypeSlotMap(LoadMap(closure)), &runtime);
1385 : Node* maybe_map =
1386 : LoadObjectField(closure, JSFunction::kPrototypeOrInitialMapOffset);
1387 112 : GotoIf(DoesntHaveInstanceType(maybe_map, MAP_TYPE), &runtime);
1388 :
1389 : Node* shared =
1390 : LoadObjectField(closure, JSFunction::kSharedFunctionInfoOffset);
1391 112 : Node* bytecode_array = LoadSharedFunctionInfoBytecodeArray(shared);
1392 :
1393 : Node* formal_parameter_count = ChangeInt32ToIntPtr(
1394 : LoadObjectField(shared, SharedFunctionInfo::kFormalParameterCountOffset,
1395 168 : MachineType::Uint16()));
1396 : Node* frame_size = ChangeInt32ToIntPtr(LoadObjectField(
1397 168 : bytecode_array, BytecodeArray::kFrameSizeOffset, MachineType::Int32()));
1398 112 : Node* size = IntPtrAdd(WordSar(frame_size, IntPtrConstant(kTaggedSizeLog2)),
1399 224 : formal_parameter_count);
1400 112 : Node* parameters_and_registers = AllocateFixedArray(HOLEY_ELEMENTS, size);
1401 : FillFixedArrayWithValue(HOLEY_ELEMENTS, parameters_and_registers,
1402 112 : IntPtrConstant(0), size, RootIndex::kUndefinedValue);
1403 : // TODO(cbruni): support start_offset to avoid double initialization.
1404 : Node* result = AllocateJSObjectFromMap(maybe_map, nullptr, nullptr, kNone,
1405 56 : kWithSlackTracking);
1406 : StoreObjectFieldNoWriteBarrier(result, JSGeneratorObject::kFunctionOffset,
1407 56 : closure);
1408 : StoreObjectFieldNoWriteBarrier(result, JSGeneratorObject::kContextOffset,
1409 56 : context);
1410 : StoreObjectFieldNoWriteBarrier(result, JSGeneratorObject::kReceiverOffset,
1411 56 : receiver);
1412 : StoreObjectFieldNoWriteBarrier(
1413 : result, JSGeneratorObject::kParametersAndRegistersOffset,
1414 56 : parameters_and_registers);
1415 112 : Node* executing = SmiConstant(JSGeneratorObject::kGeneratorExecuting);
1416 : StoreObjectFieldNoWriteBarrier(result, JSGeneratorObject::kContinuationOffset,
1417 56 : executing);
1418 112 : GotoIfNot(HasInstanceType(maybe_map, JS_ASYNC_GENERATOR_OBJECT_TYPE), &done);
1419 : StoreObjectFieldNoWriteBarrier(
1420 112 : result, JSAsyncGeneratorObject::kIsAwaitingOffset, SmiConstant(0));
1421 56 : Goto(&done);
1422 :
1423 56 : BIND(&done);
1424 56 : { Return(result); }
1425 :
1426 56 : BIND(&runtime);
1427 : {
1428 : Return(CallRuntime(Runtime::kCreateJSGeneratorObject, context, closure,
1429 56 : receiver));
1430 56 : }
1431 56 : }
1432 :
1433 : // ES6 section 19.1.2.7 Object.getOwnPropertyDescriptor ( O, P )
1434 224 : TF_BUILTIN(ObjectGetOwnPropertyDescriptor, ObjectBuiltinsAssembler) {
1435 : Node* argc = Parameter(Descriptor::kJSActualArgumentsCount);
1436 : Node* context = Parameter(Descriptor::kContext);
1437 : CSA_ASSERT(this, IsUndefined(Parameter(Descriptor::kJSNewTarget)));
1438 :
1439 168 : CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
1440 112 : Node* object = args.GetOptionalArgumentValue(0);
1441 112 : Node* key = args.GetOptionalArgumentValue(1);
1442 :
1443 : // 1. Let obj be ? ToObject(O).
1444 112 : object = ToObject_Inline(CAST(context), CAST(object));
1445 :
1446 : // 2. Let key be ? ToPropertyKey(P).
1447 112 : key = CallBuiltin(Builtins::kToName, context, key);
1448 :
1449 : // 3. Let desc be ? obj.[[GetOwnProperty]](key).
1450 56 : Label if_keyisindex(this), if_iskeyunique(this),
1451 56 : call_runtime(this, Label::kDeferred),
1452 56 : return_undefined(this, Label::kDeferred), if_notunique_name(this);
1453 112 : Node* map = LoadMap(object);
1454 56 : TNode<Int32T> instance_type = LoadMapInstanceType(map);
1455 112 : GotoIf(IsSpecialReceiverInstanceType(instance_type), &call_runtime);
1456 : {
1457 112 : VARIABLE(var_index, MachineType::PointerRepresentation(),
1458 : IntPtrConstant(0));
1459 112 : VARIABLE(var_name, MachineRepresentation::kTagged);
1460 :
1461 : TryToName(key, &if_keyisindex, &var_index, &if_iskeyunique, &var_name,
1462 56 : &call_runtime, &if_notunique_name);
1463 :
1464 56 : BIND(&if_notunique_name);
1465 : {
1466 : Label not_in_string_table(this);
1467 : TryInternalizeString(key, &if_keyisindex, &var_index, &if_iskeyunique,
1468 56 : &var_name, ¬_in_string_table, &call_runtime);
1469 :
1470 56 : BIND(¬_in_string_table);
1471 : {
1472 : // If the string was not found in the string table, then no regular
1473 : // object can have a property with that name, so return |undefined|.
1474 56 : Goto(&return_undefined);
1475 56 : }
1476 : }
1477 :
1478 56 : BIND(&if_iskeyunique);
1479 : {
1480 56 : Label if_found_value(this), return_empty(this), if_not_found(this);
1481 :
1482 112 : VARIABLE(var_value, MachineRepresentation::kTagged);
1483 112 : VARIABLE(var_details, MachineRepresentation::kWord32);
1484 112 : VARIABLE(var_raw_value, MachineRepresentation::kTagged);
1485 :
1486 : TryGetOwnProperty(context, object, object, map, instance_type,
1487 : var_name.value(), &if_found_value, &var_value,
1488 : &var_details, &var_raw_value, &return_empty,
1489 112 : &if_not_found, kReturnAccessorPair);
1490 :
1491 56 : BIND(&if_found_value);
1492 : // 4. Return FromPropertyDescriptor(desc).
1493 : Node* js_desc = FromPropertyDetails(context, var_value.value(),
1494 56 : var_details.value(), &call_runtime);
1495 56 : args.PopAndReturn(js_desc);
1496 :
1497 56 : BIND(&return_empty);
1498 112 : var_value.Bind(UndefinedConstant());
1499 112 : args.PopAndReturn(UndefinedConstant());
1500 :
1501 56 : BIND(&if_not_found);
1502 112 : Goto(&call_runtime);
1503 56 : }
1504 : }
1505 :
1506 56 : BIND(&if_keyisindex);
1507 56 : Goto(&call_runtime);
1508 :
1509 56 : BIND(&call_runtime);
1510 : {
1511 : Node* desc =
1512 : CallRuntime(Runtime::kGetOwnPropertyDescriptor, context, object, key);
1513 :
1514 112 : GotoIf(IsUndefined(desc), &return_undefined);
1515 :
1516 : CSA_ASSERT(this, IsFixedArray(desc));
1517 :
1518 : // 4. Return FromPropertyDescriptor(desc).
1519 56 : Node* js_desc = FromPropertyDescriptor(context, desc);
1520 56 : args.PopAndReturn(js_desc);
1521 : }
1522 56 : BIND(&return_undefined);
1523 168 : args.PopAndReturn(UndefinedConstant());
1524 56 : }
1525 :
1526 336 : void ObjectBuiltinsAssembler::AddToDictionaryIf(
1527 : TNode<BoolT> condition, TNode<NameDictionary> name_dictionary,
1528 : Handle<Name> name, TNode<Object> value, Label* bailout) {
1529 336 : Label done(this);
1530 336 : GotoIfNot(condition, &done);
1531 :
1532 336 : Add<NameDictionary>(name_dictionary, HeapConstant(name), value, bailout);
1533 336 : Goto(&done);
1534 :
1535 336 : BIND(&done);
1536 336 : }
1537 :
1538 56 : Node* ObjectBuiltinsAssembler::FromPropertyDescriptor(Node* context,
1539 : Node* desc) {
1540 56 : VARIABLE(js_descriptor, MachineRepresentation::kTagged);
1541 :
1542 : Node* flags = LoadAndUntagToWord32ObjectField(
1543 112 : desc, PropertyDescriptorObject::kFlagsOffset);
1544 :
1545 : Node* has_flags =
1546 168 : Word32And(flags, Int32Constant(PropertyDescriptorObject::kHasMask));
1547 :
1548 56 : Label if_accessor_desc(this), if_data_desc(this), if_generic_desc(this),
1549 56 : return_desc(this);
1550 : GotoIf(
1551 : Word32Equal(has_flags,
1552 : Int32Constant(
1553 112 : PropertyDescriptorObject::kRegularAccessorPropertyBits)),
1554 112 : &if_accessor_desc);
1555 : GotoIf(Word32Equal(
1556 : has_flags,
1557 112 : Int32Constant(PropertyDescriptorObject::kRegularDataPropertyBits)),
1558 112 : &if_data_desc);
1559 56 : Goto(&if_generic_desc);
1560 :
1561 56 : BIND(&if_accessor_desc);
1562 : {
1563 : js_descriptor.Bind(ConstructAccessorDescriptor(
1564 : context, LoadObjectField(desc, PropertyDescriptorObject::kGetOffset),
1565 : LoadObjectField(desc, PropertyDescriptorObject::kSetOffset),
1566 : IsSetWord32<PropertyDescriptorObject::IsEnumerableBit>(flags),
1567 56 : IsSetWord32<PropertyDescriptorObject::IsConfigurableBit>(flags)));
1568 56 : Goto(&return_desc);
1569 : }
1570 :
1571 56 : BIND(&if_data_desc);
1572 : {
1573 : js_descriptor.Bind(ConstructDataDescriptor(
1574 : context, LoadObjectField(desc, PropertyDescriptorObject::kValueOffset),
1575 : IsSetWord32<PropertyDescriptorObject::IsWritableBit>(flags),
1576 : IsSetWord32<PropertyDescriptorObject::IsEnumerableBit>(flags),
1577 56 : IsSetWord32<PropertyDescriptorObject::IsConfigurableBit>(flags)));
1578 56 : Goto(&return_desc);
1579 : }
1580 :
1581 56 : BIND(&if_generic_desc);
1582 : {
1583 112 : Node* native_context = LoadNativeContext(context);
1584 : Node* map = LoadContextElement(
1585 112 : native_context, Context::SLOW_OBJECT_WITH_OBJECT_PROTOTYPE_MAP);
1586 : // We want to preallocate the slots for value, writable, get, set,
1587 : // enumerable and configurable - a total of 6
1588 56 : TNode<NameDictionary> properties = AllocateNameDictionary(6);
1589 56 : Node* js_desc = AllocateJSObjectFromMap(map, properties);
1590 :
1591 : Label bailout(this, Label::kDeferred);
1592 :
1593 56 : Factory* factory = isolate()->factory();
1594 : TNode<Object> value =
1595 : LoadObjectField(desc, PropertyDescriptorObject::kValueOffset);
1596 : AddToDictionaryIf(IsNotTheHole(value), properties, factory->value_string(),
1597 56 : value, &bailout);
1598 : AddToDictionaryIf(
1599 : IsSetWord32<PropertyDescriptorObject::HasWritableBit>(flags),
1600 : properties, factory->writable_string(),
1601 : SelectBooleanConstant(
1602 56 : IsSetWord32<PropertyDescriptorObject::IsWritableBit>(flags)),
1603 112 : &bailout);
1604 :
1605 : TNode<Object> get =
1606 : LoadObjectField(desc, PropertyDescriptorObject::kGetOffset);
1607 : AddToDictionaryIf(IsNotTheHole(get), properties, factory->get_string(), get,
1608 56 : &bailout);
1609 : TNode<Object> set =
1610 : LoadObjectField(desc, PropertyDescriptorObject::kSetOffset);
1611 : AddToDictionaryIf(IsNotTheHole(set), properties, factory->set_string(), set,
1612 56 : &bailout);
1613 :
1614 : AddToDictionaryIf(
1615 : IsSetWord32<PropertyDescriptorObject::HasEnumerableBit>(flags),
1616 : properties, factory->enumerable_string(),
1617 : SelectBooleanConstant(
1618 56 : IsSetWord32<PropertyDescriptorObject::IsEnumerableBit>(flags)),
1619 112 : &bailout);
1620 : AddToDictionaryIf(
1621 : IsSetWord32<PropertyDescriptorObject::HasConfigurableBit>(flags),
1622 : properties, factory->configurable_string(),
1623 : SelectBooleanConstant(
1624 56 : IsSetWord32<PropertyDescriptorObject::IsConfigurableBit>(flags)),
1625 112 : &bailout);
1626 :
1627 56 : js_descriptor.Bind(js_desc);
1628 56 : Goto(&return_desc);
1629 :
1630 56 : BIND(&bailout);
1631 : CSA_ASSERT(this, Int32Constant(0));
1632 56 : Unreachable();
1633 : }
1634 :
1635 56 : BIND(&return_desc);
1636 112 : return js_descriptor.value();
1637 : }
1638 :
1639 56 : Node* ObjectBuiltinsAssembler::FromPropertyDetails(Node* context,
1640 : Node* raw_value,
1641 : Node* details,
1642 : Label* if_bailout) {
1643 56 : VARIABLE(js_descriptor, MachineRepresentation::kTagged);
1644 :
1645 56 : Label if_accessor_desc(this), if_data_desc(this), return_desc(this);
1646 56 : BranchIfAccessorPair(raw_value, &if_accessor_desc, &if_data_desc);
1647 :
1648 56 : BIND(&if_accessor_desc);
1649 : {
1650 : Node* getter = LoadObjectField(raw_value, AccessorPair::kGetterOffset);
1651 : Node* setter = LoadObjectField(raw_value, AccessorPair::kSetterOffset);
1652 : js_descriptor.Bind(ConstructAccessorDescriptor(
1653 : context, GetAccessorOrUndefined(getter, if_bailout),
1654 : GetAccessorOrUndefined(setter, if_bailout),
1655 56 : IsNotSetWord32(details, PropertyDetails::kAttributesDontEnumMask),
1656 224 : IsNotSetWord32(details, PropertyDetails::kAttributesDontDeleteMask)));
1657 56 : Goto(&return_desc);
1658 : }
1659 :
1660 56 : BIND(&if_data_desc);
1661 : {
1662 : js_descriptor.Bind(ConstructDataDescriptor(
1663 : context, raw_value,
1664 56 : IsNotSetWord32(details, PropertyDetails::kAttributesReadOnlyMask),
1665 56 : IsNotSetWord32(details, PropertyDetails::kAttributesDontEnumMask),
1666 336 : IsNotSetWord32(details, PropertyDetails::kAttributesDontDeleteMask)));
1667 56 : Goto(&return_desc);
1668 : }
1669 :
1670 56 : BIND(&return_desc);
1671 112 : return js_descriptor.value();
1672 : }
1673 :
1674 112 : Node* ObjectBuiltinsAssembler::GetAccessorOrUndefined(Node* accessor,
1675 : Label* if_bailout) {
1676 224 : Label bind_undefined(this, Label::kDeferred), return_result(this);
1677 224 : VARIABLE(result, MachineRepresentation::kTagged);
1678 :
1679 224 : GotoIf(IsNull(accessor), &bind_undefined);
1680 112 : result.Bind(accessor);
1681 224 : Node* map = LoadMap(accessor);
1682 : // TODO(ishell): probe template instantiations cache.
1683 224 : GotoIf(IsFunctionTemplateInfoMap(map), if_bailout);
1684 112 : Goto(&return_result);
1685 :
1686 112 : BIND(&bind_undefined);
1687 224 : result.Bind(UndefinedConstant());
1688 112 : Goto(&return_result);
1689 :
1690 112 : BIND(&return_result);
1691 224 : return result.value();
1692 : }
1693 : } // namespace internal
1694 94089 : } // namespace v8
|