v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
builtins-constructor-gen.cc
Go to the documentation of this file.
1// Copyright 2016 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
6
7#include <optional>
8
9#include "src/ast/ast.h"
17#include "src/common/globals.h"
20
21namespace v8 {
22namespace internal {
23
25
26void Builtins::Generate_ConstructVarargs(MacroAssembler* masm) {
27 Generate_CallOrConstructVarargs(masm, Builtin::kConstruct);
28}
29
30void Builtins::Generate_ConstructForwardVarargs(MacroAssembler* masm) {
32 Builtin::kConstruct);
33}
34
35void Builtins::Generate_ConstructFunctionForwardVarargs(MacroAssembler* masm) {
37 Builtin::kConstructFunction);
38}
39
40// static
41void Builtins::Generate_InterpreterForwardAllArgsThenConstruct(
42 MacroAssembler* masm) {
45}
46
47// static
48void Builtins::Generate_ConstructForwardAllArgs(MacroAssembler* masm) {
51}
52
54 auto target = Parameter<JSAny>(Descriptor::kTarget);
55 auto new_target = Parameter<JSAny>(Descriptor::kNewTarget);
56 auto argc = UncheckedParameter<Int32T>(Descriptor::kActualArgumentsCount);
57 auto slot = UncheckedParameter<UintPtrT>(Descriptor::kSlot);
58
59 BuildConstruct(
60 target, new_target, argc, [=, this] { return LoadContextFromBaseline(); },
61 [=, this] { return LoadFeedbackVectorFromBaseline(); }, slot,
63}
64
66 auto target = Parameter<JSAny>(Descriptor::kTarget);
67 auto new_target = Parameter<JSAny>(Descriptor::kNewTarget);
68 auto argc = UncheckedParameter<Int32T>(Descriptor::kActualArgumentsCount);
69 auto context = Parameter<Context>(Descriptor::kContext);
70 auto feedback_vector = Parameter<FeedbackVector>(Descriptor::kFeedbackVector);
71 auto slot = UncheckedParameter<UintPtrT>(Descriptor::kSlot);
72
73 BuildConstruct(
74 target, new_target, argc, [=] { return context; },
75 [=] { return feedback_vector; }, slot,
77}
78
81 const LazyNode<Context>& context,
82 const LazyNode<Union<Undefined, FeedbackVector>>& feedback_vector,
84 TVARIABLE(AllocationSite, allocation_site);
85 Label if_construct_generic(this), if_construct_array(this);
86 TNode<Context> eager_context = context();
87 // TODO(42200059): Propagate TaggedIndex usage.
88 CollectConstructFeedback(eager_context, target, new_target, feedback_vector(),
89 IntPtrToTaggedIndex(Signed(slot)), mode,
90 &if_construct_generic, &if_construct_array,
91 &allocation_site);
92
93 BIND(&if_construct_generic);
94 TailCallBuiltin(Builtin::kConstruct, eager_context, target, new_target, argc);
95
96 BIND(&if_construct_array);
97 TailCallBuiltin(Builtin::kArrayConstructorImpl, eager_context, target,
98 new_target, argc, allocation_site.value());
99}
100
102 auto target = Parameter<JSAny>(Descriptor::kTarget);
103 auto new_target = Parameter<JSAny>(Descriptor::kNewTarget);
104 auto arguments_list = Parameter<Object>(Descriptor::kArgumentsList);
105 auto context = Parameter<Context>(Descriptor::kContext);
106 CallOrConstructWithArrayLike(target, new_target, arguments_list, context);
107}
108
110 auto target = Parameter<JSAny>(Descriptor::kTarget);
111 auto new_target = Parameter<JSAny>(Descriptor::kNewTarget);
112 auto spread = Parameter<JSAny>(Descriptor::kSpread);
113 auto args_count =
114 UncheckedParameter<Int32T>(Descriptor::kActualArgumentsCount);
115 auto context = Parameter<Context>(Descriptor::kContext);
116 CallOrConstructWithSpread(target, new_target, spread, args_count, context);
117}
118
119TF_BUILTIN(ConstructWithSpread_Baseline, CallOrConstructBuiltinsAssembler) {
120 auto target = Parameter<JSAny>(Descriptor::kTarget);
121 auto new_target = Parameter<JSAny>(Descriptor::kNewTarget);
122 auto spread = Parameter<JSAny>(Descriptor::kSpread);
123 auto args_count =
124 UncheckedParameter<Int32T>(Descriptor::kActualArgumentsCount);
125 auto slot = UncheckedParameter<TaggedIndex>(Descriptor::kSlot);
126 return BuildConstructWithSpread(
127 target, new_target, spread, args_count,
128 [=, this] { return LoadContextFromBaseline(); },
129 [=, this] { return LoadFeedbackVectorFromBaseline(); }, slot,
131}
132
133TF_BUILTIN(ConstructWithSpread_WithFeedback, CallOrConstructBuiltinsAssembler) {
134 auto target = Parameter<JSAny>(Descriptor::kTarget);
135 auto new_target = Parameter<JSAny>(Descriptor::kNewTarget);
136 auto spread = Parameter<JSAny>(Descriptor::kSpread);
137 auto args_count =
138 UncheckedParameter<Int32T>(Descriptor::kActualArgumentsCount);
139 auto context = Parameter<Context>(Descriptor::kContext);
140 auto feedback_vector = Parameter<FeedbackVector>(Descriptor::kVector);
141 auto slot = UncheckedParameter<TaggedIndex>(Descriptor::kSlot);
142
143 return BuildConstructWithSpread(
144 target, new_target, spread, args_count, [=] { return context; },
145 [=] { return feedback_vector; }, slot,
147}
148
151 TNode<Int32T> argc, const LazyNode<Context>& context,
152 const LazyNode<Union<Undefined, FeedbackVector>>& feedback_vector,
154 TVARIABLE(AllocationSite, allocation_site);
155 Label if_construct_generic(this), if_construct_array(this);
156 TNode<Context> eager_context = context();
157 CollectConstructFeedback(eager_context, target, new_target, feedback_vector(),
159 &if_construct_generic, &if_construct_array,
160 &allocation_site);
161
162 BIND(&if_construct_array);
163 Goto(&if_construct_generic); // Not implemented.
164
165 BIND(&if_construct_generic);
166 CallOrConstructWithSpread(target, new_target, spread, argc, eager_context);
167}
168
169TF_BUILTIN(ConstructForwardAllArgs_Baseline, CallOrConstructBuiltinsAssembler) {
170 auto target = Parameter<JSAny>(Descriptor::kTarget);
171 auto new_target = Parameter<JSAny>(Descriptor::kNewTarget);
172 auto slot = UncheckedParameter<TaggedIndex>(Descriptor::kSlot);
173
174 return BuildConstructForwardAllArgs(
175 target, new_target, [=, this] { return LoadContextFromBaseline(); },
176 [=, this] { return LoadFeedbackVectorFromBaseline(); }, slot);
177}
178
179TF_BUILTIN(ConstructForwardAllArgs_WithFeedback,
181 auto target = Parameter<JSAny>(Descriptor::kTarget);
182 auto new_target = Parameter<JSAny>(Descriptor::kNewTarget);
183 auto slot = UncheckedParameter<TaggedIndex>(Descriptor::kSlot);
184 auto feedback_vector = Parameter<FeedbackVector>(Descriptor::kVector);
185 auto context = Parameter<Context>(Descriptor::kContext);
186
187 return BuildConstructForwardAllArgs(
188 target, new_target, [=] { return context; },
189 [=] { return feedback_vector; }, slot);
190}
191
194 const LazyNode<Context>& context,
195 const LazyNode<Union<Undefined, FeedbackVector>>& feedback_vector,
196 TNode<TaggedIndex> slot) {
197 TVARIABLE(AllocationSite, allocation_site);
198 TNode<Context> eager_context = context();
199
200 Label construct(this);
201 CollectConstructFeedback(eager_context, target, new_target, feedback_vector(),
203 &construct, &construct, &allocation_site);
204
205 BIND(&construct);
206 TailCallBuiltin(Builtin::kConstructForwardAllArgs, eager_context, target,
207 new_target);
208}
209
211 auto shared_function_info =
212 Parameter<SharedFunctionInfo>(Descriptor::kSharedFunctionInfo);
213 auto feedback_cell = Parameter<FeedbackCell>(Descriptor::kFeedbackCell);
214 auto context = Parameter<Context>(Descriptor::kContext);
215
216 // Bump the closure counter encoded in the {feedback_cell}s map.
217 {
218 const TNode<Map> feedback_cell_map = LoadMap(feedback_cell);
219 Label no_closures(this), one_closure(this), cell_done(this);
220
221 GotoIf(IsNoClosuresCellMap(feedback_cell_map), &no_closures);
222 GotoIf(IsOneClosureCellMap(feedback_cell_map), &one_closure);
223 CSA_DCHECK(this, IsManyClosuresCellMap(feedback_cell_map),
224 feedback_cell_map, feedback_cell);
225 Goto(&cell_done);
226
227 BIND(&no_closures);
228 StoreMapNoWriteBarrier(feedback_cell, RootIndex::kOneClosureCellMap);
229 Goto(&cell_done);
230
231 BIND(&one_closure);
232#ifdef V8_ENABLE_LEAPTIERING
233 // The transition from one to many closures under leap tiering requires
234 // making sure that the dispatch_handle's code isn't context specialized for
235 // the single closure. This is handled in the runtime.
236 //
237 // TODO(leszeks): We could fast path this for the case where the dispatch
238 // handle either doesn't contain any code, or that code isn't context
239 // specialized.
240 TailCallRuntime(Runtime::kNewClosure, context, shared_function_info,
241 feedback_cell);
242#else
243 StoreMapNoWriteBarrier(feedback_cell, RootIndex::kManyClosuresCellMap);
244 Goto(&cell_done);
245#endif // V8_ENABLE_LEAPTIERING
246
247 BIND(&cell_done);
248 }
249
250 // The calculation of |function_map_index| must be in sync with
251 // SharedFunctionInfo::function_map_index().
252 TNode<Uint32T> flags = LoadObjectField<Uint32T>(
253 shared_function_info, SharedFunctionInfo::kFlagsOffset);
254 const TNode<IntPtrT> function_map_index = Signed(IntPtrAdd(
255 DecodeWordFromWord32<SharedFunctionInfo::FunctionMapIndexBits>(flags),
256 IntPtrConstant(Context::FIRST_FUNCTION_MAP_INDEX)));
257 CSA_DCHECK(this, UintPtrLessThanOrEqual(
258 function_map_index,
259 IntPtrConstant(Context::LAST_FUNCTION_MAP_INDEX)));
260
261 // Get the function map in the current native context and set that
262 // as the map of the allocated object.
263 const TNode<NativeContext> native_context = LoadNativeContext(context);
264 const TNode<Map> function_map =
265 CAST(LoadContextElement(native_context, function_map_index));
266
267 // Create a new closure from the given function info in new space
268 TNode<IntPtrT> instance_size_in_bytes =
269 TimesTaggedSize(LoadMapInstanceSizeInWords(function_map));
270 TNode<HeapObject> result = Allocate(instance_size_in_bytes);
271 StoreMapNoWriteBarrier(result, function_map);
272 InitializeJSObjectBodyNoSlackTracking(result, function_map,
273 instance_size_in_bytes,
275
276 // Initialize the rest of the function.
277 StoreObjectFieldRoot(result, JSObject::kPropertiesOrHashOffset,
278 RootIndex::kEmptyFixedArray);
279 StoreObjectFieldRoot(result, JSObject::kElementsOffset,
280 RootIndex::kEmptyFixedArray);
281 {
282 // Set function prototype if necessary.
283 Label done(this), init_prototype(this);
284 Branch(IsFunctionWithPrototypeSlotMap(function_map), &init_prototype,
285 &done);
286
287 BIND(&init_prototype);
288 StoreObjectFieldRoot(result, JSFunction::kPrototypeOrInitialMapOffset,
289 RootIndex::kTheHoleValue);
290 Goto(&done);
291 BIND(&done);
292 }
293
295 StoreObjectFieldNoWriteBarrier(result, JSFunction::kFeedbackCellOffset,
296 feedback_cell);
297 StoreObjectFieldNoWriteBarrier(result, JSFunction::kSharedFunctionInfoOffset,
298 shared_function_info);
299 StoreObjectFieldNoWriteBarrier(result, JSFunction::kContextOffset, context);
300#ifdef V8_ENABLE_LEAPTIERING
301 TNode<JSDispatchHandleT> dispatch_handle = LoadObjectField<JSDispatchHandleT>(
302 feedback_cell, FeedbackCell::kDispatchHandleOffset);
303 CSA_DCHECK(this,
304 Word32NotEqual(dispatch_handle,
305 Int32Constant(kNullJSDispatchHandle.value())));
306 StoreObjectFieldNoWriteBarrier(result, JSFunction::kDispatchHandleOffset,
307 dispatch_handle);
308#else
309 TNode<Code> lazy_builtin =
310 HeapConstantNoHole(BUILTIN_CODE(isolate(), CompileLazy));
311 StoreCodePointerField(result, JSFunction::kCodeOffset, lazy_builtin);
312#endif // V8_ENABLE_LEAPTIERING
313 Return(result);
314}
315
317 auto context = Parameter<Context>(Descriptor::kContext);
318 auto target = Parameter<JSFunction>(Descriptor::kTarget);
319 auto new_target = Parameter<JSReceiver>(Descriptor::kNewTarget);
320
321 Label call_runtime(this);
322
324 FastNewObject(context, target, new_target, &call_runtime);
325 Return(result);
326
327 BIND(&call_runtime);
328 TailCallRuntime(Runtime::kNewObject, context, target, new_target);
329}
330
332 TNode<Context> context, TNode<JSFunction> target,
334 TVARIABLE(JSObject, var_obj);
335 Label call_runtime(this), end(this);
336
337 var_obj = FastNewObject(context, target, new_target, &call_runtime);
338 Goto(&end);
339
340 BIND(&call_runtime);
341 var_obj = CAST(CallRuntime(Runtime::kNewObject, context, target, new_target));
342 Goto(&end);
343
344 BIND(&end);
345 return var_obj.value();
346}
347
349 TNode<Context> context, TNode<JSFunction> target,
350 TNode<JSReceiver> new_target, Label* call_runtime) {
351 // Verify that the new target is a JSFunction.
352 Label end(this);
353 TNode<JSFunction> new_target_func =
355 // Fast path.
356
357 // Load the initial map and verify that it's in fact a map.
358 TNode<Object> initial_map_or_proto =
359 LoadJSFunctionPrototypeOrInitialMap(new_target_func);
360 GotoIf(TaggedIsSmi(initial_map_or_proto), call_runtime);
361 GotoIf(DoesntHaveInstanceType(CAST(initial_map_or_proto), MAP_TYPE),
362 call_runtime);
363 TNode<Map> initial_map = CAST(initial_map_or_proto);
364
365 // Fall back to runtime if the target differs from the new target's
366 // initial map constructor.
367 TNode<Object> new_target_constructor = LoadObjectField(
368 initial_map, Map::kConstructorOrBackPointerOrNativeContextOffset);
369 GotoIf(TaggedNotEqual(target, new_target_constructor), call_runtime);
370
371 TVARIABLE(HeapObject, properties);
372
373 Label instantiate_map(this), allocate_properties(this);
374 GotoIf(IsDictionaryMap(initial_map), &allocate_properties);
375 {
376 properties = EmptyFixedArrayConstant();
377 Goto(&instantiate_map);
378 }
379 BIND(&allocate_properties);
380 {
381 properties =
383 Goto(&instantiate_map);
384 }
385
386 BIND(&instantiate_map);
387 return AllocateJSObjectFromMap(initial_map, properties.value(), std::nullopt,
389}
390
392 TNode<ScopeInfo> scope_info, TNode<Uint32T> slots, TNode<Context> context,
393 ScopeType scope_type) {
394 TNode<IntPtrT> slots_intptr = Signed(ChangeUint32ToWord(slots));
397
398 // Create a new closure from the given function info in new space
399 TNode<Context> function_context =
401
404 switch (scope_type) {
405 case EVAL_SCOPE:
406 index = Context::EVAL_CONTEXT_MAP_INDEX;
407 break;
408 case FUNCTION_SCOPE:
409 index = Context::FUNCTION_CONTEXT_MAP_INDEX;
410 break;
411 default:
412 UNREACHABLE();
413 }
414 TNode<Map> map = CAST(LoadContextElement(native_context, index));
415 // Set up the header.
416 StoreMapNoWriteBarrier(function_context, map);
418 // TODO(ishell): for now, length also includes MIN_CONTEXT_SLOTS.
419 TNode<IntPtrT> length = IntPtrAdd(slots_intptr, min_context_slots);
420 StoreObjectFieldNoWriteBarrier(function_context, Context::kLengthOffset,
421 SmiTag(length));
423 scope_info);
425 context);
426
427 // Initialize the varrest of the slots to undefined.
428 TNode<Oddball> undefined = UndefinedConstant();
432 vars, start_offset, size,
433 [=, this](TNode<IntPtrT> offset) {
434 StoreObjectFieldNoWriteBarrier(function_context, offset, undefined);
435 },
437 return function_context;
438}
439
441 TNode<HeapObject> maybe_feedback_vector, TNode<TaggedIndex> slot,
443 Label call_runtime(this, Label::kDeferred), end(this);
444
445 GotoIf(IsUndefined(maybe_feedback_vector), &call_runtime);
446
448 TNode<FeedbackVector> feedback_vector = CAST(maybe_feedback_vector);
449 TNode<Object> literal_site =
450 CAST(LoadFeedbackVectorSlot(feedback_vector, slot));
451 GotoIfNot(HasBoilerplate(literal_site), &call_runtime);
452 {
453 static_assert(JSRegExp::kDataOffset == JSObject::kHeaderSize);
454 static_assert(JSRegExp::kSourceOffset ==
455 JSRegExp::kDataOffset + kTaggedSize);
456 static_assert(JSRegExp::kFlagsOffset ==
457 JSRegExp::kSourceOffset + kTaggedSize);
458 static_assert(JSRegExp::kHeaderSize ==
459 JSRegExp::kFlagsOffset + kTaggedSize);
460 static_assert(JSRegExp::kLastIndexOffset == JSRegExp::kHeaderSize);
462
463 TNode<RegExpBoilerplateDescription> boilerplate = CAST(literal_site);
465
466 // Initialize Object fields.
467 TNode<JSFunction> regexp_function = CAST(LoadContextElement(
468 LoadNativeContext(context), Context::REGEXP_FUNCTION_INDEX));
469 TNode<Map> initial_map = CAST(LoadObjectField(
470 regexp_function, JSFunction::kPrototypeOrInitialMapOffset));
471 StoreMapNoWriteBarrier(new_object, initial_map);
472 // Initialize JSReceiver fields.
473 StoreObjectFieldRoot(new_object, JSReceiver::kPropertiesOrHashOffset,
474 RootIndex::kEmptyFixedArray);
475 // Initialize JSObject fields.
476 StoreObjectFieldRoot(new_object, JSObject::kElementsOffset,
477 RootIndex::kEmptyFixedArray);
478 // Initialize JSRegExp fields.
480 new_object, JSRegExp::kDataOffset, kRegExpDataIndirectPointerTag,
482 boilerplate, RegExpBoilerplateDescription::kDataOffset,
483 kRegExpDataIndirectPointerTag)));
485 new_object, JSRegExp::kSourceOffset,
486 LoadObjectField(boilerplate,
487 RegExpBoilerplateDescription::kSourceOffset));
489 new_object, JSRegExp::kFlagsOffset,
490 LoadObjectField(boilerplate,
491 RegExpBoilerplateDescription::kFlagsOffset));
493 new_object, JSRegExp::kLastIndexOffset,
495
496 result = CAST(new_object);
497 Goto(&end);
498 }
499
500 BIND(&call_runtime);
501 {
502 result = CAST(CallRuntime(Runtime::kCreateRegExpLiteral, context,
503 maybe_feedback_vector, slot, pattern, flags));
504 Goto(&end);
505 }
506
507 BIND(&end);
508 return result.value();
509}
510
512 TNode<FeedbackVector> feedback_vector, TNode<TaggedIndex> slot,
513 TNode<Context> context, AllocationSiteMode allocation_site_mode,
514 Label* call_runtime) {
515 TNode<Object> maybe_allocation_site =
516 CAST(LoadFeedbackVectorSlot(feedback_vector, slot));
517 GotoIfNot(HasBoilerplate(maybe_allocation_site), call_runtime);
518
519 TNode<AllocationSite> allocation_site = CAST(maybe_allocation_site);
520 TNode<JSArray> boilerplate = CAST(LoadBoilerplate(allocation_site));
521
522 if (allocation_site_mode == TRACK_ALLOCATION_SITE &&
524 return CloneFastJSArray(context, boilerplate, allocation_site);
525 } else {
526 return CloneFastJSArray(context, boilerplate);
527 }
528}
529
531 TNode<FeedbackVector> feedback_vector, TNode<TaggedIndex> slot,
532 TNode<Context> context) {
533 // Array literals always have a valid AllocationSite to properly track
534 // elements transitions.
535 TNode<Object> maybe_allocation_site =
536 CAST(LoadFeedbackVectorSlot(feedback_vector, slot));
537 TVARIABLE(AllocationSite, allocation_site);
538
539 Label create_empty_array(this),
540 initialize_allocation_site(this, Label::kDeferred), done(this);
541 GotoIf(TaggedIsSmi(maybe_allocation_site), &initialize_allocation_site);
542 {
543 allocation_site = CAST(maybe_allocation_site);
544 Goto(&create_empty_array);
545 }
546 // TODO(cbruni): create the AllocationSite in CSA.
547 BIND(&initialize_allocation_site);
548 {
549 allocation_site = CreateAllocationSiteInFeedbackVector(
550 feedback_vector,
551 // TODO(v8:10047): pass slot as TaggedIndex here
553 Goto(&create_empty_array);
554 }
555
556 BIND(&create_empty_array);
557 TNode<Int32T> kind = LoadElementsKind(allocation_site.value());
559 Comment("LoadJSArrayElementsMap");
561 TNode<IntPtrT> zero_intptr = IntPtrConstant(0);
562 TNode<Smi> zero = SmiConstant(0);
563 Comment("Allocate JSArray");
564 std::optional<TNode<AllocationSite>> site =
566 ? std::make_optional(allocation_site.value())
567 : std::nullopt;
569 array_map, zero_intptr, zero, site);
570
571 Goto(&done);
572 BIND(&done);
573
574 return result;
575}
576
578 TNode<FeedbackVector> feedback_vector, TNode<TaggedIndex> slot,
579 Label* call_runtime) {
580 TNode<Object> maybe_allocation_site =
581 CAST(LoadFeedbackVectorSlot(feedback_vector, slot));
582 GotoIfNot(HasBoilerplate(maybe_allocation_site), call_runtime);
583
584 TNode<AllocationSite> allocation_site = CAST(maybe_allocation_site);
585 TNode<JSObject> boilerplate = LoadBoilerplate(allocation_site);
586 return CreateShallowObjectLiteral(allocation_site, boilerplate, call_runtime);
587}
588
590 TNode<AllocationSite> allocation_site, TNode<JSObject> boilerplate,
591 Label* call_runtime, bool bailout_if_dictionary_properties) {
592 TNode<Map> boilerplate_map = LoadMap(boilerplate);
593 CSA_DCHECK(this, IsJSObjectMap(boilerplate_map));
594
595 TVARIABLE(HeapObject, var_properties);
596 {
597 TNode<Uint32T> bit_field_3 = LoadMapBitField3(boilerplate_map);
598 GotoIf(IsSetWord32<Map::Bits3::IsDeprecatedBit>(bit_field_3), call_runtime);
599 // Directly copy over the property store for dict-mode boilerplates.
600 Label if_dictionary(this), if_fast(this), done(this);
602 &if_dictionary, &if_fast);
603 BIND(&if_dictionary);
604 {
605 if (bailout_if_dictionary_properties) {
606 Goto(call_runtime);
607 } else {
608 Comment("Copy dictionary properties");
610 var_properties =
612 } else {
613 var_properties = CopyNameDictionary(
614 CAST(LoadSlowProperties(boilerplate)), call_runtime);
615 }
616 // Slow objects have no in-object properties.
617 Goto(&done);
618 }
619 }
620 BIND(&if_fast);
621 {
622 // TODO(cbruni): support copying out-of-object properties.
623 // (CreateObjectFromSlowBoilerplate needs to handle them, too.)
624 TNode<HeapObject> boilerplate_properties =
625 LoadFastProperties(boilerplate);
626 GotoIfNot(IsEmptyFixedArray(boilerplate_properties), call_runtime);
627 var_properties = EmptyFixedArrayConstant();
628 Goto(&done);
629 }
630 BIND(&done);
631 }
632
633 TVARIABLE(FixedArrayBase, var_elements);
634 {
635 // Copy the elements backing store, assuming that it's flat.
636 Label if_empty_fixed_array(this), if_copy_elements(this), done(this);
637 TNode<FixedArrayBase> boilerplate_elements = LoadElements(boilerplate);
638 Branch(IsEmptyFixedArray(boilerplate_elements), &if_empty_fixed_array,
639 &if_copy_elements);
640
641 BIND(&if_empty_fixed_array);
642 var_elements = boilerplate_elements;
643 Goto(&done);
644
645 BIND(&if_copy_elements);
646 CSA_DCHECK(this, Word32BinaryNot(
647 IsFixedCOWArrayMap(LoadMap(boilerplate_elements))));
649 var_elements = CloneFixedArray(boilerplate_elements, flags);
650 Goto(&done);
651 BIND(&done);
652 }
653
654 // Ensure new-space allocation for a fresh JSObject so we can skip write
655 // barriers when copying all object fields.
657 TNode<IntPtrT> instance_size =
659 TNode<IntPtrT> aligned_instance_size =
660 AlignToAllocationAlignment(instance_size);
661 TNode<IntPtrT> allocation_size = instance_size;
662 bool needs_allocation_memento = v8_flags.allocation_site_pretenuring;
663 if (needs_allocation_memento) {
665 // Prepare for inner-allocating the AllocationMemento.
666 allocation_size = IntPtrAdd(aligned_instance_size,
668 sizeof(AllocationMemento))));
669 }
670
671 TNode<HeapObject> copy =
673 {
674 Comment("Initialize Literal Copy");
675 // Initialize Object fields.
676 StoreMapNoWriteBarrier(copy, boilerplate_map);
677 StoreObjectFieldNoWriteBarrier(copy, JSObject::kPropertiesOrHashOffset,
678 var_properties.value());
679 StoreObjectFieldNoWriteBarrier(copy, JSObject::kElementsOffset,
680 var_elements.value());
681 }
682
683 // Initialize the AllocationMemento before potential GCs due to heap number
684 // allocation when copying the in-object properties.
685 if (needs_allocation_memento) {
686 InitializeAllocationMemento(copy, aligned_instance_size, allocation_site);
687 }
688
689 {
690 // Copy over in-object properties.
691 Label continue_with_write_barrier(this), done_init(this);
692 TVARIABLE(IntPtrT, offset, IntPtrConstant(JSObject::kHeaderSize));
693 {
694 Comment("Copy in-object properties fast");
695 Label continue_fast(this, &offset);
696 Branch(IntPtrEqual(offset.value(), instance_size), &done_init,
697 &continue_fast);
698 BIND(&continue_fast);
699 TNode<Object> field = LoadObjectField(boilerplate, offset.value());
700 Label store_field(this);
701 GotoIf(TaggedIsSmi(field), &store_field);
702 // TODO(leszeks): Read the field descriptor to decide if this heap
703 // number is mutable or not.
704 GotoIf(IsHeapNumber(CAST(field)), &continue_with_write_barrier);
705 Goto(&store_field);
706 BIND(&store_field);
707 StoreObjectFieldNoWriteBarrier(copy, offset.value(), field);
709 Branch(WordNotEqual(offset.value(), instance_size), &continue_fast,
710 &done_init);
711 }
712
713 // Continue initializing the literal after seeing the first sub-object
714 // potentially causing allocation. In this case we prepare the new literal
715 // by copying all pending fields over from the boilerplate and emit full
716 // write barriers from here on.
717 BIND(&continue_with_write_barrier);
718 {
719 Comment("Copy in-object properties slow");
721 offset.value(), instance_size,
722 [=, this](TNode<IntPtrT> offset) {
723 // TODO(ishell): value decompression is not necessary here.
724 TNode<Object> field = LoadObjectField(boilerplate, offset);
725 StoreObjectFieldNoWriteBarrier(copy, offset, field);
726 },
728 CopyMutableHeapNumbersInObject(copy, offset.value(), instance_size);
729 Goto(&done_init);
730 }
731 BIND(&done_init);
732 }
733 return copy;
734}
735
736// Used by the CreateEmptyObjectLiteral bytecode and the Object constructor.
738 TNode<Context> context) {
741 // Ensure that slack tracking is disabled for the map.
742 static_assert(Map::kNoSlackTracking == 0);
744 LoadMapBitField3(map)));
745 TNode<FixedArray> empty_fixed_array = EmptyFixedArrayConstant();
747 AllocateJSObjectFromMap(map, empty_fixed_array, empty_fixed_array);
748 return result;
749}
750
752 TNode<HeapObject> copy, TNode<IntPtrT> start_offset,
753 TNode<IntPtrT> end_offset) {
754 // Iterate over all object properties of a freshly copied object and
755 // duplicate mutable heap numbers.
756 Comment("Copy mutable HeapNumber values");
758 start_offset, end_offset,
759 [=, this](TNode<IntPtrT> offset) {
760 TNode<Object> field = LoadObjectField(copy, offset);
761 Label copy_heap_number(this, Label::kDeferred), continue_loop(this);
762 // We only have to clone complex field values.
763 GotoIf(TaggedIsSmi(field), &continue_loop);
764 // TODO(leszeks): Read the field descriptor to decide if this heap
765 // number is mutable or not.
766 Branch(IsHeapNumber(CAST(field)), &copy_heap_number, &continue_loop);
767 BIND(&copy_heap_number);
768 {
769 TNode<Float64T> double_value = LoadHeapNumberValue(CAST(field));
770 TNode<HeapNumber> heap_number =
771 AllocateHeapNumberWithValue(double_value);
772 StoreObjectField(copy, offset, heap_number);
773 Goto(&continue_loop);
774 }
775 BIND(&continue_loop);
776 },
778}
779
781
782} // namespace internal
783} // namespace v8
#define BIND(label)
#define TVARIABLE(...)
#define CSA_DCHECK(csa,...)
#define TF_BUILTIN(Name, AssemblerBase)
Builtins::Kind kind
Definition builtins.cc:40
#define BUILTIN_CODE(isolate, name)
Definition builtins.h:45
constexpr UnderlyingType & value() &
static void Generate_CallOrConstructForwardVarargs(MacroAssembler *masm, CallOrConstructMode mode, Builtin target_builtin)
static void Generate_CallOrConstructVarargs(MacroAssembler *masm, Builtin target_builtin)
static void Generate_ConstructForwardAllArgsImpl(MacroAssembler *masm, ForwardWhichFrame which_frame)
void BuildConstructForwardAllArgs(TNode< JSAny > target, TNode< JSAny > new_target, const LazyNode< Context > &context, const LazyNode< Union< Undefined, FeedbackVector > > &feedback_vector, TNode< TaggedIndex > slot)
void BuildConstructWithSpread(TNode< JSAny > target, TNode< JSAny > new_target, TNode< JSAny > spread, TNode< Int32T > argc, const LazyNode< Context > &context, const LazyNode< Union< Undefined, FeedbackVector > > &feedback_vector, TNode< TaggedIndex > slot, UpdateFeedbackMode mode)
void BuildConstruct(TNode< JSAny > target, TNode< JSAny > new_target, TNode< Int32T > argc, const LazyNode< Context > &context, const LazyNode< Union< Undefined, FeedbackVector > > &feedback_vector, TNode< UintPtrT > slot, UpdateFeedbackMode mode)
void CallOrConstructWithSpread(TNode< JSAny > target, std::optional< TNode< Object > > new_target, TNode< JSAny > spread, TNode< Int32T > args_count, TNode< Context > context)
TNode< JSArray > AllocateJSArray(ElementsKind kind, TNode< Map > array_map, TNode< IntPtrT > capacity, TNode< Smi > length, std::optional< TNode< AllocationSite > > allocation_site, AllocationFlags allocation_flags=AllocationFlag::kNone)
TNode< WordT > TimesTaggedSize(TNode< WordT > value)
void InitializeAllocationMemento(TNode< HeapObject > base, TNode< IntPtrT > base_allocation_size, TNode< AllocationSite > allocation_site)
TNode< BoolT > IsJSObjectMap(TNode< Map > map)
TNode< SwissNameDictionary > CopySwissNameDictionary(TNode< SwissNameDictionary > original)
TNode< HeapObject > LoadSlowProperties(TNode< JSReceiver > object)
TNode< HeapObject > AllocateInNewSpace(TNode< IntPtrT > size, AllocationFlags flags=AllocationFlag::kNone)
TNode< TrustedObject > LoadTrustedPointerFromObject(TNode< HeapObject > object, int offset, IndirectPointerTag tag)
TNode< BoolT > DoesntHaveInstanceType(TNode< HeapObject > object, InstanceType type)
TNode< Smi > SmiTag(TNode< IntPtrT > value)
TNode< HeapObject > Allocate(TNode< IntPtrT > size, AllocationFlags flags=AllocationFlag::kNone)
void StoreObjectFieldRoot(TNode< HeapObject > object, int offset, RootIndex root)
TNode< FixedArrayBase > LoadElements(TNode< JSObject > object)
TNode< T > LoadObjectField(TNode< HeapObject > object, int offset)
TNode< BoolT > TaggedNotEqual(TNode< AnyTaggedT > a, TNode< AnyTaggedT > b)
TNode< Uint32T > LoadMapBitField3(TNode< Map > map)
TNode< JSObject > LoadBoilerplate(TNode< AllocationSite > allocation_site)
TNode< BoolT > IsSetWord32(TNode< Word32T > word32)
TNode< HeapObject > LoadFastProperties(TNode< JSReceiver > object, bool skip_empty_check=false)
TNode< Map > LoadJSArrayElementsMap(ElementsKind kind, TNode< NativeContext > native_context)
void BuildFastLoop(const VariableList &vars, TVariable< TIndex > &var_index, TNode< TIndex > start_index, TNode< TIndex > end_index, const FastLoopBody< TIndex > &body, TNode< TIndex > increment, LoopUnrollingMode unrolling_mode, IndexAdvanceMode advance_mode, IndexAdvanceDirection advance_direction)
TNode< Int32T > LoadElementsKind(TNode< HeapObject > object)
TNode< JSArray > CloneFastJSArray(TNode< Context > context, TNode< JSArray > array, std::optional< TNode< AllocationSite > > allocation_site=std::nullopt, HoleConversionMode convert_holes=HoleConversionMode::kDontConvert)
std::function< TNode< T >()> LazyNode
TNode< BoolT > IsClearWord32(TNode< Word32T > word32)
void StoreObjectFieldNoWriteBarrier(TNode< HeapObject > object, TNode< IntPtrT > offset, TNode< T > value)
TNode< IntPtrT > ElementOffsetFromIndex(TNode< TIndex > index, ElementsKind kind, int base_size=0)
TNode< HeapNumber > AllocateHeapNumberWithValue(TNode< Float64T > value)
TNode< JSFunction > HeapObjectToJSFunctionWithPrototypeSlot(TNode< HeapObject > heap_object, Label *fail)
void StoreTrustedPointerField(TNode< HeapObject > object, int offset, IndirectPointerTag tag, TNode< ExposedTrustedObject > value)
TNode< NativeContext > LoadNativeContext(TNode< Context > context)
TNode< BoolT > TaggedIsSmi(TNode< MaybeObject > a)
TNode< Float64T > LoadHeapNumberValue(TNode< HeapObject > object)
TNode< Map > LoadMap(TNode< HeapObject > object)
TNode< BoolT > IsDictionaryMap(TNode< Map > map)
TNode< IntPtrT > TaggedIndexToIntPtr(TNode< TaggedIndex > value)
TNode< JSObject > AllocateJSObjectFromMap(TNode< Map > map, std::optional< TNode< HeapObject > > properties=std::nullopt, std::optional< TNode< FixedArray > > elements=std::nullopt, AllocationFlags flags=AllocationFlag::kNone, SlackTrackingMode slack_tracking_mode=kNoSlackTracking)
TNode< IntPtrT > AlignToAllocationAlignment(TNode< IntPtrT > value)
TNode< PropertyDictionary > AllocatePropertyDictionary(int at_least_space_for)
TNode< NameDictionary > CopyNameDictionary(TNode< NameDictionary > dictionary, Label *large_object_fallback)
void StoreObjectField(TNode< HeapObject > object, int offset, TNode< Smi > value)
TNode< BoolT > HasBoilerplate(TNode< Object > maybe_literal_site)
TNode< IntPtrT > LoadMapInstanceSizeInWords(TNode< Map > map)
TNode< MaybeObject > LoadFeedbackVectorSlot(TNode< FeedbackVector > feedback_vector, TNode< TIndex > slot, int additional_offset=0)
TNode< Map > LoadObjectFunctionInitialMap(TNode< NativeContext > native_context)
TNode< AllocationSite > CreateAllocationSiteInFeedbackVector(TNode< FeedbackVector > feedback_vector, TNode< UintPtrT > slot)
TNode< FixedArrayBase > CloneFixedArray(TNode< FixedArrayBase > source, ExtractFixedArrayFlags flags=ExtractFixedArrayFlag::kAllFixedArraysDontCopyCOW)
TNode< TaggedIndex > IntPtrToTaggedIndex(TNode< IntPtrT > value)
void StoreMapNoWriteBarrier(TNode< HeapObject > object, RootIndex map_root_index)
TNode< JSObject > CreateEmptyObjectLiteral(TNode< Context > context)
TNode< JSObject > FastNewObject(TNode< Context > context, TNode< JSFunction > target, TNode< JSReceiver > new_target)
TNode< HeapObject > CreateShallowObjectLiteral(TNode< FeedbackVector > feedback_vector, TNode< TaggedIndex > slot, Label *call_runtime)
TNode< Context > FastNewFunctionContext(TNode< ScopeInfo > scope_info, TNode< Uint32T > slots, TNode< Context > context, ScopeType scope_type)
void CopyMutableHeapNumbersInObject(TNode< HeapObject > copy, TNode< IntPtrT > start_offset, TNode< IntPtrT > instance_size)
TNode< JSArray > CreateShallowArrayLiteral(TNode< FeedbackVector > feedback_vector, TNode< TaggedIndex > slot, TNode< Context > context, AllocationSiteMode allocation_site_mode, Label *call_runtime)
TNode< JSRegExp > CreateRegExpLiteral(TNode< HeapObject > maybe_feedback_vector, TNode< TaggedIndex > slot, TNode< Object > pattern, TNode< Smi > flags, TNode< Context > context)
TNode< JSArray > CreateEmptyArrayLiteral(TNode< FeedbackVector > feedback_vector, TNode< TaggedIndex > slot, TNode< Context > context)
static const int FIRST_FUNCTION_MAP_INDEX
Definition contexts.h:570
static const int kScopeInfoOffset
Definition contexts.h:491
static const int kTodoHeaderSize
Definition contexts.h:497
static const int LAST_FUNCTION_MAP_INDEX
Definition contexts.h:571
static const int kPreviousOffset
Definition contexts.h:492
static constexpr int kSizeWithoutPrototype
static const int kMaxInstanceSize
Definition js-objects.h:945
static constexpr int Size()
Definition js-regexp.h:119
static constexpr int kLastIndexOffset
Definition js-regexp.h:108
static constexpr int kInitialLastIndexValue
Definition js-regexp.h:111
static const int kNoSlackTracking
Definition map.h:349
static const int kInitialCapacity
Definition dictionary.h:250
TNode< IntPtrT > IntPtrAdd(TNode< IntPtrT > left, TNode< IntPtrT > right)
TNode< Int32T > Signed(TNode< Word32T > x)
void Comment(MessageWithSourceLocation message, Args &&... args)
TNode< IntPtrT > IntPtrConstant(intptr_t value)
TNode< UintPtrT > ChangeUint32ToWord(TNode< Word32T > value)
TNode< T > UncheckedCast(Node *value)
void GotoIfNot(TNode< IntegralT > condition, Label *false_label, GotoHint goto_hint=GotoHint::kNone)
TNode< Uint32T > Unsigned(TNode< Word32T > x)
TNode< Smi > SmiConstant(Tagged< Smi > value)
void GotoIf(TNode< IntegralT > condition, Label *true_label, GotoHint goto_hint=GotoHint::kNone)
TNode< BoolT > IntPtrEqual(TNode< WordT > left, TNode< WordT > right)
void TailCallBuiltin(Builtin id, TNode< Object > context, TArgs... args)
TNode< BoolT > WordNotEqual(TNode< WordT > left, TNode< WordT > right)
TNode< T > CallRuntime(Runtime::FunctionId function, TNode< Object > context, TArgs... args)
void Branch(TNode< IntegralT > condition, Label *true_label, Label *false_label, BranchHint branch_hint=BranchHint::kNone)
#define CAST(x)
#define V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL
Definition globals.h:242
#define ALIGN_TO_ALLOCATION_ALIGNMENT(value)
Definition globals.h:1796
int end
DirectHandle< Object > new_target
Definition execution.cc:75
#define V8_ALLOCATION_SITE_TRACKING_BOOL
Isolate * isolate
int32_t offset
TNode< Context > context
std::string pattern
ZoneVector< RpoNumber > & result
constexpr int kTaggedSize
Definition globals.h:542
constexpr int kMaxRegularHeapObjectSize
Definition globals.h:680
@ TRACK_ALLOCATION_SITE
Definition globals.h:1936
constexpr JSDispatchHandle kNullJSDispatchHandle(0)
V8_EXPORT_PRIVATE FlagValues v8_flags
ElementsKind GetInitialFastElementsKind()
!IsContextMap !IsContextMap native_context
Definition map-inl.h:877
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485