• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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/compiler/linkage.h"
6 
7 #include "src/codegen/assembler-inl.h"
8 #include "src/codegen/macro-assembler.h"
9 #include "src/codegen/optimized-compilation-info.h"
10 #include "src/compiler/frame.h"
11 #include "src/compiler/osr.h"
12 #include "src/compiler/pipeline.h"
13 
14 namespace v8 {
15 namespace internal {
16 namespace compiler {
17 
18 namespace {
19 
regloc(Register reg,MachineType type)20 inline LinkageLocation regloc(Register reg, MachineType type) {
21   return LinkageLocation::ForRegister(reg.code(), type);
22 }
23 
regloc(DoubleRegister reg,MachineType type)24 inline LinkageLocation regloc(DoubleRegister reg, MachineType type) {
25   return LinkageLocation::ForRegister(reg.code(), type);
26 }
27 
28 }  // namespace
29 
30 
operator <<(std::ostream & os,const CallDescriptor::Kind & k)31 std::ostream& operator<<(std::ostream& os, const CallDescriptor::Kind& k) {
32   switch (k) {
33     case CallDescriptor::kCallCodeObject:
34       os << "Code";
35       break;
36     case CallDescriptor::kCallJSFunction:
37       os << "JS";
38       break;
39     case CallDescriptor::kCallAddress:
40       os << "Addr";
41       break;
42     case CallDescriptor::kCallWasmCapiFunction:
43       os << "WasmExit";
44       break;
45     case CallDescriptor::kCallWasmFunction:
46       os << "WasmFunction";
47       break;
48     case CallDescriptor::kCallWasmImportWrapper:
49       os << "WasmImportWrapper";
50       break;
51     case CallDescriptor::kCallBuiltinPointer:
52       os << "BuiltinPointer";
53       break;
54   }
55   return os;
56 }
57 
58 
operator <<(std::ostream & os,const CallDescriptor & d)59 std::ostream& operator<<(std::ostream& os, const CallDescriptor& d) {
60   // TODO(svenpanne) Output properties etc. and be less cryptic.
61   return os << d.kind() << ":" << d.debug_name() << ":r" << d.ReturnCount()
62             << "s" << d.StackParameterCount() << "i" << d.InputCount() << "f"
63             << d.FrameStateCount();
64 }
65 
GetMachineSignature(Zone * zone) const66 MachineSignature* CallDescriptor::GetMachineSignature(Zone* zone) const {
67   size_t param_count = ParameterCount();
68   size_t return_count = ReturnCount();
69   MachineType* types = zone->NewArray<MachineType>(param_count + return_count);
70   int current = 0;
71   for (size_t i = 0; i < return_count; ++i) {
72     types[current++] = GetReturnType(i);
73   }
74   for (size_t i = 0; i < param_count; ++i) {
75     types[current++] = GetParameterType(i);
76   }
77   return zone->New<MachineSignature>(return_count, param_count, types);
78 }
79 
GetFirstUnusedStackSlot() const80 int CallDescriptor::GetFirstUnusedStackSlot() const {
81   int slots_above_sp = 0;
82   for (size_t i = 0; i < InputCount(); ++i) {
83     LinkageLocation operand = GetInputLocation(i);
84     if (!operand.IsRegister()) {
85       int new_candidate =
86           -operand.GetLocation() + operand.GetSizeInPointers() - 1;
87       if (new_candidate > slots_above_sp) {
88         slots_above_sp = new_candidate;
89       }
90     }
91   }
92   return slots_above_sp;
93 }
94 
GetStackParameterDelta(CallDescriptor const * tail_caller) const95 int CallDescriptor::GetStackParameterDelta(
96     CallDescriptor const* tail_caller) const {
97   // In the IsTailCallForTierUp case, the callee has
98   // identical linkage and runtime arguments to the caller, thus the stack
99   // parameter delta is 0. We don't explicitly pass the runtime arguments as
100   // inputs to the TailCall node, since they already exist on the stack.
101   if (IsTailCallForTierUp()) return 0;
102 
103   int callee_slots_above_sp = GetFirstUnusedStackSlot();
104   int tail_caller_slots_above_sp = tail_caller->GetFirstUnusedStackSlot();
105   int stack_param_delta = callee_slots_above_sp - tail_caller_slots_above_sp;
106   if (ShouldPadArguments(stack_param_delta)) {
107     if (callee_slots_above_sp % 2 != 0) {
108       // The delta is odd due to the callee - we will need to add one slot
109       // of padding.
110       ++stack_param_delta;
111     } else {
112       DCHECK_NE(tail_caller_slots_above_sp % 2, 0);
113       // The delta is odd because of the caller. We already have one slot of
114       // padding that we can reuse for arguments, so we will need one fewer
115       // slot.
116       --stack_param_delta;
117     }
118   }
119   return stack_param_delta;
120 }
121 
GetTaggedParameterSlots() const122 int CallDescriptor::GetTaggedParameterSlots() const {
123   int result = 0;
124   for (size_t i = 0; i < InputCount(); ++i) {
125     LinkageLocation operand = GetInputLocation(i);
126     if (!operand.IsRegister() && operand.GetType().IsTagged()) {
127       ++result;
128     }
129   }
130   return result;
131 }
132 
CanTailCall(const CallDescriptor * callee) const133 bool CallDescriptor::CanTailCall(const CallDescriptor* callee) const {
134   if (ReturnCount() != callee->ReturnCount()) return false;
135   const int stack_param_delta = callee->GetStackParameterDelta(this);
136   for (size_t i = 0; i < ReturnCount(); ++i) {
137     if (GetReturnLocation(i).IsCallerFrameSlot() &&
138         callee->GetReturnLocation(i).IsCallerFrameSlot()) {
139       if (GetReturnLocation(i).AsCallerFrameSlot() - stack_param_delta !=
140           callee->GetReturnLocation(i).AsCallerFrameSlot()) {
141         return false;
142       }
143     } else if (!LinkageLocation::IsSameLocation(GetReturnLocation(i),
144                                                 callee->GetReturnLocation(i))) {
145       return false;
146     }
147   }
148   return true;
149 }
150 
151 // TODO(jkummerow, sigurds): Arguably frame size calculation should be
152 // keyed on code/frame type, not on CallDescriptor kind. Think about a
153 // good way to organize this logic.
CalculateFixedFrameSize(CodeKind code_kind) const154 int CallDescriptor::CalculateFixedFrameSize(CodeKind code_kind) const {
155   switch (kind_) {
156     case kCallJSFunction:
157       return StandardFrameConstants::kFixedSlotCount;
158     case kCallAddress:
159       if (code_kind == CodeKind::C_WASM_ENTRY) {
160         return CWasmEntryFrameConstants::kFixedSlotCount;
161       }
162       return CommonFrameConstants::kFixedSlotCountAboveFp +
163              CommonFrameConstants::kCPSlotCount;
164     case kCallCodeObject:
165     case kCallBuiltinPointer:
166       return TypedFrameConstants::kFixedSlotCount;
167     case kCallWasmFunction:
168     case kCallWasmImportWrapper:
169       return WasmFrameConstants::kFixedSlotCount;
170     case kCallWasmCapiFunction:
171       return WasmExitFrameConstants::kFixedSlotCount;
172   }
173   UNREACHABLE();
174 }
175 
ComputeIncoming(Zone * zone,OptimizedCompilationInfo * info)176 CallDescriptor* Linkage::ComputeIncoming(Zone* zone,
177                                          OptimizedCompilationInfo* info) {
178   DCHECK(info->IsOptimizing() || info->IsWasm());
179   if (!info->closure().is_null()) {
180     // If we are compiling a JS function, use a JS call descriptor,
181     // plus the receiver.
182     SharedFunctionInfo shared = info->closure()->shared();
183     return GetJSCallDescriptor(zone, info->is_osr(),
184                                1 + shared.internal_formal_parameter_count(),
185                                CallDescriptor::kCanUseRoots);
186   }
187   return nullptr;  // TODO(titzer): ?
188 }
189 
190 
191 // static
NeedsFrameStateInput(Runtime::FunctionId function)192 bool Linkage::NeedsFrameStateInput(Runtime::FunctionId function) {
193   switch (function) {
194     // Most runtime functions need a FrameState. A few chosen ones that we know
195     // not to call into arbitrary JavaScript, not to throw, and not to lazily
196     // deoptimize are allowlisted here and can be called without a FrameState.
197     case Runtime::kAbort:
198     case Runtime::kAllocateInOldGeneration:
199     case Runtime::kCreateIterResultObject:
200     case Runtime::kIncBlockCounter:
201     case Runtime::kIsFunction:
202     case Runtime::kNewClosure:
203     case Runtime::kNewClosure_Tenured:
204     case Runtime::kNewFunctionContext:
205     case Runtime::kPushBlockContext:
206     case Runtime::kPushCatchContext:
207     case Runtime::kReThrow:
208     case Runtime::kStringEqual:
209     case Runtime::kStringLessThan:
210     case Runtime::kStringLessThanOrEqual:
211     case Runtime::kStringGreaterThan:
212     case Runtime::kStringGreaterThanOrEqual:
213     case Runtime::kToFastProperties:  // TODO(conradw): Is it safe?
214     case Runtime::kTraceEnter:
215     case Runtime::kTraceExit:
216       return false;
217 
218     // Some inline intrinsics are also safe to call without a FrameState.
219     case Runtime::kInlineCreateIterResultObject:
220     case Runtime::kInlineIncBlockCounter:
221     case Runtime::kInlineGeneratorClose:
222     case Runtime::kInlineGeneratorGetResumeMode:
223     case Runtime::kInlineCreateJSGeneratorObject:
224     case Runtime::kInlineIsArray:
225     case Runtime::kInlineIsJSReceiver:
226     case Runtime::kInlineIsRegExp:
227     case Runtime::kInlineIsSmi:
228       return false;
229 
230     default:
231       break;
232   }
233 
234   // For safety, default to needing a FrameState unless allowlisted.
235   return true;
236 }
237 
238 
UsesOnlyRegisters() const239 bool CallDescriptor::UsesOnlyRegisters() const {
240   for (size_t i = 0; i < InputCount(); ++i) {
241     if (!GetInputLocation(i).IsRegister()) return false;
242   }
243   for (size_t i = 0; i < ReturnCount(); ++i) {
244     if (!GetReturnLocation(i).IsRegister()) return false;
245   }
246   return true;
247 }
248 
249 
GetRuntimeCallDescriptor(Zone * zone,Runtime::FunctionId function_id,int js_parameter_count,Operator::Properties properties,CallDescriptor::Flags flags)250 CallDescriptor* Linkage::GetRuntimeCallDescriptor(
251     Zone* zone, Runtime::FunctionId function_id, int js_parameter_count,
252     Operator::Properties properties, CallDescriptor::Flags flags) {
253   const Runtime::Function* function = Runtime::FunctionForId(function_id);
254   const int return_count = function->result_size;
255   const char* debug_name = function->name;
256 
257   if (!Linkage::NeedsFrameStateInput(function_id)) {
258     flags = static_cast<CallDescriptor::Flags>(
259         flags & ~CallDescriptor::kNeedsFrameState);
260   }
261 
262   return GetCEntryStubCallDescriptor(zone, return_count, js_parameter_count,
263                                      debug_name, properties, flags);
264 }
265 
GetCEntryStubCallDescriptor(Zone * zone,int return_count,int js_parameter_count,const char * debug_name,Operator::Properties properties,CallDescriptor::Flags flags,StackArgumentOrder stack_order)266 CallDescriptor* Linkage::GetCEntryStubCallDescriptor(
267     Zone* zone, int return_count, int js_parameter_count,
268     const char* debug_name, Operator::Properties properties,
269     CallDescriptor::Flags flags, StackArgumentOrder stack_order) {
270   const size_t function_count = 1;
271   const size_t num_args_count = 1;
272   const size_t context_count = 1;
273   const size_t parameter_count = function_count +
274                                  static_cast<size_t>(js_parameter_count) +
275                                  num_args_count + context_count;
276 
277   LocationSignature::Builder locations(zone, static_cast<size_t>(return_count),
278                                        static_cast<size_t>(parameter_count));
279 
280   // Add returns.
281   if (locations.return_count_ > 0) {
282     locations.AddReturn(regloc(kReturnRegister0, MachineType::AnyTagged()));
283   }
284   if (locations.return_count_ > 1) {
285     locations.AddReturn(regloc(kReturnRegister1, MachineType::AnyTagged()));
286   }
287   if (locations.return_count_ > 2) {
288     locations.AddReturn(regloc(kReturnRegister2, MachineType::AnyTagged()));
289   }
290 
291   // All parameters to the runtime call go on the stack.
292   for (int i = 0; i < js_parameter_count; i++) {
293     locations.AddParam(LinkageLocation::ForCallerFrameSlot(
294         i - js_parameter_count, MachineType::AnyTagged()));
295   }
296   // Add runtime function itself.
297   locations.AddParam(
298       regloc(kRuntimeCallFunctionRegister, MachineType::Pointer()));
299 
300   // Add runtime call argument count.
301   locations.AddParam(
302       regloc(kRuntimeCallArgCountRegister, MachineType::Int32()));
303 
304   // Add context.
305   locations.AddParam(regloc(kContextRegister, MachineType::AnyTagged()));
306 
307   // The target for runtime calls is a code object.
308   MachineType target_type = MachineType::AnyTagged();
309   LinkageLocation target_loc =
310       LinkageLocation::ForAnyRegister(MachineType::AnyTagged());
311   return zone->New<CallDescriptor>(     // --
312       CallDescriptor::kCallCodeObject,  // kind
313       target_type,                      // target MachineType
314       target_loc,                       // target location
315       locations.Build(),                // location_sig
316       js_parameter_count,               // stack_parameter_count
317       properties,                       // properties
318       kNoCalleeSaved,                   // callee-saved
319       kNoCalleeSaved,                   // callee-saved fp
320       flags,                            // flags
321       debug_name,                       // debug name
322       stack_order);                     // stack order
323 }
324 
GetJSCallDescriptor(Zone * zone,bool is_osr,int js_parameter_count,CallDescriptor::Flags flags)325 CallDescriptor* Linkage::GetJSCallDescriptor(Zone* zone, bool is_osr,
326                                              int js_parameter_count,
327                                              CallDescriptor::Flags flags) {
328   const size_t return_count = 1;
329   const size_t context_count = 1;
330   const size_t new_target_count = 1;
331   const size_t num_args_count = 1;
332   const size_t parameter_count =
333       js_parameter_count + new_target_count + num_args_count + context_count;
334 
335   LocationSignature::Builder locations(zone, return_count, parameter_count);
336 
337   // All JS calls have exactly one return value.
338   locations.AddReturn(regloc(kReturnRegister0, MachineType::AnyTagged()));
339 
340   // All parameters to JS calls go on the stack.
341   for (int i = 0; i < js_parameter_count; i++) {
342     int spill_slot_index = -i - 1;
343     locations.AddParam(LinkageLocation::ForCallerFrameSlot(
344         spill_slot_index, MachineType::AnyTagged()));
345   }
346 
347   // Add JavaScript call new target value.
348   locations.AddParam(
349       regloc(kJavaScriptCallNewTargetRegister, MachineType::AnyTagged()));
350 
351   // Add JavaScript call argument count.
352   locations.AddParam(
353       regloc(kJavaScriptCallArgCountRegister, MachineType::Int32()));
354 
355   // Add context.
356   locations.AddParam(regloc(kContextRegister, MachineType::AnyTagged()));
357 
358   // The target for JS function calls is the JSFunction object.
359   MachineType target_type = MachineType::AnyTagged();
360   // When entering into an OSR function from unoptimized code the JSFunction
361   // is not in a register, but it is on the stack in the marker spill slot.
362   LinkageLocation target_loc =
363       is_osr ? LinkageLocation::ForSavedCallerFunction()
364              : regloc(kJSFunctionRegister, MachineType::AnyTagged());
365   return zone->New<CallDescriptor>(     // --
366       CallDescriptor::kCallJSFunction,  // kind
367       target_type,                      // target MachineType
368       target_loc,                       // target location
369       locations.Build(),                // location_sig
370       js_parameter_count,               // stack_parameter_count
371       Operator::kNoProperties,          // properties
372       kNoCalleeSaved,                   // callee-saved
373       kNoCalleeSaved,                   // callee-saved fp
374       flags,                            // flags
375       "js-call");                       // debug name
376 }
377 
378 // TODO(turbofan): cache call descriptors for code stub calls.
379 // TODO(jgruber): Clean up stack parameter count handling. The descriptor
380 // already knows the formal stack parameter count and ideally only additional
381 // stack parameters should be passed into this method. All call-sites should
382 // be audited for correctness (e.g. many used to assume a stack parameter count
383 // of 0).
GetStubCallDescriptor(Zone * zone,const CallInterfaceDescriptor & descriptor,int stack_parameter_count,CallDescriptor::Flags flags,Operator::Properties properties,StubCallMode stub_mode)384 CallDescriptor* Linkage::GetStubCallDescriptor(
385     Zone* zone, const CallInterfaceDescriptor& descriptor,
386     int stack_parameter_count, CallDescriptor::Flags flags,
387     Operator::Properties properties, StubCallMode stub_mode) {
388   const int register_parameter_count = descriptor.GetRegisterParameterCount();
389   const int js_parameter_count =
390       register_parameter_count + stack_parameter_count;
391   const int context_count = descriptor.HasContextParameter() ? 1 : 0;
392   const size_t parameter_count =
393       static_cast<size_t>(js_parameter_count + context_count);
394 
395   DCHECK_GE(stack_parameter_count, descriptor.GetStackParameterCount());
396 
397   size_t return_count = descriptor.GetReturnCount();
398   LocationSignature::Builder locations(zone, return_count, parameter_count);
399 
400   // Add returns.
401   static constexpr Register return_registers[] = {
402       kReturnRegister0, kReturnRegister1, kReturnRegister2};
403   size_t num_returns = 0;
404   size_t num_fp_returns = 0;
405   for (size_t i = 0; i < locations.return_count_; i++) {
406     MachineType type = descriptor.GetReturnType(static_cast<int>(i));
407     if (IsFloatingPoint(type.representation())) {
408       DCHECK_LT(num_fp_returns, 1);  // Only 1 FP return is supported.
409       locations.AddReturn(regloc(kFPReturnRegister0, type));
410       num_fp_returns++;
411     } else {
412       DCHECK_LT(num_returns, arraysize(return_registers));
413       locations.AddReturn(regloc(return_registers[num_returns], type));
414       num_returns++;
415     }
416   }
417 
418   // Add parameters in registers and on the stack.
419   for (int i = 0; i < js_parameter_count; i++) {
420     if (i < register_parameter_count) {
421       // The first parameters go in registers.
422       // TODO(bbudge) Add floating point registers to the InterfaceDescriptor
423       // and use them for FP types. Currently, this works because on most
424       // platforms, all FP registers are available for use. On ia32, xmm0 is
425       // not allocatable and so we must work around that with platform-specific
426       // descriptors, adjusting the GP register set to avoid eax, which has
427       // register code 0.
428       Register reg = descriptor.GetRegisterParameter(i);
429       MachineType type = descriptor.GetParameterType(i);
430       locations.AddParam(regloc(reg, type));
431     } else {
432       // The rest of the parameters go on the stack.
433       int stack_slot = i - register_parameter_count - stack_parameter_count;
434       locations.AddParam(LinkageLocation::ForCallerFrameSlot(
435           stack_slot, i < descriptor.GetParameterCount()
436                           ? descriptor.GetParameterType(i)
437                           : MachineType::AnyTagged()));
438     }
439   }
440   // Add context.
441   if (context_count) {
442     locations.AddParam(regloc(kContextRegister, MachineType::AnyTagged()));
443   }
444 
445   // The target for stub calls depends on the requested mode.
446   CallDescriptor::Kind kind;
447   MachineType target_type;
448   switch (stub_mode) {
449     case StubCallMode::kCallCodeObject:
450       kind = CallDescriptor::kCallCodeObject;
451       target_type = MachineType::AnyTagged();
452       break;
453     case StubCallMode::kCallWasmRuntimeStub:
454       kind = CallDescriptor::kCallWasmFunction;
455       target_type = MachineType::Pointer();
456       break;
457     case StubCallMode::kCallBuiltinPointer:
458       kind = CallDescriptor::kCallBuiltinPointer;
459       target_type = MachineType::AnyTagged();
460       break;
461   }
462 
463   LinkageLocation target_loc = LinkageLocation::ForAnyRegister(target_type);
464   return zone->New<CallDescriptor>(          // --
465       kind,                                  // kind
466       target_type,                           // target MachineType
467       target_loc,                            // target location
468       locations.Build(),                     // location_sig
469       stack_parameter_count,                 // stack_parameter_count
470       properties,                            // properties
471       kNoCalleeSaved,                        // callee-saved registers
472       kNoCalleeSaved,                        // callee-saved fp
473       CallDescriptor::kCanUseRoots | flags,  // flags
474       descriptor.DebugName(),                // debug name
475       descriptor.GetStackArgumentOrder(),    // stack order
476       descriptor.allocatable_registers());
477 }
478 
479 // static
GetBytecodeDispatchCallDescriptor(Zone * zone,const CallInterfaceDescriptor & descriptor,int stack_parameter_count)480 CallDescriptor* Linkage::GetBytecodeDispatchCallDescriptor(
481     Zone* zone, const CallInterfaceDescriptor& descriptor,
482     int stack_parameter_count) {
483   const int register_parameter_count = descriptor.GetRegisterParameterCount();
484   const int parameter_count = register_parameter_count + stack_parameter_count;
485 
486   DCHECK_EQ(descriptor.GetReturnCount(), 1);
487   LocationSignature::Builder locations(zone, 1, parameter_count);
488 
489   locations.AddReturn(regloc(kReturnRegister0, descriptor.GetReturnType(0)));
490 
491   // Add parameters in registers and on the stack.
492   for (int i = 0; i < parameter_count; i++) {
493     if (i < register_parameter_count) {
494       // The first parameters go in registers.
495       Register reg = descriptor.GetRegisterParameter(i);
496       MachineType type = descriptor.GetParameterType(i);
497       locations.AddParam(regloc(reg, type));
498     } else {
499       // The rest of the parameters go on the stack.
500       int stack_slot = i - register_parameter_count - stack_parameter_count;
501       locations.AddParam(LinkageLocation::ForCallerFrameSlot(
502           stack_slot, MachineType::AnyTagged()));
503     }
504   }
505 
506   // The target for interpreter dispatches is a code entry address.
507   MachineType target_type = MachineType::Pointer();
508   LinkageLocation target_loc = LinkageLocation::ForAnyRegister(target_type);
509   const CallDescriptor::Flags kFlags =
510       CallDescriptor::kCanUseRoots | CallDescriptor::kFixedTargetRegister;
511   return zone->New<CallDescriptor>(  // --
512       CallDescriptor::kCallAddress,  // kind
513       target_type,                   // target MachineType
514       target_loc,                    // target location
515       locations.Build(),             // location_sig
516       stack_parameter_count,         // stack_parameter_count
517       Operator::kNoProperties,       // properties
518       kNoCalleeSaved,                // callee-saved registers
519       kNoCalleeSaved,                // callee-saved fp
520       kFlags,                        // flags
521       descriptor.DebugName());
522 }
523 
GetOsrValueLocation(int index) const524 LinkageLocation Linkage::GetOsrValueLocation(int index) const {
525   CHECK(incoming_->IsJSFunctionCall());
526   int parameter_count = static_cast<int>(incoming_->JSParameterCount() - 1);
527   int first_stack_slot = OsrHelper::FirstStackSlotIndex(parameter_count);
528 
529   if (index == kOsrContextSpillSlotIndex) {
530     // Context. Use the parameter location of the context spill slot.
531     // Parameter (arity + 2) is special for the context of the function frame.
532     // >> context_index = target + receiver + params + new_target + #args
533     int context_index = 1 + 1 + parameter_count + 1 + 1;
534     return incoming_->GetInputLocation(context_index);
535   } else if (index >= first_stack_slot) {
536     // Local variable stored in this (callee) stack.
537     int spill_index =
538         index - first_stack_slot + StandardFrameConstants::kFixedSlotCount;
539     return LinkageLocation::ForCalleeFrameSlot(spill_index,
540                                                MachineType::AnyTagged());
541   } else {
542     // Parameter. Use the assigned location from the incoming call descriptor.
543     int parameter_index = 1 + index;  // skip index 0, which is the target.
544     return incoming_->GetInputLocation(parameter_index);
545   }
546 }
547 
548 namespace {
IsTaggedReg(const LinkageLocation & loc,Register reg)549 inline bool IsTaggedReg(const LinkageLocation& loc, Register reg) {
550   return loc.IsRegister() && loc.AsRegister() == reg.code() &&
551          loc.GetType().representation() ==
552              MachineRepresentation::kTaggedPointer;
553 }
554 }  // namespace
555 
ParameterHasSecondaryLocation(int index) const556 bool Linkage::ParameterHasSecondaryLocation(int index) const {
557   // TODO(titzer): this should be configurable, not call-type specific.
558   if (incoming_->IsJSFunctionCall()) {
559     LinkageLocation loc = GetParameterLocation(index);
560     return IsTaggedReg(loc, kJSFunctionRegister) ||
561            IsTaggedReg(loc, kContextRegister);
562   }
563   if (incoming_->IsWasmFunctionCall()) {
564     LinkageLocation loc = GetParameterLocation(index);
565     return IsTaggedReg(loc, kWasmInstanceRegister);
566   }
567   return false;
568 }
569 
GetParameterSecondaryLocation(int index) const570 LinkageLocation Linkage::GetParameterSecondaryLocation(int index) const {
571   // TODO(titzer): these constants are necessary due to offset/slot# mismatch
572   static const int kJSContextSlot = 2 + StandardFrameConstants::kCPSlotCount;
573   static const int kJSFunctionSlot = 3 + StandardFrameConstants::kCPSlotCount;
574   static const int kWasmInstanceSlot = 3 + StandardFrameConstants::kCPSlotCount;
575 
576   DCHECK(ParameterHasSecondaryLocation(index));
577   LinkageLocation loc = GetParameterLocation(index);
578 
579   // TODO(titzer): this should be configurable, not call-type specific.
580   if (incoming_->IsJSFunctionCall()) {
581     if (IsTaggedReg(loc, kJSFunctionRegister)) {
582       return LinkageLocation::ForCalleeFrameSlot(kJSFunctionSlot,
583                                                  MachineType::AnyTagged());
584     } else {
585       DCHECK(IsTaggedReg(loc, kContextRegister));
586       return LinkageLocation::ForCalleeFrameSlot(kJSContextSlot,
587                                                  MachineType::AnyTagged());
588     }
589   }
590   if (incoming_->IsWasmFunctionCall()) {
591     DCHECK(IsTaggedReg(loc, kWasmInstanceRegister));
592     return LinkageLocation::ForCalleeFrameSlot(kWasmInstanceSlot,
593                                                MachineType::AnyTagged());
594   }
595   UNREACHABLE();
596   return LinkageLocation::ForCalleeFrameSlot(0, MachineType::AnyTagged());
597 }
598 
599 
600 }  // namespace compiler
601 }  // namespace internal
602 }  // namespace v8
603