v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
linkage.cc
Go to the documentation of this file.
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
6
11#include "src/compiler/frame.h"
13#include "src/compiler/osr.h"
15
16#if V8_ENABLE_WEBASSEMBLY
18#endif
19
20namespace v8 {
21namespace internal {
22namespace compiler {
23
24namespace {
25
26// Offsets from callee to caller frame, in slots.
27constexpr int kFirstCallerSlotOffset = 1;
28constexpr int kNoCallerSlotOffset = 0;
29
30inline LinkageLocation regloc(Register reg, MachineType type) {
31 return LinkageLocation::ForRegister(reg.code(), type);
32}
33
34inline LinkageLocation regloc(DoubleRegister reg, MachineType type) {
35 return LinkageLocation::ForRegister(reg.code(), type);
36}
37
38} // namespace
39
40
41std::ostream& operator<<(std::ostream& os, const CallDescriptor::Kind& k) {
42 switch (k) {
44 os << "Code";
45 break;
47 os << "JS";
48 break;
50 os << "Addr";
51 break;
52#if V8_ENABLE_WEBASSEMBLY
53 case CallDescriptor::kCallWasmCapiFunction:
54 os << "WasmExit";
55 break;
56 case CallDescriptor::kCallWasmFunction:
57 os << "WasmFunction";
58 break;
59 case CallDescriptor::kCallWasmFunctionIndirect:
60 os << "WasmFunctionIndirect";
61 break;
62 case CallDescriptor::kCallWasmImportWrapper:
63 os << "WasmImportWrapper";
64 break;
65#endif // V8_ENABLE_WEBASSEMBLY
67 os << "BuiltinPointer";
68 break;
69 }
70 return os;
71}
72
73
74std::ostream& operator<<(std::ostream& os, const CallDescriptor& d) {
75 // TODO(svenpanne) Output properties etc. and be less cryptic.
76 return os << d.kind() << ":" << d.debug_name() << ":r" << d.ReturnCount()
77 << "s" << d.ParameterSlotCount() << "i" << d.InputCount() << "f"
78 << d.FrameStateCount();
79}
80
82 size_t param_count = ParameterCount();
83 size_t return_count = ReturnCount();
84 MachineType* types =
85 zone->AllocateArray<MachineType>(param_count + return_count);
86 int current = 0;
87 for (size_t i = 0; i < return_count; ++i) {
88 types[current++] = GetReturnType(i);
89 }
90 for (size_t i = 0; i < param_count; ++i) {
91 types[current++] = GetParameterType(i);
92 }
93 return zone->New<MachineSignature>(return_count, param_count, types);
94}
95
97 CallDescriptor const* tail_caller) const {
98 // In the IsTailCallForTierUp case, the callee has
99 // identical linkage and runtime arguments to the caller, thus the stack
100 // parameter delta is 0. We don't explicitly pass the runtime arguments as
101 // inputs to the TailCall node, since they already exist on the stack.
102 if (IsTailCallForTierUp()) return 0;
103
104 // Add padding if necessary before computing the stack parameter delta.
105 int callee_slots_above_sp = AddArgumentPaddingSlots(GetOffsetToReturns());
106 int tail_caller_slots_above_sp =
108 int stack_param_delta = callee_slots_above_sp - tail_caller_slots_above_sp;
109 DCHECK(!ShouldPadArguments(stack_param_delta));
110 return stack_param_delta;
111}
112
114 int offset = kFirstCallerSlotOffset;
115 for (size_t i = 0; i < InputCount(); ++i) {
117 if (!operand.IsRegister()) {
118 DCHECK(operand.IsCallerFrameSlot());
119 int slot_offset = -operand.GetLocation();
120 offset = std::max(offset, slot_offset + operand.GetSizeInPointers());
121 }
122 }
123 return offset;
124}
125
127 // Find the return slot with the least offset relative to the callee.
128 int offset = kNoCallerSlotOffset;
129 for (size_t i = 0; i < ReturnCount(); ++i) {
131 if (!operand.IsRegister()) {
132 DCHECK(operand.IsCallerFrameSlot());
133 int slot_offset = -operand.GetLocation();
134 offset = std::min(offset, slot_offset);
135 }
136 }
137 // If there was a return slot, return the offset minus 1 slot.
138 if (offset != kNoCallerSlotOffset) {
139 return offset - 1;
140 }
141
142 // Otherwise, return the first slot after the parameters area, including
143 // optional padding slots.
144 int last_argument_slot = GetOffsetToFirstUnusedStackSlot() - 1;
145 offset = AddArgumentPaddingSlots(last_argument_slot);
146
148 return offset;
149}
150
152 uint32_t count = 0;
153 uint32_t untagged_count = 0;
154 uint32_t first_offset = kMaxInt;
155 for (size_t i = 0; i < InputCount(); ++i) {
157 if (!operand.IsRegister()) {
158 if (operand.GetType().IsTagged()) {
159 ++count;
160 // Caller frame slots have negative indices and start at -1. Flip it
161 // back to a positive offset (to be added to the frame's SP to find the
162 // slot).
163 int slot_offset = -operand.GetLocation() - 1;
164 DCHECK_GE(slot_offset, 0);
165 first_offset =
166 std::min(first_offset, static_cast<uint32_t>(slot_offset));
167 } else {
168 untagged_count += operand.GetSizeInPointers();
169 }
170 }
171 }
172 if (count == 0) {
173 // If we don't have any tagged parameter slots, still initialize the offset
174 // to point past the untagged parameter slots, so that
175 // offset + count == stack slot count.
176 first_offset = untagged_count;
177 }
178 DCHECK(first_offset != kMaxInt);
179 return (first_offset << 16) | (count & 0xFFFFu);
180}
181
183 if (ReturnCount() != callee->ReturnCount()) return false;
184 const int stack_returns_delta =
186 for (size_t i = 0; i < ReturnCount(); ++i) {
187 if (GetReturnLocation(i).IsCallerFrameSlot() &&
189 if (GetReturnLocation(i).AsCallerFrameSlot() + stack_returns_delta !=
191 return false;
192 }
194 callee->GetReturnLocation(i))) {
195 return false;
196 }
197 }
198 return true;
199}
200
201// TODO(jkummerow, sigurds): Arguably frame size calculation should be
202// keyed on code/frame type, not on CallDescriptor kind. Think about a
203// good way to organize this logic.
205 switch (kind_) {
206 case kCallJSFunction:
208 case kCallAddress:
209#if V8_ENABLE_WEBASSEMBLY
210 if (code_kind == CodeKind::C_WASM_ENTRY) {
211 return CWasmEntryFrameConstants::kFixedSlotCount;
212 }
213#endif // V8_ENABLE_WEBASSEMBLY
216 case kCallCodeObject:
219#if V8_ENABLE_WEBASSEMBLY
220 case kCallWasmFunction:
221 case kCallWasmFunctionIndirect:
222 case kCallWasmImportWrapper:
223 return WasmFrameConstants::kFixedSlotCount;
224 case kCallWasmCapiFunction:
225 return WasmExitFrameConstants::kFixedSlotCount;
226#endif // V8_ENABLE_WEBASSEMBLY
227 }
228 UNREACHABLE();
229}
230
232#if V8_ENABLE_WEBASSEMBLY
233 DCHECK_EQ(kind_, kCallWasmFunctionIndirect);
234#endif
235 return signature_hash_;
236}
237
239 int parameter_count = static_cast<int>(ParameterCount());
242
243 for (int i = 0; i < parameter_count; ++i) {
244 if (IsFloatingPoint(GetParameterType(i).representation())) {
245 sig.SetFloat(i);
246 }
247 }
248 if (ReturnCount() > 0) {
250 if (IsFloatingPoint(GetReturnType(0).representation())) {
251 if (GetReturnType(0).representation() ==
253 sig.SetReturnFloat64();
254 } else {
255 sig.SetReturnFloat32();
256 }
257 }
258 }
259 return sig;
260}
261
263 gp_param_count_ = 0;
264 fp_param_count_ = 0;
265 for (size_t i = 0; i < ParameterCount(); ++i) {
266 if (IsFloatingPoint(GetParameterType(i).representation())) {
267 ++fp_param_count_.value();
268 } else {
269 ++gp_param_count_.value();
270 }
271 }
272}
273
274#if V8_ENABLE_WEBASSEMBLY
275namespace {
276CallDescriptor* ReplaceTypeInCallDescriptorWith(
277 Zone* zone, const CallDescriptor* call_descriptor, size_t num_replacements,
278 MachineType from, MachineType to) {
279 // The last parameter may be the special callable parameter. In that case we
280 // have to preserve it as the last parameter, i.e. we allocate it in the new
281 // location signature again in the same register.
282 bool extra_callable_param =
283 (call_descriptor->GetInputLocation(call_descriptor->InputCount() - 1) ==
286
287 size_t return_count = call_descriptor->ReturnCount();
288 // To recover the function parameter count, disregard the instance parameter,
289 // and the extra callable parameter if present.
290 size_t parameter_count =
291 call_descriptor->ParameterCount() - (extra_callable_param ? 2 : 1);
292
293 // Precompute if the descriptor contains {from}.
294 bool needs_change = false;
295 for (size_t i = 0; !needs_change && i < return_count; i++) {
296 needs_change = call_descriptor->GetReturnType(i) == from;
297 }
298 for (size_t i = 1; !needs_change && i < parameter_count + 1; i++) {
299 needs_change = call_descriptor->GetParameterType(i) == from;
300 }
301 if (!needs_change) return const_cast<CallDescriptor*>(call_descriptor);
302
303 std::vector<MachineType> reps;
304
305 for (size_t i = 0, limit = return_count; i < limit; i++) {
306 MachineType initial_type = call_descriptor->GetReturnType(i);
307 if (initial_type == from) {
308 for (size_t j = 0; j < num_replacements; j++) reps.push_back(to);
309 return_count += num_replacements - 1;
310 } else {
311 reps.push_back(initial_type);
312 }
313 }
314
315 // Disregard the instance (first) parameter.
316 for (size_t i = 1, limit = parameter_count + 1; i < limit; i++) {
317 MachineType initial_type = call_descriptor->GetParameterType(i);
318 if (initial_type == from) {
319 for (size_t j = 0; j < num_replacements; j++) reps.push_back(to);
320 parameter_count += num_replacements - 1;
321 } else {
322 reps.push_back(initial_type);
323 }
324 }
325
326 MachineSignature sig(return_count, parameter_count, reps.data());
327
328 int parameter_slots;
329 int return_slots;
330 LocationSignature* location_sig = BuildLocations(
331 zone, &sig, extra_callable_param, &parameter_slots, &return_slots);
332
333 return zone->New<CallDescriptor>( // --
334 call_descriptor->kind(), // kind
335 call_descriptor->tag(), // tag
336 call_descriptor->GetInputType(0), // target MachineType
337 call_descriptor->GetInputLocation(0), // target location
338 location_sig, // location_sig
339 parameter_slots, // parameter slot count
340 call_descriptor->properties(), // properties
341 call_descriptor->CalleeSavedRegisters(), // callee-saved registers
342 call_descriptor->CalleeSavedFPRegisters(), // callee-saved fp regs
343 call_descriptor->flags(), // flags
344 call_descriptor->debug_name(), // debug name
345 call_descriptor->GetStackArgumentOrder(), // stack order
346 call_descriptor->AllocatableRegisters(), // allocatable registers
347 return_slots, // return slot count
348 call_descriptor->IsIndirectWasmFunctionCall()
349 ? call_descriptor->signature_hash()
350 : kInvalidWasmSignatureHash); // signature hash
351}
352} // namespace
353
354CallDescriptor* GetI32WasmCallDescriptor(
355 Zone* zone, const CallDescriptor* call_descriptor) {
356 return ReplaceTypeInCallDescriptorWith(
357 zone, call_descriptor, 2, MachineType::Int64(), MachineType::Int32());
358}
359#endif
360
363#if V8_ENABLE_WEBASSEMBLY
364 DCHECK(info->IsOptimizing() || info->IsWasm());
365#else
366 DCHECK(info->IsOptimizing());
367#endif // V8_ENABLE_WEBASSEMBLY
368 if (!info->closure().is_null()) {
369 // If we are compiling a JS function, use a JS call descriptor,
370 // plus the receiver.
371 DCHECK(info->has_bytecode_array());
372 DCHECK_EQ(info->closure()
373 ->shared()
374 ->internal_formal_parameter_count_with_receiver(),
375 info->bytecode_array()->parameter_count());
376 return GetJSCallDescriptor(zone, info->is_osr(),
377 info->bytecode_array()->parameter_count(),
379 }
380 return nullptr; // TODO(titzer): ?
381}
382
383
384// static
386 switch (function) {
387 // Most runtime functions need a FrameState. A few chosen ones that we know
388 // not to call into arbitrary JavaScript, not to throw, and not to lazily
389 // deoptimize are allowlisted here and can be called without a FrameState.
390 case Runtime::kAbort:
391 case Runtime::kAllocateInOldGeneration:
392 case Runtime::kCreateIterResultObject:
393 case Runtime::kGrowableSharedArrayBufferByteLength:
394 case Runtime::kIncBlockCounter:
395 case Runtime::kNewClosure:
396 case Runtime::kNewClosure_Tenured:
397 case Runtime::kNewFunctionContext:
398 case Runtime::kPushBlockContext:
399 case Runtime::kPushCatchContext:
400 case Runtime::kStringEqual:
401 case Runtime::kStringLessThan:
402 case Runtime::kStringLessThanOrEqual:
403 case Runtime::kStringGreaterThan:
404 case Runtime::kStringGreaterThanOrEqual:
405 case Runtime::kToFastProperties: // TODO(conradw): Is it safe?
406 case Runtime::kTraceEnter:
407 case Runtime::kTraceExit:
408 return false;
409
410 // Some inline intrinsics are also safe to call without a FrameState.
411 case Runtime::kInlineCreateIterResultObject:
412 case Runtime::kInlineIncBlockCounter:
413 case Runtime::kInlineGeneratorClose:
414 case Runtime::kInlineGeneratorGetResumeMode:
415 case Runtime::kInlineCreateJSGeneratorObject:
416 return false;
417
418 default:
419 break;
420 }
421
422 // For safety, default to needing a FrameState unless allowlisted.
423 return true;
424}
425
427 Zone* zone, Runtime::FunctionId function_id, int js_parameter_count,
429 LazyDeoptOnThrow lazy_deopt_on_throw) {
430 const Runtime::Function* function = Runtime::FunctionForId(function_id);
431 const int return_count = function->result_size;
432 const char* debug_name = function->name;
433
434 if (lazy_deopt_on_throw == LazyDeoptOnThrow::kNo &&
435 !Linkage::NeedsFrameStateInput(function_id)) {
436 flags = static_cast<CallDescriptor::Flags>(
437 flags & ~CallDescriptor::kNeedsFrameState);
438 }
439
440 DCHECK_IMPLIES(lazy_deopt_on_throw == LazyDeoptOnThrow::kYes,
442
443 return GetCEntryStubCallDescriptor(zone, return_count, js_parameter_count,
444 debug_name, properties, flags);
445}
446
448 Zone* zone, int return_count, int js_parameter_count,
449 const char* debug_name, Operator::Properties properties,
450 CallDescriptor::Flags flags, StackArgumentOrder stack_order) {
451 const size_t function_count = 1;
452 const size_t num_args_count = 1;
453 const size_t context_count = 1;
454 const size_t parameter_count = function_count +
455 static_cast<size_t>(js_parameter_count) +
456 num_args_count + context_count;
457
458 LocationSignature::Builder locations(zone, static_cast<size_t>(return_count),
459 static_cast<size_t>(parameter_count));
460
461 // Add returns.
462 if (locations.return_count_ > 0) {
463 locations.AddReturn(regloc(kReturnRegister0, MachineType::AnyTagged()));
464 }
465 if (locations.return_count_ > 1) {
466 locations.AddReturn(regloc(kReturnRegister1, MachineType::AnyTagged()));
467 }
468 if (locations.return_count_ > 2) {
469 locations.AddReturn(regloc(kReturnRegister2, MachineType::AnyTagged()));
470 }
471
472 // All parameters to the runtime call go on the stack.
473 for (int i = 0; i < js_parameter_count; i++) {
474 locations.AddParam(LinkageLocation::ForCallerFrameSlot(
475 i - js_parameter_count, MachineType::AnyTagged()));
476 }
477 // Add runtime function itself.
478 locations.AddParam(
480
481 // Add runtime call argument count.
482 locations.AddParam(
484
485 // Add context.
486 locations.AddParam(regloc(kContextRegister, MachineType::AnyTagged()));
487
488 // The target for runtime calls is a code object.
489 MachineType target_type = MachineType::AnyTagged();
490 LinkageLocation target_loc =
492 return zone->New<CallDescriptor>( // --
495 target_type, // target MachineType
496 target_loc, // target location
497 locations.Get(), // location_sig
498 js_parameter_count, // stack_parameter_count
499 properties, // properties
500 kNoCalleeSaved, // callee-saved
501 kNoCalleeSavedFp, // callee-saved fp
502 flags, // flags
503 debug_name, // debug name
504 stack_order); // stack order
505}
506
508 int js_parameter_count,
510 Operator::Properties properties) {
511 const size_t return_count = 1;
512 const size_t context_count = 1;
513 const size_t new_target_count = 1;
514 const size_t num_args_count = 1;
515 const size_t dispatch_handle_count =
517 const size_t parameter_count = js_parameter_count + new_target_count +
518 num_args_count + dispatch_handle_count +
519 context_count;
520
521 // The JSCallDescriptor must be compatible both with the interface descriptor
522 // of JS builtins and with the general JS calling convention (as defined by
523 // the JSTrampolineDescriptor). The JS builtin descriptors are already
524 // statically asserted to be compatible with the JS calling convention, so
525 // here we just ensure compatibility with the JS builtin descriptors.
527
528 LocationSignature::Builder locations(zone, return_count, parameter_count);
529
530 // All JS calls have exactly one return value.
532
533 // All parameters to JS calls go on the stack.
534 for (int i = 0; i < js_parameter_count; i++) {
535 int spill_slot_index = -i - 1;
537 spill_slot_index, MachineType::AnyTagged()));
538 }
539
540 // Add JavaScript call new target value.
541 locations.AddParam(
543
544 // Add JavaScript call argument count.
545 locations.AddParam(
547
548#ifdef V8_JS_LINKAGE_INCLUDES_DISPATCH_HANDLE
549 // Add dispatch handle.
550 locations.AddParam(
552#endif
553
554 // Add context.
556
557 // The target for JS function calls is the JSFunction object.
558 MachineType target_type = MachineType::AnyTagged();
559 // When entering into an OSR function from unoptimized code the JSFunction
560 // is not in a register, but it is on the stack in the marker spill slot.
561 // For kind == JSDescKind::kBuiltin, we should still use the regular
562 // kJSFunctionRegister, so that frame attribution for stack traces works.
563 LinkageLocation target_loc = is_osr
565 : regloc(kJSFunctionRegister, target_type);
567 return zone->New<CallDescriptor>( // --
568 descriptor_kind, // kind
569 kJSEntrypointTag, // tag
570 target_type, // target MachineType
571 target_loc, // target location
572 locations.Get(), // location_sig
573 js_parameter_count, // stack_parameter_count
574 properties, // properties
575 kNoCalleeSaved, // callee-saved
576 kNoCalleeSavedFp, // callee-saved fp
577 flags, // flags
578 "js-call"); // debug name
579}
580
581// TODO(turbofan): cache call descriptors for code stub calls.
582// TODO(jgruber): Clean up stack parameter count handling. The descriptor
583// already knows the formal stack parameter count and ideally only additional
584// stack parameters should be passed into this method. All call-sites should
585// be audited for correctness (e.g. many used to assume a stack parameter count
586// of 0).
588 Zone* zone, const CallInterfaceDescriptor& descriptor,
589 int stack_parameter_count, CallDescriptor::Flags flags,
590 Operator::Properties properties, StubCallMode stub_mode) {
591 const int register_parameter_count = descriptor.GetRegisterParameterCount();
592 const int js_parameter_count =
593 register_parameter_count + stack_parameter_count;
594 const int context_count = descriptor.HasContextParameter() ? 1 : 0;
595 const size_t parameter_count =
596 static_cast<size_t>(js_parameter_count + context_count);
597
598 DCHECK_GE(stack_parameter_count, descriptor.GetStackParameterCount());
599
600 int return_count = descriptor.GetReturnCount();
601 LocationSignature::Builder locations(zone, return_count, parameter_count);
602
603 // Add returns.
604 for (int i = 0; i < return_count; i++) {
605 MachineType type = descriptor.GetReturnType(static_cast<int>(i));
606 if (IsFloatingPoint(type.representation())) {
608 locations.AddReturn(regloc(reg, type));
609 } else {
610 Register reg = descriptor.GetRegisterReturn(i);
611 locations.AddReturn(regloc(reg, type));
612 }
613 }
614
615 // Add parameters in registers and on the stack.
616 for (int i = 0; i < js_parameter_count; i++) {
617 if (i < register_parameter_count) {
618 // The first parameters go in registers.
619 MachineType type = descriptor.GetParameterType(i);
620 if (IsFloatingPoint(type.representation())) {
622 locations.AddParam(regloc(reg, type));
623 } else {
624 Register reg = descriptor.GetRegisterParameter(i);
625 locations.AddParam(regloc(reg, type));
626 }
627 } else {
628 // The rest of the parameters go on the stack.
629 int stack_slot = i - register_parameter_count - stack_parameter_count;
631 stack_slot, i < descriptor.GetParameterCount()
632 ? descriptor.GetParameterType(i)
634 }
635 }
636
637 // Add context.
638 if (context_count) {
640 }
641
642 // The target for stub calls depends on the requested mode.
644 MachineType target_type;
645 switch (stub_mode) {
648 target_type = MachineType::AnyTagged();
649 break;
650#if V8_ENABLE_WEBASSEMBLY
651 case StubCallMode::kCallWasmRuntimeStub:
652 kind = CallDescriptor::kCallWasmFunction;
653 target_type = MachineType::Pointer();
654 break;
655#endif // V8_ENABLE_WEBASSEMBLY
658 target_type = MachineType::AnyTagged();
659 break;
660 }
661
662 RegList allocatable_registers = descriptor.allocatable_registers();
663 RegList callee_saved_registers = kNoCalleeSaved;
664 if (descriptor.CalleeSaveRegisters()) {
665 callee_saved_registers = allocatable_registers;
666 DCHECK(!callee_saved_registers.is_empty());
667 }
668 LinkageLocation target_loc = LinkageLocation::ForAnyRegister(target_type);
669 return zone->New<CallDescriptor>( // --
670 kind, // kind
671 descriptor.tag(), // tag
672 target_type, // target MachineType
673 target_loc, // target location
674 locations.Get(), // location_sig
675 stack_parameter_count, // stack_parameter_count
676 properties, // properties
677 callee_saved_registers, // callee-saved registers
678 kNoCalleeSavedFp, // callee-saved fp
679 CallDescriptor::kCanUseRoots | flags, // flags
680 descriptor.DebugName(), // debug name
681 descriptor.GetStackArgumentOrder(), // stack order
682 allocatable_registers);
683}
684
685// static
687 Zone* zone, const CallInterfaceDescriptor& descriptor,
688 int stack_parameter_count) {
689 const int register_parameter_count = descriptor.GetRegisterParameterCount();
690 const int parameter_count = register_parameter_count + stack_parameter_count;
691
692 DCHECK_EQ(descriptor.GetReturnCount(), 1);
694
695 locations.AddReturn(regloc(kReturnRegister0, descriptor.GetReturnType(0)));
696
697 // Add parameters in registers and on the stack.
698 for (int i = 0; i < parameter_count; i++) {
699 if (i < register_parameter_count) {
700 // The first parameters go in registers.
701 Register reg = descriptor.GetRegisterParameter(i);
702 MachineType type = descriptor.GetParameterType(i);
703 locations.AddParam(regloc(reg, type));
704 } else {
705 // The rest of the parameters go on the stack.
706 int stack_slot = i - register_parameter_count - stack_parameter_count;
708 stack_slot, MachineType::AnyTagged()));
709 }
710 }
711
712 // The target for interpreter dispatches is a code entry address.
713 MachineType target_type = MachineType::Pointer();
714 LinkageLocation target_loc = LinkageLocation::ForAnyRegister(target_type);
715 const CallDescriptor::Flags kFlags =
717 return zone->New<CallDescriptor>( // --
720 target_type, // target MachineType
721 target_loc, // target location
722 locations.Get(), // location_sig
723 stack_parameter_count, // stack_parameter_count
724 Operator::kNoProperties, // properties
725 kNoCalleeSaved, // callee-saved registers
726 kNoCalleeSavedFp, // callee-saved fp
727 kFlags, // flags
728 descriptor.DebugName());
729}
730
733 int parameter_count_with_receiver =
734 static_cast<int>(incoming_->JSParameterCount());
735 int first_stack_slot =
736 OsrHelper::FirstStackSlotIndex(parameter_count_with_receiver - 1);
737
738 if (index == kOsrContextSpillSlotIndex) {
739 int context_index =
740 Linkage::GetJSCallContextParamIndex(parameter_count_with_receiver);
741 return GetParameterLocation(context_index);
742 } else if (index >= first_stack_slot) {
743 // Local variable stored in this (callee) stack.
744 int spill_index =
745 index - first_stack_slot + StandardFrameConstants::kFixedSlotCount;
746 return LinkageLocation::ForCalleeFrameSlot(spill_index,
748 } else {
749 // Parameter. Use the assigned location from the incoming call descriptor.
750 return GetParameterLocation(index);
751 }
752}
753
754namespace {
755inline bool IsTaggedReg(const LinkageLocation& loc, Register reg) {
756 return loc.IsRegister() && loc.AsRegister() == reg.code() &&
757 loc.GetType().representation() ==
759}
760} // namespace
761
763 // TODO(titzer): this should be configurable, not call-type specific.
766 return IsTaggedReg(loc, kJSFunctionRegister) ||
767 IsTaggedReg(loc, kContextRegister);
768 }
769#if V8_ENABLE_WEBASSEMBLY
770 if (incoming_->IsAnyWasmFunctionCall()) {
772 return IsTaggedReg(loc, kWasmImplicitArgRegister);
773 }
774#endif // V8_ENABLE_WEBASSEMBLY
775 return false;
776}
777
779 // TODO(titzer): these constants are necessary due to offset/slot# mismatch
780 static const int kJSContextSlot = 2 + StandardFrameConstants::kCPSlotCount;
781 static const int kJSFunctionSlot = 3 + StandardFrameConstants::kCPSlotCount;
782
785
786 // TODO(titzer): this should be configurable, not call-type specific.
788 if (IsTaggedReg(loc, kJSFunctionRegister)) {
789 return LinkageLocation::ForCalleeFrameSlot(kJSFunctionSlot,
791 } else {
792 DCHECK(IsTaggedReg(loc, kContextRegister));
793 return LinkageLocation::ForCalleeFrameSlot(kJSContextSlot,
795 }
796 }
797#if V8_ENABLE_WEBASSEMBLY
798 static const int kWasmInstanceDataSlot =
800 if (incoming_->IsAnyWasmFunctionCall()) {
801 DCHECK(IsTaggedReg(loc, kWasmImplicitArgRegister));
802 return LinkageLocation::ForCalleeFrameSlot(kWasmInstanceDataSlot,
804 }
805#endif // V8_ENABLE_WEBASSEMBLY
806 UNREACHABLE();
807}
808
809
810} // namespace compiler
811} // namespace internal
812} // namespace v8
friend Zone
Definition asm-types.cc:195
int16_t parameter_count
Definition builtins.cc:67
Builtins::Kind kind
Definition builtins.cc:40
DoubleRegister GetDoubleRegisterParameter(int index) const
MachineType GetReturnType(int index) const
DoubleRegister GetDoubleRegisterReturn(int index) const
StackArgumentOrder GetStackArgumentOrder() const
MachineType GetParameterType(int index) const
static constexpr int kFixedSlotCountAboveFp
static LinkageLocation ForRegister(int32_t reg, MachineType type=MachineType::None())
static LinkageLocation ForCallerFrameSlot(int32_t slot, MachineType type)
static LinkageLocation ForAnyRegister(MachineType type=MachineType::None())
static LinkageLocation ForCalleeFrameSlot(int32_t slot, MachineType type)
static bool IsSameLocation(const LinkageLocation &a, const LinkageLocation &b)
static LinkageLocation ForSavedCallerFunction()
NO_INLINE_FOR_ARM64_MSVC bool IsRegister() const
constexpr bool IsTagged() const
static constexpr MachineType Pointer()
constexpr MachineRepresentation representation() const
static constexpr MachineType Int32()
static constexpr MachineType AnyTagged()
static constexpr MachineType Int64()
static constexpr MachineType TaggedPointer()
constexpr bool is_empty() const
static V8_EXPORT_PRIVATE const Function * FunctionForId(FunctionId id)
Definition runtime.cc:350
T * AllocateArray(size_t length)
Definition zone.h:127
T * New(Args &&... args)
Definition zone.h:114
MachineSignature * GetMachineSignature(Zone *zone) const
Definition linkage.cc:81
int CalculateFixedFrameSize(CodeKind code_kind) const
Definition linkage.cc:204
CodeEntrypointTag tag() const
Definition linkage.h:146
std::optional< size_t > gp_param_count_
Definition linkage.h:363
MachineType GetInputType(size_t index) const
Definition linkage.h:285
DoubleRegList CalleeSavedFPRegisters() const
Definition linkage.h:303
std::optional< size_t > fp_param_count_
Definition linkage.h:364
MachineType GetParameterType(size_t index) const
Definition linkage.h:290
int GetStackParameterDelta(const CallDescriptor *tail_caller) const
Definition linkage.cc:96
StackArgumentOrder GetStackArgumentOrder() const
Definition linkage.h:294
MachineType GetReturnType(size_t index) const
Definition linkage.h:281
LinkageLocation GetReturnLocation(size_t index) const
Definition linkage.h:270
Operator::Properties properties() const
Definition linkage.h:297
bool CanTailCall(const CallDescriptor *callee) const
Definition linkage.cc:182
EncodedCSignature ToEncodedCSignature() const
Definition linkage.cc:238
LinkageLocation GetInputLocation(size_t index) const
Definition linkage.h:274
const char * debug_name() const
Definition linkage.h:307
static bool NeedsFrameStateInput(Runtime::FunctionId function)
Definition linkage.cc:385
CallDescriptor *const incoming_
Definition linkage.h:514
static constexpr int GetJSCallContextParamIndex(int parameter_count)
Definition linkage.h:495
bool ParameterHasSecondaryLocation(int index) const
Definition linkage.cc:762
static CallDescriptor * GetStubCallDescriptor(Zone *zone, const CallInterfaceDescriptor &descriptor, int stack_parameter_count, CallDescriptor::Flags flags, Operator::Properties properties=Operator::kNoProperties, StubCallMode stub_mode=StubCallMode::kCallCodeObject)
Definition linkage.cc:587
LinkageLocation GetParameterSecondaryLocation(int index) const
Definition linkage.cc:778
static CallDescriptor * GetRuntimeCallDescriptor(Zone *zone, Runtime::FunctionId function, int js_parameter_count, Operator::Properties properties, CallDescriptor::Flags flags, LazyDeoptOnThrow lazy_deopt_on_throw=LazyDeoptOnThrow::kNo)
Definition linkage.cc:426
static CallDescriptor * GetJSCallDescriptor(Zone *zone, bool is_osr, int parameter_count, CallDescriptor::Flags flags, Operator::Properties properties=Operator::kNoProperties)
Definition linkage.cc:507
static CallDescriptor * GetBytecodeDispatchCallDescriptor(Zone *zone, const CallInterfaceDescriptor &descriptor, int stack_parameter_count)
Definition linkage.cc:686
static const int kOsrContextSpillSlotIndex
Definition linkage.h:508
LinkageLocation GetParameterLocation(int index) const
Definition linkage.h:444
static CallDescriptor * GetCEntryStubCallDescriptor(Zone *zone, int return_count, int js_parameter_count, const char *debug_name, Operator::Properties properties, CallDescriptor::Flags flags, StackArgumentOrder stack_order=StackArgumentOrder::kDefault)
Definition linkage.cc:447
LinkageLocation GetOsrValueLocation(int index) const
Definition linkage.cc:731
static CallDescriptor * ComputeIncoming(Zone *zone, OptimizedCompilationInfo *info)
Definition linkage.cc:361
static int FirstStackSlotIndex(int parameter_count)
Definition osr.h:34
#define V8_JS_LINKAGE_INCLUDES_DISPATCH_HANDLE_BOOL
Definition globals.h:161
uint32_t count
int32_t offset
LiftoffRegister reg
Point from
LocationSignature * BuildLocations(Zone *zone, const Signature< T > *sig, bool extra_callable_param, int *parameter_slots, int *return_slots)
constexpr RegList kNoCalleeSaved
Definition linkage.h:36
std::ostream & operator<<(std::ostream &os, AccessMode access_mode)
constexpr DoubleRegList kNoCalleeSavedFp
Definition linkage.h:37
constexpr bool ShouldPadArguments(int argument_count)
Definition register.h:18
constexpr Register kRuntimeCallFunctionRegister
DwVfpRegister DoubleRegister
Signature< LinkageLocation > LocationSignature
constexpr int AddArgumentPaddingSlots(int argument_count)
Definition register.h:14
constexpr Register kJavaScriptCallArgCountRegister
kWasmInternalFunctionIndirectPointerTag kProtectedInstanceDataOffset sig
Signature< MachineType > MachineSignature
Definition signature.h:151
constexpr Register kReturnRegister1
constexpr bool IsFloatingPoint(MachineRepresentation rep)
constexpr Register kReturnRegister0
constexpr Register kWasmImplicitArgRegister
constexpr Register kContextRegister
constexpr Register kRuntimeCallArgCountRegister
constexpr Register kReturnRegister2
constexpr size_t kJSBuiltinBaseParameterCount
constexpr int kMaxInt
Definition globals.h:374
constexpr Register kJavaScriptCallDispatchHandleRegister
constexpr uint64_t kInvalidWasmSignatureHash
Definition globals.h:2896
constexpr Register kJavaScriptCallNewTargetRegister
constexpr Register kJSFunctionRegister
#define CHECK(condition)
Definition logging.h:124
#define CHECK_LT(lhs, rhs)
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485