Line data Source code
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 :
5 : #include "src/builtins/builtins-constructor-gen.h"
6 :
7 : #include "src/ast/ast.h"
8 : #include "src/builtins/builtins-call-gen.h"
9 : #include "src/builtins/builtins-constructor.h"
10 : #include "src/builtins/builtins-utils-gen.h"
11 : #include "src/builtins/builtins.h"
12 : #include "src/code-factory.h"
13 : #include "src/code-stub-assembler.h"
14 : #include "src/counters.h"
15 : #include "src/interface-descriptors.h"
16 : #include "src/objects-inl.h"
17 :
18 : namespace v8 {
19 : namespace internal {
20 :
21 31 : void Builtins::Generate_ConstructVarargs(MacroAssembler* masm) {
22 : Generate_CallOrConstructVarargs(masm,
23 31 : BUILTIN_CODE(masm->isolate(), Construct));
24 31 : }
25 :
26 31 : void Builtins::Generate_ConstructForwardVarargs(MacroAssembler* masm) {
27 : Generate_CallOrConstructForwardVarargs(
28 : masm, CallOrConstructMode::kConstruct,
29 31 : BUILTIN_CODE(masm->isolate(), Construct));
30 31 : }
31 :
32 31 : void Builtins::Generate_ConstructFunctionForwardVarargs(MacroAssembler* masm) {
33 : Generate_CallOrConstructForwardVarargs(
34 : masm, CallOrConstructMode::kConstruct,
35 31 : BUILTIN_CODE(masm->isolate(), ConstructFunction));
36 31 : }
37 :
38 124 : TF_BUILTIN(ConstructWithArrayLike, CallOrConstructBuiltinsAssembler) {
39 : Node* target = Parameter(ConstructWithArrayLikeDescriptor::kTarget);
40 : Node* new_target = Parameter(ConstructWithArrayLikeDescriptor::kNewTarget);
41 : Node* arguments_list =
42 : Parameter(ConstructWithArrayLikeDescriptor::kArgumentsList);
43 : Node* context = Parameter(ConstructWithArrayLikeDescriptor::kContext);
44 31 : CallOrConstructWithArrayLike(target, new_target, arguments_list, context);
45 31 : }
46 :
47 124 : TF_BUILTIN(ConstructWithSpread, CallOrConstructBuiltinsAssembler) {
48 : Node* target = Parameter(ConstructWithSpreadDescriptor::kTarget);
49 : Node* new_target = Parameter(ConstructWithSpreadDescriptor::kNewTarget);
50 : Node* spread = Parameter(ConstructWithSpreadDescriptor::kSpread);
51 : Node* args_count = Parameter(ConstructWithSpreadDescriptor::kArgumentsCount);
52 : Node* context = Parameter(ConstructWithSpreadDescriptor::kContext);
53 31 : CallOrConstructWithSpread(target, new_target, spread, args_count, context);
54 31 : }
55 :
56 : typedef compiler::Node Node;
57 :
58 124 : Node* ConstructorBuiltinsAssembler::EmitFastNewClosure(Node* shared_info,
59 : Node* feedback_vector,
60 : Node* slot,
61 : Node* context) {
62 124 : Isolate* isolate = this->isolate();
63 : Factory* factory = isolate->factory();
64 124 : IncrementCounter(isolate->counters()->fast_new_closure_total(), 1);
65 :
66 : Node* compiler_hints =
67 : LoadObjectField(shared_info, SharedFunctionInfo::kCompilerHintsOffset,
68 124 : MachineType::Uint32());
69 :
70 : // The calculation of |function_map_index| must be in sync with
71 : // SharedFunctionInfo::function_map_index().
72 : Node* function_map_index =
73 : IntPtrAdd(DecodeWordFromWord32<SharedFunctionInfo::FunctionMapIndexBits>(
74 : compiler_hints),
75 496 : IntPtrConstant(Context::FIRST_FUNCTION_MAP_INDEX));
76 : CSA_ASSERT(this, UintPtrLessThanOrEqual(
77 : function_map_index,
78 : IntPtrConstant(Context::LAST_FUNCTION_MAP_INDEX)));
79 :
80 : // Get the function map in the current native context and set that
81 : // as the map of the allocated object.
82 248 : Node* native_context = LoadNativeContext(context);
83 248 : Node* function_map = LoadContextElement(native_context, function_map_index);
84 :
85 : // Create a new closure from the given function info in new space
86 : Node* instance_size_in_bytes =
87 248 : TimesPointerSize(LoadMapInstanceSize(function_map));
88 124 : Node* result = Allocate(instance_size_in_bytes);
89 124 : StoreMapNoWriteBarrier(result, function_map);
90 : InitializeJSObjectBody(result, function_map, instance_size_in_bytes,
91 124 : JSFunction::kSizeWithoutPrototype);
92 :
93 : // Initialize the rest of the function.
94 : Node* empty_fixed_array = HeapConstant(factory->empty_fixed_array());
95 : StoreObjectFieldNoWriteBarrier(result, JSObject::kPropertiesOrHashOffset,
96 124 : empty_fixed_array);
97 : StoreObjectFieldNoWriteBarrier(result, JSObject::kElementsOffset,
98 124 : empty_fixed_array);
99 : {
100 : // Set function prototype if necessary.
101 124 : Label done(this), init_prototype(this);
102 : Branch(IsFunctionWithPrototypeSlotMap(function_map), &init_prototype,
103 248 : &done);
104 :
105 124 : BIND(&init_prototype);
106 : StoreObjectFieldNoWriteBarrier(
107 248 : result, JSFunction::kPrototypeOrInitialMapOffset, TheHoleConstant());
108 124 : Goto(&done);
109 :
110 248 : BIND(&done);
111 : }
112 :
113 : Node* literals_cell = LoadFeedbackVectorSlot(
114 124 : feedback_vector, slot, 0, CodeStubAssembler::SMI_PARAMETERS);
115 : {
116 : // Bump the closure counter encoded in the cell's map.
117 248 : Node* cell_map = LoadMap(literals_cell);
118 124 : Label no_closures(this), one_closure(this), cell_done(this);
119 :
120 248 : GotoIf(IsNoClosuresCellMap(cell_map), &no_closures);
121 248 : GotoIf(IsOneClosureCellMap(cell_map), &one_closure);
122 : CSA_ASSERT(this, IsManyClosuresCellMap(cell_map), cell_map, literals_cell,
123 : feedback_vector, slot);
124 124 : Goto(&cell_done);
125 :
126 124 : BIND(&no_closures);
127 124 : StoreMapNoWriteBarrier(literals_cell, Heap::kOneClosureCellMapRootIndex);
128 124 : Goto(&cell_done);
129 :
130 124 : BIND(&one_closure);
131 124 : StoreMapNoWriteBarrier(literals_cell, Heap::kManyClosuresCellMapRootIndex);
132 124 : Goto(&cell_done);
133 :
134 248 : BIND(&cell_done);
135 : }
136 : StoreObjectFieldNoWriteBarrier(result, JSFunction::kFeedbackVectorOffset,
137 124 : literals_cell);
138 : StoreObjectFieldNoWriteBarrier(result, JSFunction::kSharedFunctionInfoOffset,
139 124 : shared_info);
140 124 : StoreObjectFieldNoWriteBarrier(result, JSFunction::kContextOffset, context);
141 : Handle<Code> lazy_builtin_handle(
142 : isolate->builtins()->builtin(Builtins::kCompileLazy));
143 : Node* lazy_builtin = HeapConstant(lazy_builtin_handle);
144 124 : StoreObjectFieldNoWriteBarrier(result, JSFunction::kCodeOffset, lazy_builtin);
145 124 : return result;
146 : }
147 :
148 0 : Node* ConstructorBuiltinsAssembler::NotHasBoilerplate(Node* literal_site) {
149 744 : return TaggedIsSmi(literal_site);
150 : }
151 :
152 0 : Node* ConstructorBuiltinsAssembler::LoadAllocationSiteBoilerplate(Node* site) {
153 : CSA_ASSERT(this, IsAllocationSite(site));
154 : return LoadObjectField(site,
155 0 : AllocationSite::kTransitionInfoOrBoilerplateOffset);
156 : }
157 :
158 124 : TF_BUILTIN(FastNewClosure, ConstructorBuiltinsAssembler) {
159 : Node* shared = Parameter(FastNewClosureDescriptor::kSharedFunctionInfo);
160 : Node* context = Parameter(FastNewClosureDescriptor::kContext);
161 : Node* vector = Parameter(FastNewClosureDescriptor::kVector);
162 : Node* slot = Parameter(FastNewClosureDescriptor::kSlot);
163 62 : Return(EmitFastNewClosure(shared, vector, slot, context));
164 31 : }
165 :
166 124 : TF_BUILTIN(FastNewObject, ConstructorBuiltinsAssembler) {
167 : Node* context = Parameter(Descriptor::kContext);
168 : Node* target = Parameter(Descriptor::kTarget);
169 : Node* new_target = Parameter(Descriptor::kNewTarget);
170 :
171 : Label call_runtime(this);
172 :
173 31 : Node* result = EmitFastNewObject(context, target, new_target, &call_runtime);
174 31 : Return(result);
175 :
176 31 : BIND(&call_runtime);
177 31 : TailCallRuntime(Runtime::kNewObject, context, target, new_target);
178 31 : }
179 :
180 217 : Node* ConstructorBuiltinsAssembler::EmitFastNewObject(Node* context,
181 : Node* target,
182 : Node* new_target) {
183 217 : VARIABLE(var_obj, MachineRepresentation::kTagged);
184 217 : Label call_runtime(this), end(this);
185 :
186 217 : Node* result = EmitFastNewObject(context, target, new_target, &call_runtime);
187 217 : var_obj.Bind(result);
188 217 : Goto(&end);
189 :
190 217 : BIND(&call_runtime);
191 217 : var_obj.Bind(CallRuntime(Runtime::kNewObject, context, target, new_target));
192 217 : Goto(&end);
193 :
194 217 : BIND(&end);
195 434 : return var_obj.value();
196 : }
197 :
198 248 : Node* ConstructorBuiltinsAssembler::EmitFastNewObject(Node* context,
199 : Node* target,
200 : Node* new_target,
201 : Label* call_runtime) {
202 : CSA_ASSERT(this, HasInstanceType(target, JS_FUNCTION_TYPE));
203 : CSA_ASSERT(this, IsJSReceiver(new_target));
204 :
205 : // Verify that the new target is a JSFunction.
206 496 : Label fast(this), end(this);
207 496 : GotoIf(HasInstanceType(new_target, JS_FUNCTION_TYPE), &fast);
208 248 : Goto(call_runtime);
209 :
210 248 : BIND(&fast);
211 :
212 : // Load the initial map and verify that it's in fact a map.
213 : Node* initial_map =
214 : LoadObjectField(new_target, JSFunction::kPrototypeOrInitialMapOffset);
215 496 : GotoIf(TaggedIsSmi(initial_map), call_runtime);
216 496 : GotoIf(DoesntHaveInstanceType(initial_map, MAP_TYPE), call_runtime);
217 :
218 : // Fall back to runtime if the target differs from the new target's
219 : // initial map constructor.
220 : Node* new_target_constructor =
221 : LoadObjectField(initial_map, Map::kConstructorOrBackPointerOffset);
222 496 : GotoIf(WordNotEqual(target, new_target_constructor), call_runtime);
223 :
224 496 : VARIABLE(properties, MachineRepresentation::kTagged);
225 :
226 248 : Label instantiate_map(this), allocate_properties(this);
227 496 : GotoIf(IsDictionaryMap(initial_map), &allocate_properties);
228 : {
229 496 : properties.Bind(EmptyFixedArrayConstant());
230 248 : Goto(&instantiate_map);
231 : }
232 248 : BIND(&allocate_properties);
233 : {
234 248 : properties.Bind(AllocateNameDictionary(NameDictionary::kInitialCapacity));
235 248 : Goto(&instantiate_map);
236 : }
237 :
238 248 : BIND(&instantiate_map);
239 :
240 248 : Node* object = AllocateJSObjectFromMap(initial_map, properties.value());
241 :
242 : // Perform in-object slack tracking if requested.
243 248 : HandleSlackTracking(context, object, initial_map, JSObject::kHeaderSize);
244 248 : return object;
245 : }
246 :
247 248 : Node* ConstructorBuiltinsAssembler::EmitFastNewFunctionContext(
248 : Node* function, Node* slots, Node* context, ScopeType scope_type) {
249 496 : slots = ChangeUint32ToWord(slots);
250 :
251 : // TODO(ishell): Use CSA::OptimalParameterMode() here.
252 : ParameterMode mode = INTPTR_PARAMETERS;
253 496 : Node* min_context_slots = IntPtrConstant(Context::MIN_CONTEXT_SLOTS);
254 496 : Node* length = IntPtrAdd(slots, min_context_slots);
255 248 : Node* size = GetFixedArrayAllocationSize(length, PACKED_ELEMENTS, mode);
256 :
257 : // Create a new closure from the given function info in new space
258 248 : Node* function_context = AllocateInNewSpace(size);
259 :
260 : Heap::RootListIndex context_type;
261 248 : switch (scope_type) {
262 : case EVAL_SCOPE:
263 : context_type = Heap::kEvalContextMapRootIndex;
264 : break;
265 : case FUNCTION_SCOPE:
266 : context_type = Heap::kFunctionContextMapRootIndex;
267 124 : break;
268 : default:
269 0 : UNREACHABLE();
270 : }
271 248 : StoreMapNoWriteBarrier(function_context, context_type);
272 : StoreObjectFieldNoWriteBarrier(function_context, Context::kLengthOffset,
273 496 : SmiTag(length));
274 :
275 : // Set up the fixed slots.
276 : StoreFixedArrayElement(function_context, Context::CLOSURE_INDEX, function,
277 248 : SKIP_WRITE_BARRIER);
278 : StoreFixedArrayElement(function_context, Context::PREVIOUS_INDEX, context,
279 248 : SKIP_WRITE_BARRIER);
280 : StoreFixedArrayElement(function_context, Context::EXTENSION_INDEX,
281 496 : TheHoleConstant(), SKIP_WRITE_BARRIER);
282 :
283 : // Copy the native context from the previous context.
284 496 : Node* native_context = LoadNativeContext(context);
285 : StoreFixedArrayElement(function_context, Context::NATIVE_CONTEXT_INDEX,
286 248 : native_context, SKIP_WRITE_BARRIER);
287 :
288 : // Initialize the rest of the slots to undefined.
289 496 : Node* undefined = UndefinedConstant();
290 : BuildFastFixedArrayForEach(
291 : function_context, PACKED_ELEMENTS, min_context_slots, length,
292 : [this, undefined](Node* context, Node* offset) {
293 : StoreNoWriteBarrier(MachineRepresentation::kTagged, context, offset,
294 248 : undefined);
295 : },
296 496 : mode);
297 :
298 248 : return function_context;
299 : }
300 :
301 124 : TF_BUILTIN(FastNewFunctionContextEval, ConstructorBuiltinsAssembler) {
302 : Node* function = Parameter(FastNewFunctionContextDescriptor::kFunction);
303 : Node* slots = Parameter(FastNewFunctionContextDescriptor::kSlots);
304 : Node* context = Parameter(FastNewFunctionContextDescriptor::kContext);
305 : Return(EmitFastNewFunctionContext(function, slots, context,
306 62 : ScopeType::EVAL_SCOPE));
307 31 : }
308 :
309 124 : TF_BUILTIN(FastNewFunctionContextFunction, ConstructorBuiltinsAssembler) {
310 : Node* function = Parameter(FastNewFunctionContextDescriptor::kFunction);
311 : Node* slots = Parameter(FastNewFunctionContextDescriptor::kSlots);
312 : Node* context = Parameter(FastNewFunctionContextDescriptor::kContext);
313 : Return(EmitFastNewFunctionContext(function, slots, context,
314 62 : ScopeType::FUNCTION_SCOPE));
315 31 : }
316 :
317 124 : Node* ConstructorBuiltinsAssembler::EmitCreateRegExpLiteral(
318 : Node* feedback_vector, Node* slot, Node* pattern, Node* flags,
319 : Node* context) {
320 248 : Label call_runtime(this, Label::kDeferred), end(this);
321 :
322 248 : VARIABLE(result, MachineRepresentation::kTagged);
323 : Node* literal_site =
324 124 : LoadFeedbackVectorSlot(feedback_vector, slot, 0, INTPTR_PARAMETERS);
325 124 : GotoIf(NotHasBoilerplate(literal_site), &call_runtime);
326 : {
327 : Node* boilerplate = literal_site;
328 : CSA_ASSERT(this, IsJSRegExp(boilerplate));
329 : int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
330 124 : Node* copy = Allocate(size);
331 992 : for (int offset = 0; offset < size; offset += kPointerSize) {
332 : Node* value = LoadObjectField(boilerplate, offset);
333 868 : StoreObjectFieldNoWriteBarrier(copy, offset, value);
334 : }
335 124 : result.Bind(copy);
336 124 : Goto(&end);
337 : }
338 :
339 124 : BIND(&call_runtime);
340 : {
341 : result.Bind(CallRuntime(Runtime::kCreateRegExpLiteral, context,
342 248 : feedback_vector, SmiTag(slot), pattern, flags));
343 124 : Goto(&end);
344 : }
345 :
346 124 : BIND(&end);
347 248 : return result.value();
348 : }
349 :
350 155 : TF_BUILTIN(CreateRegExpLiteral, ConstructorBuiltinsAssembler) {
351 : Node* feedback_vector = Parameter(Descriptor::kFeedbackVector);
352 62 : Node* slot = SmiUntag(Parameter(Descriptor::kSlot));
353 : Node* pattern = Parameter(Descriptor::kPattern);
354 : Node* flags = Parameter(Descriptor::kFlags);
355 : Node* context = Parameter(Descriptor::kContext);
356 : Node* result =
357 31 : EmitCreateRegExpLiteral(feedback_vector, slot, pattern, flags, context);
358 31 : Return(result);
359 31 : }
360 :
361 124 : Node* ConstructorBuiltinsAssembler::EmitCreateShallowArrayLiteral(
362 : Node* feedback_vector, Node* slot, Node* context, Label* call_runtime,
363 : AllocationSiteMode allocation_site_mode) {
364 248 : Label zero_capacity(this), cow_elements(this), fast_elements(this),
365 124 : return_result(this);
366 248 : VARIABLE(result, MachineRepresentation::kTagged);
367 :
368 : Node* allocation_site =
369 124 : LoadFeedbackVectorSlot(feedback_vector, slot, 0, INTPTR_PARAMETERS);
370 124 : GotoIf(NotHasBoilerplate(allocation_site), call_runtime);
371 :
372 : Node* boilerplate = LoadAllocationSiteBoilerplate(allocation_site);
373 : allocation_site =
374 124 : allocation_site_mode == TRACK_ALLOCATION_SITE ? allocation_site : nullptr;
375 :
376 : CSA_ASSERT(this, IsJSArrayMap(LoadMap(boilerplate)));
377 : ParameterMode mode = OptimalParameterMode();
378 248 : return CloneFastJSArray(context, boilerplate, mode, allocation_site);
379 : }
380 :
381 155 : TF_BUILTIN(CreateShallowArrayLiteral, ConstructorBuiltinsAssembler) {
382 : Node* feedback_vector = Parameter(Descriptor::kFeedbackVector);
383 62 : Node* slot = SmiUntag(Parameter(Descriptor::kSlot));
384 : Node* constant_elements = Parameter(Descriptor::kConstantElements);
385 : Node* context = Parameter(Descriptor::kContext);
386 : Label call_runtime(this, Label::kDeferred);
387 : Return(EmitCreateShallowArrayLiteral(feedback_vector, slot, context,
388 : &call_runtime,
389 62 : DONT_TRACK_ALLOCATION_SITE));
390 :
391 31 : BIND(&call_runtime);
392 : {
393 31 : Comment("call runtime");
394 : int const flags =
395 : AggregateLiteral::kDisableMementos | AggregateLiteral::kIsShallow;
396 : Return(CallRuntime(Runtime::kCreateArrayLiteral, context, feedback_vector,
397 93 : SmiTag(slot), constant_elements, SmiConstant(flags)));
398 31 : }
399 31 : }
400 :
401 124 : Node* ConstructorBuiltinsAssembler::EmitCreateEmptyArrayLiteral(
402 : Node* feedback_vector, Node* slot, Node* context) {
403 : // Array literals always have a valid AllocationSite to properly track
404 : // elements transitions.
405 124 : VARIABLE(allocation_site, MachineRepresentation::kTagged,
406 : LoadFeedbackVectorSlot(feedback_vector, slot, 0, INTPTR_PARAMETERS));
407 :
408 124 : Label create_empty_array(this),
409 124 : initialize_allocation_site(this, Label::kDeferred), done(this);
410 248 : Branch(TaggedIsSmi(allocation_site.value()), &initialize_allocation_site,
411 248 : &create_empty_array);
412 :
413 : // TODO(cbruni): create the AllocationSite in CSA.
414 124 : BIND(&initialize_allocation_site);
415 : {
416 : allocation_site.Bind(
417 248 : CreateAllocationSiteInFeedbackVector(feedback_vector, SmiTag(slot)));
418 124 : Goto(&create_empty_array);
419 : }
420 :
421 124 : BIND(&create_empty_array);
422 : CSA_ASSERT(this, IsAllocationSite(allocation_site.value()));
423 124 : Node* kind = SmiToWord32(CAST(
424 : LoadObjectField(allocation_site.value(),
425 248 : AllocationSite::kTransitionInfoOrBoilerplateOffset)));
426 : CSA_ASSERT(this, IsFastElementsKind(kind));
427 248 : Node* native_context = LoadNativeContext(context);
428 124 : Comment("LoadJSArrayElementsMap");
429 248 : Node* array_map = LoadJSArrayElementsMap(kind, native_context);
430 248 : Node* zero = SmiConstant(0);
431 124 : Comment("Allocate JSArray");
432 : Node* result =
433 : AllocateJSArray(GetInitialFastElementsKind(), array_map, zero, zero,
434 124 : allocation_site.value(), ParameterMode::SMI_PARAMETERS);
435 :
436 124 : Goto(&done);
437 124 : BIND(&done);
438 :
439 124 : return result;
440 : }
441 :
442 155 : TF_BUILTIN(CreateEmptyArrayLiteral, ConstructorBuiltinsAssembler) {
443 : Node* feedback_vector = Parameter(Descriptor::kFeedbackVector);
444 62 : Node* slot = SmiUntag(Parameter(Descriptor::kSlot));
445 : Node* context = Parameter(Descriptor::kContext);
446 31 : Node* result = EmitCreateEmptyArrayLiteral(feedback_vector, slot, context);
447 31 : Return(result);
448 31 : }
449 :
450 124 : Node* ConstructorBuiltinsAssembler::EmitCreateShallowObjectLiteral(
451 : Node* feedback_vector, Node* slot, Label* call_runtime) {
452 : Node* allocation_site =
453 124 : LoadFeedbackVectorSlot(feedback_vector, slot, 0, INTPTR_PARAMETERS);
454 124 : GotoIf(NotHasBoilerplate(allocation_site), call_runtime);
455 :
456 : Node* boilerplate = LoadAllocationSiteBoilerplate(allocation_site);
457 248 : Node* boilerplate_map = LoadMap(boilerplate);
458 : CSA_ASSERT(this, IsJSObjectMap(boilerplate_map));
459 :
460 124 : VARIABLE(var_properties, MachineRepresentation::kTagged);
461 : {
462 248 : Node* bit_field_3 = LoadMapBitField3(boilerplate_map);
463 124 : GotoIf(IsSetWord32<Map::Deprecated>(bit_field_3), call_runtime);
464 : // Directly copy over the property store for dict-mode boilerplates.
465 124 : Label if_dictionary(this), if_fast(this), done(this);
466 : Branch(IsSetWord32<Map::DictionaryMap>(bit_field_3), &if_dictionary,
467 124 : &if_fast);
468 124 : BIND(&if_dictionary);
469 : {
470 124 : Comment("Copy dictionary properties");
471 : var_properties.Bind(
472 248 : CopyNameDictionary(LoadSlowProperties(boilerplate), call_runtime));
473 : // Slow objects have no in-object properties.
474 124 : Goto(&done);
475 : }
476 124 : BIND(&if_fast);
477 : {
478 : // TODO(cbruni): support copying out-of-object properties.
479 248 : Node* boilerplate_properties = LoadFastProperties(boilerplate);
480 248 : GotoIfNot(IsEmptyFixedArray(boilerplate_properties), call_runtime);
481 248 : var_properties.Bind(EmptyFixedArrayConstant());
482 124 : Goto(&done);
483 : }
484 248 : BIND(&done);
485 : }
486 :
487 248 : VARIABLE(var_elements, MachineRepresentation::kTagged);
488 : {
489 : // Copy the elements backing store, assuming that it's flat.
490 124 : Label if_empty_fixed_array(this), if_copy_elements(this), done(this);
491 248 : Node* boilerplate_elements = LoadElements(boilerplate);
492 124 : Branch(IsEmptyFixedArray(boilerplate_elements), &if_empty_fixed_array,
493 248 : &if_copy_elements);
494 :
495 124 : BIND(&if_empty_fixed_array);
496 124 : var_elements.Bind(boilerplate_elements);
497 124 : Goto(&done);
498 :
499 124 : BIND(&if_copy_elements);
500 : CSA_ASSERT(this, Word32BinaryNot(
501 : IsFixedCOWArrayMap(LoadMap(boilerplate_elements))));
502 : ExtractFixedArrayFlags flags;
503 : flags |= ExtractFixedArrayFlag::kAllFixedArrays;
504 : flags |= ExtractFixedArrayFlag::kNewSpaceAllocationOnly;
505 : flags |= ExtractFixedArrayFlag::kDontCopyCOW;
506 124 : var_elements.Bind(CloneFixedArray(boilerplate_elements, flags));
507 124 : Goto(&done);
508 248 : BIND(&done);
509 : }
510 :
511 : // Ensure new-space allocation for a fresh JSObject so we can skip write
512 : // barriers when copying all object fields.
513 : STATIC_ASSERT(JSObject::kMaxInstanceSize < kMaxRegularHeapObjectSize);
514 248 : Node* instance_size = TimesPointerSize(LoadMapInstanceSize(boilerplate_map));
515 : Node* allocation_size = instance_size;
516 124 : bool needs_allocation_memento = FLAG_allocation_site_pretenuring;
517 124 : if (needs_allocation_memento) {
518 : // Prepare for inner-allocating the AllocationMemento.
519 248 : allocation_size =
520 248 : IntPtrAdd(instance_size, IntPtrConstant(AllocationMemento::kSize));
521 : }
522 :
523 124 : Node* copy = AllocateInNewSpace(allocation_size);
524 : {
525 124 : Comment("Initialize Literal Copy");
526 : // Initialize Object fields.
527 124 : StoreMapNoWriteBarrier(copy, boilerplate_map);
528 : StoreObjectFieldNoWriteBarrier(copy, JSObject::kPropertiesOrHashOffset,
529 124 : var_properties.value());
530 : StoreObjectFieldNoWriteBarrier(copy, JSObject::kElementsOffset,
531 124 : var_elements.value());
532 : }
533 :
534 : // Initialize the AllocationMemento before potential GCs due to heap number
535 : // allocation when copying the in-object properties.
536 124 : if (needs_allocation_memento) {
537 124 : InitializeAllocationMemento(copy, instance_size, allocation_site);
538 : }
539 :
540 : {
541 : // Copy over in-object properties.
542 : Label continue_with_write_barrier(this), done_init(this);
543 248 : VARIABLE(offset, MachineType::PointerRepresentation(),
544 : IntPtrConstant(JSObject::kHeaderSize));
545 : // Mutable heap numbers only occur on 32-bit platforms.
546 : bool may_use_mutable_heap_numbers =
547 : FLAG_track_double_fields && !FLAG_unbox_double_fields;
548 : {
549 124 : Comment("Copy in-object properties fast");
550 : Label continue_fast(this, &offset);
551 248 : Branch(WordEqual(offset.value(), instance_size), &done_init,
552 248 : &continue_fast);
553 124 : BIND(&continue_fast);
554 124 : Node* field = LoadObjectField(boilerplate, offset.value());
555 : if (may_use_mutable_heap_numbers) {
556 : Label store_field(this);
557 : GotoIf(TaggedIsSmi(field), &store_field);
558 : GotoIf(IsMutableHeapNumber(field), &continue_with_write_barrier);
559 : Goto(&store_field);
560 : BIND(&store_field);
561 : }
562 124 : StoreObjectFieldNoWriteBarrier(copy, offset.value(), field);
563 496 : offset.Bind(IntPtrAdd(offset.value(), IntPtrConstant(kPointerSize)));
564 248 : Branch(WordNotEqual(offset.value(), instance_size), &continue_fast,
565 372 : &done_init);
566 : }
567 :
568 : if (!may_use_mutable_heap_numbers) {
569 124 : BIND(&done_init);
570 124 : return copy;
571 : }
572 : // Continue initializing the literal after seeing the first sub-object
573 : // potentially causing allocation. In this case we prepare the new literal
574 : // by copying all pending fields over from the boilerplate and emit full
575 : // write barriers from here on.
576 : BIND(&continue_with_write_barrier);
577 : {
578 : Comment("Copy in-object properties slow");
579 : BuildFastLoop(offset.value(), instance_size,
580 : [=](Node* offset) {
581 : Node* field = LoadObjectField(boilerplate, offset);
582 : StoreObjectFieldNoWriteBarrier(copy, offset, field);
583 : },
584 : kPointerSize, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
585 : Comment("Copy mutable HeapNumber values");
586 : BuildFastLoop(offset.value(), instance_size,
587 : [=](Node* offset) {
588 : Node* field = LoadObjectField(copy, offset);
589 : Label copy_mutable_heap_number(this, Label::kDeferred),
590 : continue_loop(this);
591 : // We only have to clone complex field values.
592 : GotoIf(TaggedIsSmi(field), &continue_loop);
593 : Branch(IsMutableHeapNumber(field),
594 : ©_mutable_heap_number, &continue_loop);
595 : BIND(©_mutable_heap_number);
596 : {
597 : Node* double_value = LoadHeapNumberValue(field);
598 : Node* mutable_heap_number =
599 : AllocateHeapNumberWithValue(double_value, MUTABLE);
600 : StoreObjectField(copy, offset, mutable_heap_number);
601 : Goto(&continue_loop);
602 : }
603 : BIND(&continue_loop);
604 : },
605 : kPointerSize, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
606 : Goto(&done_init);
607 : }
608 : BIND(&done_init);
609 : }
610 124 : return copy;
611 : }
612 :
613 186 : TF_BUILTIN(CreateShallowObjectLiteral, ConstructorBuiltinsAssembler) {
614 31 : Label call_runtime(this);
615 : Node* feedback_vector = Parameter(Descriptor::kFeedbackVector);
616 62 : Node* slot = SmiUntag(Parameter(Descriptor::kSlot));
617 : Node* copy =
618 31 : EmitCreateShallowObjectLiteral(feedback_vector, slot, &call_runtime);
619 31 : Return(copy);
620 :
621 31 : BIND(&call_runtime);
622 : Node* boilerplate_description =
623 : Parameter(Descriptor::kBoilerplateDescription);
624 : Node* flags = Parameter(Descriptor::kFlags);
625 : Node* context = Parameter(Descriptor::kContext);
626 : TailCallRuntime(Runtime::kCreateObjectLiteral, context, feedback_vector,
627 62 : SmiTag(slot), boilerplate_description, flags);
628 31 : }
629 :
630 : // Used by the CreateEmptyObjectLiteral bytecode and the Object constructor.
631 62 : Node* ConstructorBuiltinsAssembler::EmitCreateEmptyObjectLiteral(
632 : Node* context) {
633 124 : Node* native_context = LoadNativeContext(context);
634 : Node* object_function =
635 124 : LoadContextElement(native_context, Context::OBJECT_FUNCTION_INDEX);
636 : Node* map = LoadObjectField(object_function,
637 : JSFunction::kPrototypeOrInitialMapOffset);
638 : CSA_ASSERT(this, IsMap(map));
639 : // Ensure that slack tracking is disabled for the map.
640 : STATIC_ASSERT(Map::kNoSlackTracking == 0);
641 : CSA_ASSERT(this,
642 : IsClearWord32<Map::ConstructionCounter>(LoadMapBitField3(map)));
643 124 : Node* empty_fixed_array = EmptyFixedArrayConstant();
644 : Node* result =
645 62 : AllocateJSObjectFromMap(map, empty_fixed_array, empty_fixed_array);
646 62 : return result;
647 : }
648 :
649 155 : TF_BUILTIN(ObjectConstructor, ConstructorBuiltinsAssembler) {
650 : int const kValueArg = 0;
651 : Node* argc =
652 62 : ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
653 31 : CodeStubArguments args(this, argc);
654 62 : Node* value = args.GetOptionalArgumentValue(kValueArg);
655 : Node* context = Parameter(BuiltinDescriptor::kContext);
656 :
657 : CSA_ASSERT(this, IsUndefined(Parameter(BuiltinDescriptor::kNewTarget)));
658 :
659 : Label return_to_object(this);
660 :
661 124 : GotoIf(Word32And(IsNotUndefined(value), IsNotNull(value)), &return_to_object);
662 :
663 31 : args.PopAndReturn(EmitCreateEmptyObjectLiteral(context));
664 :
665 31 : BIND(&return_to_object);
666 31 : args.PopAndReturn(CallBuiltin(Builtins::kToObject, context, value));
667 31 : }
668 :
669 155 : TF_BUILTIN(ObjectConstructor_ConstructStub, ConstructorBuiltinsAssembler) {
670 : int const kValueArg = 0;
671 : Node* argc =
672 62 : ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
673 31 : CodeStubArguments args(this, argc);
674 62 : Node* value = args.GetOptionalArgumentValue(kValueArg);
675 :
676 : Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset,
677 31 : MachineType::TaggedPointer());
678 : Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
679 : Node* context = Parameter(BuiltinDescriptor::kContext);
680 :
681 : CSA_ASSERT(this, IsNotUndefined(new_target));
682 :
683 : Label return_to_object(this);
684 :
685 31 : GotoIf(Word32And(WordEqual(target, new_target),
686 186 : Word32And(IsNotUndefined(value), IsNotNull(value))),
687 62 : &return_to_object);
688 31 : args.PopAndReturn(EmitFastNewObject(context, target, new_target));
689 :
690 31 : BIND(&return_to_object);
691 31 : args.PopAndReturn(CallBuiltin(Builtins::kToObject, context, value));
692 31 : }
693 :
694 155 : TF_BUILTIN(NumberConstructor, ConstructorBuiltinsAssembler) {
695 : Node* argc =
696 62 : ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
697 31 : CodeStubArguments args(this, argc);
698 :
699 : Label return_zero(this);
700 :
701 93 : GotoIf(IntPtrEqual(IntPtrConstant(0), argc), &return_zero);
702 :
703 : Node* context = Parameter(BuiltinDescriptor::kContext);
704 93 : args.PopAndReturn(ToNumber(context, args.AtIndex(0)));
705 :
706 31 : BIND(&return_zero);
707 62 : args.PopAndReturn(SmiConstant(0));
708 31 : }
709 :
710 155 : TF_BUILTIN(NumberConstructor_ConstructStub, ConstructorBuiltinsAssembler) {
711 : Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset,
712 31 : MachineType::TaggedPointer());
713 : Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
714 : Node* context = Parameter(BuiltinDescriptor::kContext);
715 :
716 : Node* argc =
717 62 : ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
718 : CodeStubArguments args(this, argc);
719 :
720 31 : Label return_zero(this), wrap(this);
721 :
722 62 : VARIABLE(var_result, MachineRepresentation::kTagged);
723 :
724 93 : GotoIf(IntPtrEqual(IntPtrConstant(0), argc), &return_zero);
725 : {
726 93 : var_result.Bind(ToNumber(context, args.AtIndex(0)));
727 31 : Goto(&wrap);
728 : }
729 :
730 31 : BIND(&return_zero);
731 : {
732 62 : var_result.Bind(SmiConstant(0));
733 31 : Goto(&wrap);
734 : }
735 :
736 31 : BIND(&wrap);
737 : {
738 31 : Node* result = EmitFastNewObject(context, target, new_target);
739 31 : StoreObjectField(result, JSValue::kValueOffset, var_result.value());
740 31 : args.PopAndReturn(result);
741 31 : }
742 31 : }
743 :
744 62 : Node* ConstructorBuiltinsAssembler::EmitConstructString(Node* argc,
745 : CodeStubArguments& args,
746 : Node* context,
747 : bool convert_symbol) {
748 62 : VARIABLE(var_result, MachineRepresentation::kTagged);
749 :
750 62 : Label return_empty_string(this), to_string(this),
751 62 : check_symbol(this, Label::kDeferred), done(this);
752 :
753 186 : GotoIf(IntPtrEqual(IntPtrConstant(0), argc), &return_empty_string);
754 :
755 124 : Node* argument = args.AtIndex(0);
756 :
757 124 : GotoIf(TaggedIsSmi(argument), &to_string);
758 :
759 124 : Node* instance_type = LoadInstanceType(argument);
760 :
761 62 : Label* non_string = convert_symbol ? &check_symbol : &to_string;
762 124 : GotoIfNot(IsStringInstanceType(instance_type), non_string);
763 : {
764 62 : var_result.Bind(argument);
765 62 : Goto(&done);
766 : }
767 :
768 62 : if (convert_symbol) {
769 31 : BIND(&check_symbol);
770 62 : GotoIfNot(IsSymbolInstanceType(instance_type), &to_string);
771 : {
772 : var_result.Bind(
773 31 : CallRuntime(Runtime::kSymbolDescriptiveString, context, argument));
774 31 : Goto(&done);
775 : }
776 : }
777 :
778 62 : BIND(&to_string);
779 : {
780 124 : var_result.Bind(ToString(context, argument));
781 62 : Goto(&done);
782 : }
783 :
784 62 : BIND(&return_empty_string);
785 : {
786 124 : var_result.Bind(EmptyStringConstant());
787 62 : Goto(&done);
788 : }
789 :
790 62 : BIND(&done);
791 124 : return var_result.value();
792 : }
793 :
794 124 : TF_BUILTIN(StringConstructor, ConstructorBuiltinsAssembler) {
795 : Node* context = Parameter(BuiltinDescriptor::kContext);
796 : Node* argc =
797 62 : ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
798 31 : CodeStubArguments args(this, argc);
799 :
800 31 : args.PopAndReturn(EmitConstructString(argc, args, context, true));
801 31 : }
802 :
803 155 : TF_BUILTIN(StringConstructor_ConstructStub, ConstructorBuiltinsAssembler) {
804 : Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset,
805 31 : MachineType::TaggedPointer());
806 : Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
807 : Node* context = Parameter(BuiltinDescriptor::kContext);
808 :
809 : Node* argc =
810 62 : ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
811 : CodeStubArguments args(this, argc);
812 :
813 31 : Node* string = EmitConstructString(argc, args, context, false);
814 31 : Node* result = EmitFastNewObject(context, target, new_target);
815 31 : StoreObjectField(result, JSValue::kValueOffset, string);
816 31 : args.PopAndReturn(result);
817 31 : }
818 :
819 : } // namespace internal
820 : } // namespace v8
|