• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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-call-gen.h"
6 
7 #include "src/builtins/builtins-utils-gen.h"
8 #include "src/builtins/builtins.h"
9 #include "src/codegen/macro-assembler.h"
10 #include "src/common/globals.h"
11 #include "src/execution/isolate.h"
12 #include "src/execution/protectors.h"
13 #include "src/objects/api-callbacks.h"
14 #include "src/objects/arguments.h"
15 #include "src/objects/property-cell.h"
16 #include "src/objects/templates.h"
17 
18 namespace v8 {
19 namespace internal {
20 
Generate_CallFunction_ReceiverIsNullOrUndefined(MacroAssembler * masm)21 void Builtins::Generate_CallFunction_ReceiverIsNullOrUndefined(
22     MacroAssembler* masm) {
23   Generate_CallFunction(masm, ConvertReceiverMode::kNullOrUndefined);
24 }
25 
Generate_CallFunction_ReceiverIsNotNullOrUndefined(MacroAssembler * masm)26 void Builtins::Generate_CallFunction_ReceiverIsNotNullOrUndefined(
27     MacroAssembler* masm) {
28   Generate_CallFunction(masm, ConvertReceiverMode::kNotNullOrUndefined);
29 }
30 
Generate_CallFunction_ReceiverIsAny(MacroAssembler * masm)31 void Builtins::Generate_CallFunction_ReceiverIsAny(MacroAssembler* masm) {
32   Generate_CallFunction(masm, ConvertReceiverMode::kAny);
33 }
34 
Generate_CallBoundFunction(MacroAssembler * masm)35 void Builtins::Generate_CallBoundFunction(MacroAssembler* masm) {
36   Generate_CallBoundFunctionImpl(masm);
37 }
38 
Generate_Call_ReceiverIsNullOrUndefined(MacroAssembler * masm)39 void Builtins::Generate_Call_ReceiverIsNullOrUndefined(MacroAssembler* masm) {
40   Generate_Call(masm, ConvertReceiverMode::kNullOrUndefined);
41 }
42 
Generate_Call_ReceiverIsNotNullOrUndefined(MacroAssembler * masm)43 void Builtins::Generate_Call_ReceiverIsNotNullOrUndefined(
44     MacroAssembler* masm) {
45   Generate_Call(masm, ConvertReceiverMode::kNotNullOrUndefined);
46 }
47 
Generate_Call_ReceiverIsAny(MacroAssembler * masm)48 void Builtins::Generate_Call_ReceiverIsAny(MacroAssembler* masm) {
49   Generate_Call(masm, ConvertReceiverMode::kAny);
50 }
51 
Generate_CallVarargs(MacroAssembler * masm)52 void Builtins::Generate_CallVarargs(MacroAssembler* masm) {
53   Generate_CallOrConstructVarargs(masm, masm->isolate()->builtins()->Call());
54 }
55 
Generate_CallForwardVarargs(MacroAssembler * masm)56 void Builtins::Generate_CallForwardVarargs(MacroAssembler* masm) {
57   Generate_CallOrConstructForwardVarargs(masm, CallOrConstructMode::kCall,
58                                          masm->isolate()->builtins()->Call());
59 }
60 
Generate_CallFunctionForwardVarargs(MacroAssembler * masm)61 void Builtins::Generate_CallFunctionForwardVarargs(MacroAssembler* masm) {
62   Generate_CallOrConstructForwardVarargs(
63       masm, CallOrConstructMode::kCall,
64       masm->isolate()->builtins()->CallFunction());
65 }
66 
67 // TODO(cbruni): Try reusing code between builtin versions to avoid binary
68 // overhead.
TF_BUILTIN(Call_ReceiverIsNullOrUndefined_Baseline_Compact,CallOrConstructBuiltinsAssembler)69 TF_BUILTIN(Call_ReceiverIsNullOrUndefined_Baseline_Compact,
70            CallOrConstructBuiltinsAssembler) {
71   auto receiver = UndefinedConstant();
72   CallReceiver<Descriptor>(Builtin::kCall_ReceiverIsNullOrUndefined, receiver);
73 }
74 
TF_BUILTIN(Call_ReceiverIsNullOrUndefined_Baseline,CallOrConstructBuiltinsAssembler)75 TF_BUILTIN(Call_ReceiverIsNullOrUndefined_Baseline,
76            CallOrConstructBuiltinsAssembler) {
77   auto argc = UncheckedParameter<Int32T>(Descriptor::kActualArgumentsCount);
78   auto slot = UncheckedParameter<UintPtrT>(Descriptor::kSlot);
79   auto receiver = UndefinedConstant();
80   CallReceiver<Descriptor>(Builtin::kCall_ReceiverIsNullOrUndefined, argc, slot,
81                            receiver);
82 }
83 
TF_BUILTIN(Call_ReceiverIsNotNullOrUndefined_Baseline_Compact,CallOrConstructBuiltinsAssembler)84 TF_BUILTIN(Call_ReceiverIsNotNullOrUndefined_Baseline_Compact,
85            CallOrConstructBuiltinsAssembler) {
86   CallReceiver<Descriptor>(Builtin::kCall_ReceiverIsNotNullOrUndefined);
87 }
88 
TF_BUILTIN(Call_ReceiverIsNotNullOrUndefined_Baseline,CallOrConstructBuiltinsAssembler)89 TF_BUILTIN(Call_ReceiverIsNotNullOrUndefined_Baseline,
90            CallOrConstructBuiltinsAssembler) {
91   auto argc = UncheckedParameter<Int32T>(Descriptor::kActualArgumentsCount);
92   auto slot = UncheckedParameter<UintPtrT>(Descriptor::kSlot);
93   CallReceiver<Descriptor>(Builtin::kCall_ReceiverIsNotNullOrUndefined, argc,
94                            slot);
95 }
96 
TF_BUILTIN(Call_ReceiverIsAny_Baseline_Compact,CallOrConstructBuiltinsAssembler)97 TF_BUILTIN(Call_ReceiverIsAny_Baseline_Compact,
98            CallOrConstructBuiltinsAssembler) {
99   CallReceiver<Descriptor>(Builtin::kCall_ReceiverIsAny);
100 }
101 
TF_BUILTIN(Call_ReceiverIsAny_Baseline,CallOrConstructBuiltinsAssembler)102 TF_BUILTIN(Call_ReceiverIsAny_Baseline, CallOrConstructBuiltinsAssembler) {
103   auto argc = UncheckedParameter<Int32T>(Descriptor::kActualArgumentsCount);
104   auto slot = UncheckedParameter<UintPtrT>(Descriptor::kSlot);
105   CallReceiver<Descriptor>(Builtin::kCall_ReceiverIsAny, argc, slot);
106 }
107 
TF_BUILTIN(Call_ReceiverIsNullOrUndefined_WithFeedback,CallOrConstructBuiltinsAssembler)108 TF_BUILTIN(Call_ReceiverIsNullOrUndefined_WithFeedback,
109            CallOrConstructBuiltinsAssembler) {
110   auto target = Parameter<Object>(Descriptor::kFunction);
111   auto argc = UncheckedParameter<Int32T>(Descriptor::kActualArgumentsCount);
112   auto context = Parameter<Context>(Descriptor::kContext);
113   auto feedback_vector = Parameter<FeedbackVector>(Descriptor::kFeedbackVector);
114   auto slot = UncheckedParameter<UintPtrT>(Descriptor::kSlot);
115   auto receiver = Parameter<Object>(Descriptor::kReceiver);
116   CollectCallFeedback(
117       target, [=] { return receiver; }, context, feedback_vector, slot);
118   TailCallBuiltin(Builtin::kCall_ReceiverIsNullOrUndefined, context, target,
119                   argc);
120 }
121 
TF_BUILTIN(Call_ReceiverIsNotNullOrUndefined_WithFeedback,CallOrConstructBuiltinsAssembler)122 TF_BUILTIN(Call_ReceiverIsNotNullOrUndefined_WithFeedback,
123            CallOrConstructBuiltinsAssembler) {
124   auto target = Parameter<Object>(Descriptor::kFunction);
125   auto argc = UncheckedParameter<Int32T>(Descriptor::kActualArgumentsCount);
126   auto context = Parameter<Context>(Descriptor::kContext);
127   auto feedback_vector = Parameter<FeedbackVector>(Descriptor::kFeedbackVector);
128   auto slot = UncheckedParameter<UintPtrT>(Descriptor::kSlot);
129   auto receiver = Parameter<Object>(Descriptor::kReceiver);
130   CollectCallFeedback(
131       target, [=] { return receiver; }, context, feedback_vector, slot);
132   TailCallBuiltin(Builtin::kCall_ReceiverIsNotNullOrUndefined, context, target,
133                   argc);
134 }
135 
TF_BUILTIN(Call_ReceiverIsAny_WithFeedback,CallOrConstructBuiltinsAssembler)136 TF_BUILTIN(Call_ReceiverIsAny_WithFeedback, CallOrConstructBuiltinsAssembler) {
137   auto target = Parameter<Object>(Descriptor::kFunction);
138   auto argc = UncheckedParameter<Int32T>(Descriptor::kActualArgumentsCount);
139   auto context = Parameter<Context>(Descriptor::kContext);
140   auto feedback_vector = Parameter<FeedbackVector>(Descriptor::kFeedbackVector);
141   auto slot = UncheckedParameter<UintPtrT>(Descriptor::kSlot);
142   auto receiver = Parameter<Object>(Descriptor::kReceiver);
143   CollectCallFeedback(
144       target, [=] { return receiver; }, context, feedback_vector, slot);
145   TailCallBuiltin(Builtin::kCall_ReceiverIsAny, context, target, argc);
146 }
147 
CallOrConstructWithArrayLike(TNode<Object> target,base::Optional<TNode<Object>> new_target,TNode<Object> arguments_list,TNode<Context> context)148 void CallOrConstructBuiltinsAssembler::CallOrConstructWithArrayLike(
149     TNode<Object> target, base::Optional<TNode<Object>> new_target,
150     TNode<Object> arguments_list, TNode<Context> context) {
151   Label if_done(this), if_arguments(this), if_array(this),
152       if_holey_array(this, Label::kDeferred),
153       if_runtime(this, Label::kDeferred);
154 
155   // Perform appropriate checks on {target} (and {new_target} first).
156   if (!new_target) {
157     // Check that {target} is Callable.
158     Label if_target_callable(this),
159         if_target_not_callable(this, Label::kDeferred);
160     GotoIf(TaggedIsSmi(target), &if_target_not_callable);
161     Branch(IsCallable(CAST(target)), &if_target_callable,
162            &if_target_not_callable);
163     BIND(&if_target_not_callable);
164     {
165       CallRuntime(Runtime::kThrowApplyNonFunction, context, target);
166       Unreachable();
167     }
168     BIND(&if_target_callable);
169   } else {
170     // Check that {target} is a Constructor.
171     Label if_target_constructor(this),
172         if_target_not_constructor(this, Label::kDeferred);
173     GotoIf(TaggedIsSmi(target), &if_target_not_constructor);
174     Branch(IsConstructor(CAST(target)), &if_target_constructor,
175            &if_target_not_constructor);
176     BIND(&if_target_not_constructor);
177     {
178       CallRuntime(Runtime::kThrowNotConstructor, context, target);
179       Unreachable();
180     }
181     BIND(&if_target_constructor);
182 
183     // Check that {new_target} is a Constructor.
184     Label if_new_target_constructor(this),
185         if_new_target_not_constructor(this, Label::kDeferred);
186     GotoIf(TaggedIsSmi(*new_target), &if_new_target_not_constructor);
187     Branch(IsConstructor(CAST(*new_target)), &if_new_target_constructor,
188            &if_new_target_not_constructor);
189     BIND(&if_new_target_not_constructor);
190     {
191       CallRuntime(Runtime::kThrowNotConstructor, context, *new_target);
192       Unreachable();
193     }
194     BIND(&if_new_target_constructor);
195   }
196 
197   GotoIf(TaggedIsSmi(arguments_list), &if_runtime);
198 
199   TNode<Map> arguments_list_map = LoadMap(CAST(arguments_list));
200   TNode<NativeContext> native_context = LoadNativeContext(context);
201 
202   // Check if {arguments_list} is an (unmodified) arguments object.
203   TNode<Map> sloppy_arguments_map = CAST(
204       LoadContextElement(native_context, Context::SLOPPY_ARGUMENTS_MAP_INDEX));
205   GotoIf(TaggedEqual(arguments_list_map, sloppy_arguments_map), &if_arguments);
206   TNode<Map> strict_arguments_map = CAST(
207       LoadContextElement(native_context, Context::STRICT_ARGUMENTS_MAP_INDEX));
208   GotoIf(TaggedEqual(arguments_list_map, strict_arguments_map), &if_arguments);
209 
210   // Check if {arguments_list} is a fast JSArray.
211   Branch(IsJSArrayMap(arguments_list_map), &if_array, &if_runtime);
212 
213   TVARIABLE(FixedArrayBase, var_elements);
214   TVARIABLE(Int32T, var_length);
215   BIND(&if_array);
216   {
217     TNode<Int32T> kind = LoadMapElementsKind(arguments_list_map);
218     GotoIf(
219         IsElementsKindGreaterThan(kind, LAST_ANY_NONEXTENSIBLE_ELEMENTS_KIND),
220         &if_runtime);
221 
222     TNode<JSObject> js_object = CAST(arguments_list);
223     // Try to extract the elements from a JSArray object.
224     var_elements = LoadElements(js_object);
225     var_length =
226         LoadAndUntagToWord32ObjectField(js_object, JSArray::kLengthOffset);
227 
228     // Holey arrays and double backing stores need special treatment.
229     STATIC_ASSERT(PACKED_SMI_ELEMENTS == 0);
230     STATIC_ASSERT(HOLEY_SMI_ELEMENTS == 1);
231     STATIC_ASSERT(PACKED_ELEMENTS == 2);
232     STATIC_ASSERT(HOLEY_ELEMENTS == 3);
233     STATIC_ASSERT(PACKED_DOUBLE_ELEMENTS == 4);
234     STATIC_ASSERT(HOLEY_DOUBLE_ELEMENTS == 5);
235     STATIC_ASSERT(LAST_FAST_ELEMENTS_KIND == HOLEY_DOUBLE_ELEMENTS);
236 
237     Branch(Word32And(kind, Int32Constant(1)), &if_holey_array, &if_done);
238   }
239 
240   BIND(&if_holey_array);
241   {
242     // For holey JSArrays we need to check that the array prototype chain
243     // protector is intact and our prototype is the Array.prototype actually.
244     GotoIfNot(IsPrototypeInitialArrayPrototype(context, arguments_list_map),
245               &if_runtime);
246     Branch(IsNoElementsProtectorCellInvalid(), &if_runtime, &if_done);
247   }
248 
249   BIND(&if_arguments);
250   {
251     TNode<JSArgumentsObject> js_arguments = CAST(arguments_list);
252     // Try to extract the elements from a JSArgumentsObject with standard map.
253     TNode<Object> length = LoadJSArgumentsObjectLength(context, js_arguments);
254     TNode<FixedArrayBase> elements = LoadElements(js_arguments);
255     TNode<Smi> elements_length = LoadFixedArrayBaseLength(elements);
256     GotoIfNot(TaggedEqual(length, elements_length), &if_runtime);
257     var_elements = elements;
258     var_length = SmiToInt32(CAST(length));
259     Goto(&if_done);
260   }
261 
262   BIND(&if_runtime);
263   {
264     // Ask the runtime to create the list (actually a FixedArray).
265     var_elements = CAST(CallRuntime(Runtime::kCreateListFromArrayLike, context,
266                                     arguments_list));
267     var_length = LoadAndUntagToWord32ObjectField(var_elements.value(),
268                                                  FixedArray::kLengthOffset);
269     Goto(&if_done);
270   }
271 
272   // Tail call to the appropriate builtin (depending on whether we have
273   // a {new_target} passed).
274   BIND(&if_done);
275   {
276     Label if_not_double(this), if_double(this);
277     TNode<Int32T> args_count =
278         Int32Constant(i::JSParameterCount(0));  // args already on the stack
279 
280     TNode<Int32T> length = var_length.value();
281     {
282       Label normalize_done(this);
283       CSA_DCHECK(this, Int32LessThanOrEqual(
284                            length, Int32Constant(FixedArray::kMaxLength)));
285       GotoIfNot(Word32Equal(length, Int32Constant(0)), &normalize_done);
286       // Make sure we don't accidentally pass along the
287       // empty_fixed_double_array since the tailed-called stubs cannot handle
288       // the normalization yet.
289       var_elements = EmptyFixedArrayConstant();
290       Goto(&normalize_done);
291 
292       BIND(&normalize_done);
293     }
294 
295     TNode<FixedArrayBase> elements = var_elements.value();
296     Branch(IsFixedDoubleArray(elements), &if_double, &if_not_double);
297 
298     BIND(&if_not_double);
299     {
300       if (!new_target) {
301         Callable callable = CodeFactory::CallVarargs(isolate());
302         TailCallStub(callable, context, target, args_count, length, elements);
303       } else {
304         Callable callable = CodeFactory::ConstructVarargs(isolate());
305         TailCallStub(callable, context, target, *new_target, args_count, length,
306                      elements);
307       }
308     }
309 
310     BIND(&if_double);
311     {
312       // Kind is hardcoded here because CreateListFromArrayLike will only
313       // produce holey double arrays.
314       CallOrConstructDoubleVarargs(target, new_target, CAST(elements), length,
315                                    args_count, context,
316                                    Int32Constant(HOLEY_DOUBLE_ELEMENTS));
317     }
318   }
319 }
320 
321 // Takes a FixedArray of doubles and creates a new FixedArray with those doubles
322 // boxed as HeapNumbers, then tail calls CallVarargs/ConstructVarargs depending
323 // on whether {new_target} was passed.
CallOrConstructDoubleVarargs(TNode<Object> target,base::Optional<TNode<Object>> new_target,TNode<FixedDoubleArray> elements,TNode<Int32T> length,TNode<Int32T> args_count,TNode<Context> context,TNode<Int32T> kind)324 void CallOrConstructBuiltinsAssembler::CallOrConstructDoubleVarargs(
325     TNode<Object> target, base::Optional<TNode<Object>> new_target,
326     TNode<FixedDoubleArray> elements, TNode<Int32T> length,
327     TNode<Int32T> args_count, TNode<Context> context, TNode<Int32T> kind) {
328   const ElementsKind new_kind = PACKED_ELEMENTS;
329   const WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER;
330   CSA_DCHECK(this, Int32LessThanOrEqual(length,
331                                         Int32Constant(FixedArray::kMaxLength)));
332   TNode<IntPtrT> intptr_length = ChangeInt32ToIntPtr(length);
333   CSA_DCHECK(this, WordNotEqual(intptr_length, IntPtrConstant(0)));
334 
335   // Allocate a new FixedArray of Objects.
336   TNode<FixedArray> new_elements = CAST(AllocateFixedArray(
337       new_kind, intptr_length, AllocationFlag::kAllowLargeObjectAllocation));
338   // CopyFixedArrayElements does not distinguish between holey and packed for
339   // its first argument, so we don't need to dispatch on {kind} here.
340   CopyFixedArrayElements(PACKED_DOUBLE_ELEMENTS, elements, new_kind,
341                          new_elements, intptr_length, intptr_length,
342                          barrier_mode);
343   if (!new_target) {
344     Callable callable = CodeFactory::CallVarargs(isolate());
345     TailCallStub(callable, context, target, args_count, length, new_elements);
346   } else {
347     Callable callable = CodeFactory::ConstructVarargs(isolate());
348     TailCallStub(callable, context, target, *new_target, args_count, length,
349                  new_elements);
350   }
351 }
352 
CallOrConstructWithSpread(TNode<Object> target,base::Optional<TNode<Object>> new_target,TNode<Object> spread,TNode<Int32T> args_count,TNode<Context> context)353 void CallOrConstructBuiltinsAssembler::CallOrConstructWithSpread(
354     TNode<Object> target, base::Optional<TNode<Object>> new_target,
355     TNode<Object> spread, TNode<Int32T> args_count, TNode<Context> context) {
356   Label if_smiorobject(this), if_double(this),
357       if_generic(this, Label::kDeferred);
358 
359   TVARIABLE(JSArray, var_js_array);
360   TVARIABLE(FixedArrayBase, var_elements);
361   TVARIABLE(Int32T, var_elements_kind);
362 
363   GotoIf(TaggedIsSmi(spread), &if_generic);
364   TNode<Map> spread_map = LoadMap(CAST(spread));
365   GotoIfNot(IsJSArrayMap(spread_map), &if_generic);
366   TNode<JSArray> spread_array = CAST(spread);
367 
368   // Check that we have the original Array.prototype.
369   GotoIfNot(IsPrototypeInitialArrayPrototype(context, spread_map), &if_generic);
370 
371   // Check that there are no elements on the Array.prototype chain.
372   GotoIf(IsNoElementsProtectorCellInvalid(), &if_generic);
373 
374   // Check that the Array.prototype hasn't been modified in a way that would
375   // affect iteration.
376   TNode<PropertyCell> protector_cell = ArrayIteratorProtectorConstant();
377   GotoIf(
378       TaggedEqual(LoadObjectField(protector_cell, PropertyCell::kValueOffset),
379                   SmiConstant(Protectors::kProtectorInvalid)),
380       &if_generic);
381   {
382     // The fast-path accesses the {spread} elements directly.
383     TNode<Int32T> spread_kind = LoadMapElementsKind(spread_map);
384     var_js_array = spread_array;
385     var_elements_kind = spread_kind;
386     var_elements = LoadElements(spread_array);
387 
388     // Check elements kind of {spread}.
389     GotoIf(IsElementsKindLessThanOrEqual(spread_kind, HOLEY_ELEMENTS),
390            &if_smiorobject);
391     GotoIf(IsElementsKindLessThanOrEqual(spread_kind, LAST_FAST_ELEMENTS_KIND),
392            &if_double);
393     Branch(IsElementsKindLessThanOrEqual(spread_kind,
394                                          LAST_ANY_NONEXTENSIBLE_ELEMENTS_KIND),
395            &if_smiorobject, &if_generic);
396   }
397 
398   BIND(&if_generic);
399   {
400     Label if_iterator_fn_not_callable(this, Label::kDeferred),
401         if_iterator_is_null_or_undefined(this, Label::kDeferred),
402         throw_spread_error(this, Label::kDeferred);
403     TVARIABLE(Smi, message_id);
404 
405     GotoIf(IsNullOrUndefined(spread), &if_iterator_is_null_or_undefined);
406 
407     TNode<Object> iterator_fn =
408         GetProperty(context, spread, IteratorSymbolConstant());
409     GotoIfNot(TaggedIsCallable(iterator_fn), &if_iterator_fn_not_callable);
410     TNode<JSArray> list =
411         CAST(CallBuiltin(Builtin::kIterableToListMayPreserveHoles, context,
412                          spread, iterator_fn));
413 
414     var_js_array = list;
415     var_elements = LoadElements(list);
416     var_elements_kind = LoadElementsKind(list);
417     Branch(Int32LessThan(var_elements_kind.value(),
418                          Int32Constant(PACKED_DOUBLE_ELEMENTS)),
419            &if_smiorobject, &if_double);
420 
421     BIND(&if_iterator_fn_not_callable);
422     message_id = SmiConstant(
423         static_cast<int>(MessageTemplate::kIteratorSymbolNonCallable)),
424     Goto(&throw_spread_error);
425 
426     BIND(&if_iterator_is_null_or_undefined);
427     message_id = SmiConstant(
428         static_cast<int>(MessageTemplate::kNotIterableNoSymbolLoad));
429     Goto(&throw_spread_error);
430 
431     BIND(&throw_spread_error);
432     CallRuntime(Runtime::kThrowSpreadArgError, context, message_id.value(),
433                 spread);
434     Unreachable();
435   }
436 
437   BIND(&if_smiorobject);
438   {
439     TNode<Int32T> length = LoadAndUntagToWord32ObjectField(
440         var_js_array.value(), JSArray::kLengthOffset);
441     TNode<FixedArrayBase> elements = var_elements.value();
442     CSA_DCHECK(this, Int32LessThanOrEqual(
443                          length, Int32Constant(FixedArray::kMaxLength)));
444 
445     if (!new_target) {
446       Callable callable = CodeFactory::CallVarargs(isolate());
447       TailCallStub(callable, context, target, args_count, length, elements);
448     } else {
449       Callable callable = CodeFactory::ConstructVarargs(isolate());
450       TailCallStub(callable, context, target, *new_target, args_count, length,
451                    elements);
452     }
453   }
454 
455   BIND(&if_double);
456   {
457     TNode<Int32T> length = LoadAndUntagToWord32ObjectField(
458         var_js_array.value(), JSArray::kLengthOffset);
459     GotoIf(Word32Equal(length, Int32Constant(0)), &if_smiorobject);
460     CallOrConstructDoubleVarargs(target, new_target, CAST(var_elements.value()),
461                                  length, args_count, context,
462                                  var_elements_kind.value());
463   }
464 }
465 
466 template <class Descriptor>
CallReceiver(Builtin id,base::Optional<TNode<Object>> receiver)467 void CallOrConstructBuiltinsAssembler::CallReceiver(
468     Builtin id, base::Optional<TNode<Object>> receiver) {
469   static_assert(std::is_same<Descriptor,
470                              CallTrampoline_Baseline_CompactDescriptor>::value,
471                 "Incompatible Descriptor");
472   auto bitfield = UncheckedParameter<Word32T>(Descriptor::kBitField);
473   TNode<Int32T> argc =
474       Signed(DecodeWord32<
475              CallTrampoline_Baseline_CompactDescriptor::ArgumentCountField>(
476           bitfield));
477   TNode<UintPtrT> slot = ChangeUint32ToWord(
478       DecodeWord32<CallTrampoline_Baseline_CompactDescriptor::SlotField>(
479           bitfield));
480   CallReceiver<Descriptor>(id, argc, slot, receiver);
481 }
482 
483 template <class Descriptor>
CallReceiver(Builtin id,TNode<Int32T> argc,TNode<UintPtrT> slot,base::Optional<TNode<Object>> maybe_receiver)484 void CallOrConstructBuiltinsAssembler::CallReceiver(
485     Builtin id, TNode<Int32T> argc, TNode<UintPtrT> slot,
486     base::Optional<TNode<Object>> maybe_receiver) {
487   auto target = Parameter<Object>(Descriptor::kFunction);
488   auto context = LoadContextFromBaseline();
489   auto feedback_vector = LoadFeedbackVectorFromBaseline();
490   LazyNode<Object> receiver = [=] {
491     if (maybe_receiver) {
492       return *maybe_receiver;
493     } else {
494       CodeStubArguments args(this, argc);
495       return args.GetReceiver();
496     }
497   };
498 
499   CollectCallFeedback(target, receiver, context, feedback_vector, slot);
500   TailCallBuiltin(id, context, target, argc);
501 }
502 
TF_BUILTIN(CallWithArrayLike,CallOrConstructBuiltinsAssembler)503 TF_BUILTIN(CallWithArrayLike, CallOrConstructBuiltinsAssembler) {
504   auto target = Parameter<Object>(Descriptor::kTarget);
505   base::Optional<TNode<Object>> new_target = base::nullopt;
506   auto arguments_list = Parameter<Object>(Descriptor::kArgumentsList);
507   auto context = Parameter<Context>(Descriptor::kContext);
508   CallOrConstructWithArrayLike(target, new_target, arguments_list, context);
509 }
510 
TF_BUILTIN(CallWithArrayLike_WithFeedback,CallOrConstructBuiltinsAssembler)511 TF_BUILTIN(CallWithArrayLike_WithFeedback, CallOrConstructBuiltinsAssembler) {
512   auto target = Parameter<Object>(Descriptor::kTarget);
513   base::Optional<TNode<Object>> new_target = base::nullopt;
514   auto arguments_list = Parameter<Object>(Descriptor::kArgumentsList);
515   auto context = Parameter<Context>(Descriptor::kContext);
516   auto feedback_vector = Parameter<FeedbackVector>(Descriptor::kFeedbackVector);
517   auto slot = UncheckedParameter<UintPtrT>(Descriptor::kSlot);
518   auto receiver = Parameter<Object>(Descriptor::kReceiver);
519   CollectCallFeedback(
520       target, [=] { return receiver; }, context, feedback_vector, slot);
521   CallOrConstructWithArrayLike(target, new_target, arguments_list, context);
522 }
523 
TF_BUILTIN(CallWithSpread,CallOrConstructBuiltinsAssembler)524 TF_BUILTIN(CallWithSpread, CallOrConstructBuiltinsAssembler) {
525   auto target = Parameter<Object>(Descriptor::kTarget);
526   base::Optional<TNode<Object>> new_target = base::nullopt;
527   auto spread = Parameter<Object>(Descriptor::kSpread);
528   auto args_count = UncheckedParameter<Int32T>(Descriptor::kArgumentsCount);
529   auto context = Parameter<Context>(Descriptor::kContext);
530   CallOrConstructWithSpread(target, new_target, spread, args_count, context);
531 }
532 
TF_BUILTIN(CallWithSpread_Baseline,CallOrConstructBuiltinsAssembler)533 TF_BUILTIN(CallWithSpread_Baseline, CallOrConstructBuiltinsAssembler) {
534   auto target = Parameter<Object>(Descriptor::kTarget);
535   base::Optional<TNode<Object>> new_target = base::nullopt;
536   auto spread = Parameter<Object>(Descriptor::kSpread);
537   auto args_count = UncheckedParameter<Int32T>(Descriptor::kArgumentsCount);
538   auto context = LoadContextFromBaseline();
539   auto feedback_vector = LoadFeedbackVectorFromBaseline();
540   auto slot = UncheckedParameter<UintPtrT>(Descriptor::kSlot);
541   CodeStubArguments args(this, args_count);
542   CollectCallFeedback(
543       target, [=] { return args.GetReceiver(); }, context, feedback_vector,
544       slot);
545   CallOrConstructWithSpread(target, new_target, spread, args_count, context);
546 }
547 
TF_BUILTIN(CallWithSpread_WithFeedback,CallOrConstructBuiltinsAssembler)548 TF_BUILTIN(CallWithSpread_WithFeedback, CallOrConstructBuiltinsAssembler) {
549   auto target = Parameter<Object>(Descriptor::kTarget);
550   base::Optional<TNode<Object>> new_target = base::nullopt;
551   auto spread = Parameter<Object>(Descriptor::kSpread);
552   auto args_count = UncheckedParameter<Int32T>(Descriptor::kArgumentsCount);
553   auto context = Parameter<Context>(Descriptor::kContext);
554   auto feedback_vector = Parameter<FeedbackVector>(Descriptor::kFeedbackVector);
555   auto slot = UncheckedParameter<UintPtrT>(Descriptor::kSlot);
556   auto receiver = Parameter<Object>(Descriptor::kReceiver);
557   CollectCallFeedback(
558       target, [=] { return receiver; }, context, feedback_vector, slot);
559   CallOrConstructWithSpread(target, new_target, spread, args_count, context);
560 }
561 
GetCompatibleReceiver(TNode<JSReceiver> receiver,TNode<HeapObject> signature,TNode<Context> context)562 TNode<JSReceiver> CallOrConstructBuiltinsAssembler::GetCompatibleReceiver(
563     TNode<JSReceiver> receiver, TNode<HeapObject> signature,
564     TNode<Context> context) {
565   // Walk up the hidden prototype chain to find the compatible holder
566   // for the {signature}, starting with the {receiver} itself.
567   //
568   // Be careful, these loops are hand-tuned for (close to) ideal CSA
569   // code generation. Especially the sharing of the {var_template}
570   // below is intentional (even though it reads a bit funny in the
571   // first loop).
572   TVARIABLE(HeapObject, var_holder, receiver);
573   Label holder_loop(this, &var_holder), holder_found(this, &var_holder),
574       holder_next(this, Label::kDeferred);
575   Goto(&holder_loop);
576   BIND(&holder_loop);
577   {
578     // Find the template to compare against the {signature}. We don't
579     // bother checking that the template is a FunctionTemplateInfo here,
580     // but instead do that as part of the template loop below. The only
581     // thing we care about is that the template is actually a HeapObject.
582     TNode<HeapObject> holder = var_holder.value();
583     TVARIABLE(HeapObject, var_template, LoadMap(holder));
584     Label template_map_loop(this, &var_template),
585         template_loop(this, &var_template),
586         template_from_closure(this, &var_template);
587     Goto(&template_map_loop);
588     BIND(&template_map_loop);
589     {
590       // Load the constructor field from the current map (in the
591       // {var_template} variable), and see if that is a HeapObject.
592       // If it's a Smi then it is non-instance prototype on some
593       // initial map, which cannot be the case for API instances.
594       TNode<Object> constructor =
595           LoadObjectField(var_template.value(),
596                           Map::kConstructorOrBackPointerOrNativeContextOffset);
597       GotoIf(TaggedIsSmi(constructor), &holder_next);
598 
599       // Now there are three cases for {constructor} that we care
600       // about here:
601       //
602       //  1. {constructor} is a JSFunction, and we can load the template
603       //     from its SharedFunctionInfo::function_data field (which
604       //     may not actually be a FunctionTemplateInfo).
605       //  2. {constructor} is a Map, in which case it's not a constructor
606       //     but a back-pointer and we follow that.
607       //  3. {constructor} is a FunctionTemplateInfo (or some other
608       //     HeapObject), in which case we can directly use that for
609       //     the template loop below (non-FunctionTemplateInfo objects
610       //     will be ruled out there).
611       //
612       var_template = CAST(constructor);
613       TNode<Uint16T> template_type = LoadInstanceType(var_template.value());
614       GotoIf(IsJSFunctionInstanceType(template_type), &template_from_closure);
615       Branch(InstanceTypeEqual(template_type, MAP_TYPE), &template_map_loop,
616              &template_loop);
617     }
618 
619     BIND(&template_from_closure);
620     {
621       // The first case from above, where we load the template from the
622       // SharedFunctionInfo of the closure. We only check that the
623       // SharedFunctionInfo::function_data is a HeapObject and blindly
624       // use that as a template, since a non-FunctionTemplateInfo objects
625       // will be ruled out automatically by the template loop below.
626       TNode<SharedFunctionInfo> template_shared =
627           LoadObjectField<SharedFunctionInfo>(
628               var_template.value(), JSFunction::kSharedFunctionInfoOffset);
629       TNode<Object> template_data = LoadObjectField(
630           template_shared, SharedFunctionInfo::kFunctionDataOffset);
631       GotoIf(TaggedIsSmi(template_data), &holder_next);
632       var_template = CAST(template_data);
633       Goto(&template_loop);
634     }
635 
636     BIND(&template_loop);
637     {
638       // This loop compares the template to the expected {signature},
639       // following the chain of parent templates until it hits the
640       // end, in which case we continue with the next holder (the
641       // hidden prototype) if there's any.
642       TNode<HeapObject> current = var_template.value();
643       GotoIf(TaggedEqual(current, signature), &holder_found);
644 
645       GotoIfNot(IsFunctionTemplateInfoMap(LoadMap(current)), &holder_next);
646 
647       TNode<HeapObject> current_rare = LoadObjectField<HeapObject>(
648           current, FunctionTemplateInfo::kRareDataOffset);
649       GotoIf(IsUndefined(current_rare), &holder_next);
650       var_template = LoadObjectField<HeapObject>(
651           current_rare, FunctionTemplateRareData::kParentTemplateOffset);
652       Goto(&template_loop);
653     }
654 
655     BIND(&holder_next);
656     {
657       // Continue with the hidden prototype of the {holder} if it is a
658       // JSGlobalProxy (the hidden prototype can either be null or a
659       // JSObject in that case), or throw an illegal invocation exception,
660       // since the receiver did not pass the {signature} check.
661       TNode<Map> holder_map = LoadMap(holder);
662       var_holder = LoadMapPrototype(holder_map);
663       GotoIf(IsJSGlobalProxyMap(holder_map), &holder_loop);
664       ThrowTypeError(context, MessageTemplate::kIllegalInvocation);
665     }
666   }
667 
668   BIND(&holder_found);
669   return CAST(var_holder.value());
670 }
671 
672 // This calls an API callback by passing a {FunctionTemplateInfo},
673 // does appropriate access and compatible receiver checks.
CallFunctionTemplate(CallFunctionTemplateMode mode,TNode<FunctionTemplateInfo> function_template_info,TNode<IntPtrT> argc,TNode<Context> context)674 void CallOrConstructBuiltinsAssembler::CallFunctionTemplate(
675     CallFunctionTemplateMode mode,
676     TNode<FunctionTemplateInfo> function_template_info, TNode<IntPtrT> argc,
677     TNode<Context> context) {
678   CodeStubArguments args(this, argc);
679   Label throw_illegal_invocation(this, Label::kDeferred);
680 
681   // For API callbacks the receiver is always a JSReceiver (since
682   // they are treated like sloppy mode functions). We might need
683   // to perform access checks in the current {context}, depending
684   // on whether the "needs access check" bit is set on the receiver
685   // _and_ the {function_template_info} doesn't have the "accepts
686   // any receiver" bit set.
687   TNode<JSReceiver> receiver = CAST(args.GetReceiver());
688   if (mode == CallFunctionTemplateMode::kCheckAccess ||
689       mode == CallFunctionTemplateMode::kCheckAccessAndCompatibleReceiver) {
690     TNode<Map> receiver_map = LoadMap(receiver);
691     Label receiver_needs_access_check(this, Label::kDeferred),
692         receiver_done(this);
693     GotoIfNot(IsSetWord32<Map::Bits1::IsAccessCheckNeededBit>(
694                   LoadMapBitField(receiver_map)),
695               &receiver_done);
696     TNode<IntPtrT> function_template_info_flags = LoadAndUntagObjectField(
697         function_template_info, FunctionTemplateInfo::kFlagOffset);
698     Branch(IsSetWord(function_template_info_flags,
699                      1 << FunctionTemplateInfo::AcceptAnyReceiverBit::kShift),
700            &receiver_done, &receiver_needs_access_check);
701 
702     BIND(&receiver_needs_access_check);
703     {
704       CallRuntime(Runtime::kAccessCheck, context, receiver);
705       Goto(&receiver_done);
706     }
707 
708     BIND(&receiver_done);
709   }
710 
711   // Figure out the API holder for the {receiver} depending on the
712   // {mode} and the signature on the {function_template_info}.
713   TNode<JSReceiver> holder;
714   if (mode == CallFunctionTemplateMode::kCheckAccess) {
715     // We did the access check (including the ToObject) above, so
716     // {receiver} is a JSReceiver at this point, and we don't need
717     // to perform any "compatible receiver check", so {holder} is
718     // actually the {receiver}.
719     holder = receiver;
720   } else {
721     // If the {function_template_info} doesn't specify any signature, we
722     // just use the receiver as the holder for the API callback, otherwise
723     // we need to look for a compatible holder in the receiver's hidden
724     // prototype chain.
725     TNode<HeapObject> signature = LoadObjectField<HeapObject>(
726         function_template_info, FunctionTemplateInfo::kSignatureOffset);
727     holder = Select<JSReceiver>(
728         IsUndefined(signature),  // --
729         [&]() { return receiver; },
730         [&]() { return GetCompatibleReceiver(receiver, signature, context); });
731   }
732 
733   // Perform the actual API callback invocation via CallApiCallback.
734   TNode<CallHandlerInfo> call_handler_info = LoadObjectField<CallHandlerInfo>(
735       function_template_info, FunctionTemplateInfo::kCallCodeOffset);
736   TNode<Foreign> foreign = LoadObjectField<Foreign>(
737       call_handler_info, CallHandlerInfo::kJsCallbackOffset);
738   TNode<RawPtrT> callback = LoadForeignForeignAddressPtr(foreign);
739   TNode<Object> call_data =
740       LoadObjectField<Object>(call_handler_info, CallHandlerInfo::kDataOffset);
741   TailCallStub(CodeFactory::CallApiCallback(isolate()), context, callback,
742                args.GetLengthWithoutReceiver(), call_data, holder);
743 }
744 
TF_BUILTIN(CallFunctionTemplate_CheckAccess,CallOrConstructBuiltinsAssembler)745 TF_BUILTIN(CallFunctionTemplate_CheckAccess, CallOrConstructBuiltinsAssembler) {
746   auto context = Parameter<Context>(Descriptor::kContext);
747   auto function_template_info = UncheckedParameter<FunctionTemplateInfo>(
748       Descriptor::kFunctionTemplateInfo);
749   auto argc = UncheckedParameter<IntPtrT>(Descriptor::kArgumentsCount);
750   CallFunctionTemplate(CallFunctionTemplateMode::kCheckAccess,
751                        function_template_info, argc, context);
752 }
753 
TF_BUILTIN(CallFunctionTemplate_CheckCompatibleReceiver,CallOrConstructBuiltinsAssembler)754 TF_BUILTIN(CallFunctionTemplate_CheckCompatibleReceiver,
755            CallOrConstructBuiltinsAssembler) {
756   auto context = Parameter<Context>(Descriptor::kContext);
757   auto function_template_info = UncheckedParameter<FunctionTemplateInfo>(
758       Descriptor::kFunctionTemplateInfo);
759   auto argc = UncheckedParameter<IntPtrT>(Descriptor::kArgumentsCount);
760   CallFunctionTemplate(CallFunctionTemplateMode::kCheckCompatibleReceiver,
761                        function_template_info, argc, context);
762 }
763 
TF_BUILTIN(CallFunctionTemplate_CheckAccessAndCompatibleReceiver,CallOrConstructBuiltinsAssembler)764 TF_BUILTIN(CallFunctionTemplate_CheckAccessAndCompatibleReceiver,
765            CallOrConstructBuiltinsAssembler) {
766   auto context = Parameter<Context>(Descriptor::kContext);
767   auto function_template_info = UncheckedParameter<FunctionTemplateInfo>(
768       Descriptor::kFunctionTemplateInfo);
769   auto argc = UncheckedParameter<IntPtrT>(Descriptor::kArgumentsCount);
770   CallFunctionTemplate(
771       CallFunctionTemplateMode::kCheckAccessAndCompatibleReceiver,
772       function_template_info, argc, context);
773 }
774 
775 }  // namespace internal
776 }  // namespace v8
777