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