Line data Source code
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/code-stubs.h"
9 : #include "src/compilation-info.h"
10 : #include "src/compiler/common-operator.h"
11 : #include "src/compiler/frame.h"
12 : #include "src/compiler/node.h"
13 : #include "src/compiler/osr.h"
14 : #include "src/compiler/pipeline.h"
15 :
16 : namespace v8 {
17 : namespace internal {
18 : namespace compiler {
19 :
20 : namespace {
21 :
22 : LinkageLocation regloc(Register reg, MachineType type) {
23 : return LinkageLocation::ForRegister(reg.code(), type);
24 : }
25 :
26 : } // namespace
27 :
28 :
29 0 : std::ostream& operator<<(std::ostream& os, const CallDescriptor::Kind& k) {
30 0 : switch (k) {
31 : case CallDescriptor::kCallCodeObject:
32 0 : os << "Code";
33 0 : break;
34 : case CallDescriptor::kCallJSFunction:
35 0 : os << "JS";
36 0 : break;
37 : case CallDescriptor::kCallAddress:
38 0 : os << "Addr";
39 0 : break;
40 : }
41 0 : return os;
42 : }
43 :
44 :
45 0 : std::ostream& operator<<(std::ostream& os, const CallDescriptor& d) {
46 : // TODO(svenpanne) Output properties etc. and be less cryptic.
47 0 : return os << d.kind() << ":" << d.debug_name() << ":r" << d.ReturnCount()
48 0 : << "s" << d.StackParameterCount() << "i" << d.InputCount() << "f"
49 0 : << d.FrameStateCount() << "t" << d.SupportsTailCalls();
50 : }
51 :
52 57792 : MachineSignature* CallDescriptor::GetMachineSignature(Zone* zone) const {
53 : size_t param_count = ParameterCount();
54 : size_t return_count = ReturnCount();
55 14448 : MachineType* types = zone->NewArray<MachineType>(param_count + return_count);
56 : int current = 0;
57 28896 : for (size_t i = 0; i < return_count; ++i) {
58 28896 : types[current++] = GetReturnType(i);
59 : }
60 28896 : for (size_t i = 0; i < param_count; ++i) {
61 57792 : types[current++] = GetParameterType(i);
62 : }
63 14448 : return new (zone) MachineSignature(return_count, param_count, types);
64 : }
65 :
66 13 : bool CallDescriptor::HasSameReturnLocationsAs(
67 26 : const CallDescriptor* other) const {
68 13 : if (ReturnCount() != other->ReturnCount()) return false;
69 11 : for (size_t i = 0; i < ReturnCount(); ++i) {
70 12 : if (GetReturnLocation(i) != other->GetReturnLocation(i)) return false;
71 : }
72 : return true;
73 : }
74 :
75 186565 : int CallDescriptor::GetStackParameterDelta(
76 2017658 : CallDescriptor const* tail_caller) const {
77 : int callee_slots_above_sp = 0;
78 2006846 : for (size_t i = 0; i < InputCount(); ++i) {
79 816858 : LinkageLocation operand = GetInputLocation(i);
80 816858 : if (!operand.IsRegister()) {
81 : int new_candidate =
82 52695 : -operand.GetLocation() + operand.GetSizeInPointers() - 1;
83 52695 : if (new_candidate > callee_slots_above_sp) {
84 : callee_slots_above_sp = new_candidate;
85 : }
86 : }
87 : }
88 : int tail_caller_slots_above_sp = 0;
89 186565 : if (tail_caller != nullptr) {
90 1841905 : for (size_t i = 0; i < tail_caller->InputCount(); ++i) {
91 827670 : LinkageLocation operand = tail_caller->GetInputLocation(i);
92 827670 : if (!operand.IsRegister()) {
93 : int new_candidate =
94 2973 : -operand.GetLocation() + operand.GetSizeInPointers() - 1;
95 2973 : if (new_candidate > tail_caller_slots_above_sp) {
96 : tail_caller_slots_above_sp = new_candidate;
97 : }
98 : }
99 : }
100 : }
101 186565 : return callee_slots_above_sp - tail_caller_slots_above_sp;
102 : }
103 :
104 13 : bool CallDescriptor::CanTailCall(const Node* node) const {
105 13 : return HasSameReturnLocationsAs(CallDescriptorOf(node->op()));
106 : }
107 :
108 2376247 : int CallDescriptor::CalculateFixedFrameSize() const {
109 2376247 : switch (kind_) {
110 : case kCallJSFunction:
111 : return PushArgumentCount()
112 : ? OptimizedBuiltinFrameConstants::kFixedSlotCount
113 1239451 : : StandardFrameConstants::kFixedSlotCount;
114 : break;
115 : case kCallAddress:
116 : return CommonFrameConstants::kFixedSlotCountAboveFp +
117 : CommonFrameConstants::kCPSlotCount;
118 : break;
119 : case kCallCodeObject:
120 678994 : return TypedFrameConstants::kFixedSlotCount;
121 : }
122 0 : UNREACHABLE();
123 : }
124 :
125 443411 : CallDescriptor* Linkage::ComputeIncoming(Zone* zone, CompilationInfo* info) {
126 : DCHECK(!info->IsStub());
127 443411 : if (!info->closure().is_null()) {
128 : // If we are compiling a JS function, use a JS call descriptor,
129 : // plus the receiver.
130 : SharedFunctionInfo* shared = info->closure()->shared();
131 : return GetJSCallDescriptor(zone, info->is_osr(),
132 : 1 + shared->internal_formal_parameter_count(),
133 886822 : CallDescriptor::kNoFlags);
134 : }
135 : return nullptr; // TODO(titzer): ?
136 : }
137 :
138 :
139 : // static
140 9158456 : bool Linkage::NeedsFrameStateInput(Runtime::FunctionId function) {
141 9158456 : switch (function) {
142 : // Most runtime functions need a FrameState. A few chosen ones that we know
143 : // not to call into arbitrary JavaScript, not to throw, and not to lazily
144 : // deoptimize are whitelisted here and can be called without a FrameState.
145 : case Runtime::kAbort:
146 : case Runtime::kAllocateInTargetSpace:
147 : case Runtime::kConvertReceiver:
148 : case Runtime::kCreateIterResultObject:
149 : case Runtime::kGeneratorGetContinuation:
150 : case Runtime::kIncBlockCounter:
151 : case Runtime::kIsFunction:
152 : case Runtime::kNewClosure:
153 : case Runtime::kNewClosure_Tenured:
154 : case Runtime::kNewFunctionContext:
155 : case Runtime::kPushBlockContext:
156 : case Runtime::kPushCatchContext:
157 : case Runtime::kReThrow:
158 : case Runtime::kStringCompare:
159 : case Runtime::kStringEqual:
160 : case Runtime::kStringNotEqual:
161 : case Runtime::kStringLessThan:
162 : case Runtime::kStringLessThanOrEqual:
163 : case Runtime::kStringGreaterThan:
164 : case Runtime::kStringGreaterThanOrEqual:
165 : case Runtime::kToFastProperties: // TODO(conradw): Is it safe?
166 : case Runtime::kTraceEnter:
167 : case Runtime::kTraceExit:
168 : return false;
169 :
170 : // Some inline intrinsics are also safe to call without a FrameState.
171 : case Runtime::kInlineClassOf:
172 : case Runtime::kInlineCreateIterResultObject:
173 : case Runtime::kInlineGeneratorClose:
174 : case Runtime::kInlineGeneratorGetContext:
175 : case Runtime::kInlineGeneratorGetInputOrDebugPos:
176 : case Runtime::kInlineGeneratorGetResumeMode:
177 : case Runtime::kInlineCreateJSGeneratorObject:
178 : case Runtime::kInlineIsArray:
179 : case Runtime::kInlineIsJSMap:
180 : case Runtime::kInlineIsJSSet:
181 : case Runtime::kInlineIsJSWeakMap:
182 : case Runtime::kInlineIsJSWeakSet:
183 : case Runtime::kInlineIsJSReceiver:
184 : case Runtime::kInlineIsRegExp:
185 : case Runtime::kInlineIsSmi:
186 : case Runtime::kInlineIsTypedArray:
187 : return false;
188 :
189 : default:
190 : break;
191 : }
192 :
193 : // For safety, default to needing a FrameState unless whitelisted.
194 8143841 : return true;
195 : }
196 :
197 :
198 0 : bool CallDescriptor::UsesOnlyRegisters() const {
199 0 : for (size_t i = 0; i < InputCount(); ++i) {
200 0 : if (!GetInputLocation(i).IsRegister()) return false;
201 : }
202 0 : for (size_t i = 0; i < ReturnCount(); ++i) {
203 0 : if (!GetReturnLocation(i).IsRegister()) return false;
204 : }
205 : return true;
206 : }
207 :
208 :
209 1085295 : CallDescriptor* Linkage::GetRuntimeCallDescriptor(
210 : Zone* zone, Runtime::FunctionId function_id, int js_parameter_count,
211 : Operator::Properties properties, CallDescriptor::Flags flags) {
212 1085295 : const Runtime::Function* function = Runtime::FunctionForId(function_id);
213 1085298 : const int return_count = function->result_size;
214 1085298 : const char* debug_name = function->name;
215 :
216 1085298 : if (!Linkage::NeedsFrameStateInput(function_id)) {
217 : flags = static_cast<CallDescriptor::Flags>(
218 : flags & ~CallDescriptor::kNeedsFrameState);
219 : }
220 :
221 : return GetCEntryStubCallDescriptor(zone, return_count, js_parameter_count,
222 1085298 : debug_name, properties, flags);
223 : }
224 :
225 1093214 : CallDescriptor* Linkage::GetCEntryStubCallDescriptor(
226 : Zone* zone, int return_count, int js_parameter_count,
227 : const char* debug_name, Operator::Properties properties,
228 : CallDescriptor::Flags flags) {
229 : const size_t function_count = 1;
230 : const size_t num_args_count = 1;
231 : const size_t context_count = 1;
232 : const size_t parameter_count = function_count +
233 : static_cast<size_t>(js_parameter_count) +
234 1093214 : num_args_count + context_count;
235 :
236 : LocationSignature::Builder locations(zone, static_cast<size_t>(return_count),
237 1093214 : static_cast<size_t>(parameter_count));
238 :
239 : // Add returns.
240 1093216 : if (locations.return_count_ > 0) {
241 : locations.AddReturn(regloc(kReturnRegister0, MachineType::AnyTagged()));
242 : }
243 1093216 : if (locations.return_count_ > 1) {
244 392 : locations.AddReturn(regloc(kReturnRegister1, MachineType::AnyTagged()));
245 : }
246 1093216 : if (locations.return_count_ > 2) {
247 0 : locations.AddReturn(regloc(kReturnRegister2, MachineType::AnyTagged()));
248 : }
249 :
250 : // All parameters to the runtime call go on the stack.
251 1470438 : for (int i = 0; i < js_parameter_count; i++) {
252 : locations.AddParam(LinkageLocation::ForCallerFrameSlot(
253 1470438 : i - js_parameter_count, MachineType::AnyTagged()));
254 : }
255 : // Add runtime function itself.
256 : locations.AddParam(
257 : regloc(kRuntimeCallFunctionRegister, MachineType::Pointer()));
258 :
259 : // Add runtime call argument count.
260 : locations.AddParam(
261 : regloc(kRuntimeCallArgCountRegister, MachineType::Int32()));
262 :
263 : // Add context.
264 : locations.AddParam(regloc(kContextRegister, MachineType::AnyTagged()));
265 :
266 : // The target for runtime calls is a code object.
267 : MachineType target_type = MachineType::AnyTagged();
268 : LinkageLocation target_loc =
269 : LinkageLocation::ForAnyRegister(MachineType::AnyTagged());
270 : return new (zone) CallDescriptor( // --
271 : CallDescriptor::kCallCodeObject, // kind
272 : target_type, // target MachineType
273 : target_loc, // target location
274 : locations.Build(), // location_sig
275 : js_parameter_count, // stack_parameter_count
276 : properties, // properties
277 : kNoCalleeSaved, // callee-saved
278 : kNoCalleeSaved, // callee-saved fp
279 : flags, // flags
280 2186436 : debug_name); // debug name
281 : }
282 :
283 761418 : CallDescriptor* Linkage::GetJSCallDescriptor(Zone* zone, bool is_osr,
284 : int js_parameter_count,
285 : CallDescriptor::Flags flags) {
286 : const size_t return_count = 1;
287 : const size_t context_count = 1;
288 : const size_t new_target_count = 1;
289 : const size_t num_args_count = 1;
290 : const size_t parameter_count =
291 761418 : js_parameter_count + new_target_count + num_args_count + context_count;
292 :
293 : LocationSignature::Builder locations(zone, return_count, parameter_count);
294 :
295 : // All JS calls have exactly one return value.
296 : locations.AddReturn(regloc(kReturnRegister0, MachineType::AnyTagged()));
297 :
298 : // All parameters to JS calls go on the stack.
299 3004407 : for (int i = 0; i < js_parameter_count; i++) {
300 2242989 : int spill_slot_index = i - js_parameter_count;
301 : locations.AddParam(LinkageLocation::ForCallerFrameSlot(
302 : spill_slot_index, MachineType::AnyTagged()));
303 : }
304 :
305 : // Add JavaScript call new target value.
306 : locations.AddParam(
307 : regloc(kJavaScriptCallNewTargetRegister, MachineType::AnyTagged()));
308 :
309 : // Add JavaScript call argument count.
310 : locations.AddParam(
311 : regloc(kJavaScriptCallArgCountRegister, MachineType::Int32()));
312 :
313 : // Add context.
314 : locations.AddParam(regloc(kContextRegister, MachineType::AnyTagged()));
315 :
316 : // The target for JS function calls is the JSFunction object.
317 : MachineType target_type = MachineType::AnyTagged();
318 : // When entering into an OSR function from unoptimized code the JSFunction
319 : // is not in a register, but it is on the stack in the marker spill slot.
320 : LinkageLocation target_loc =
321 : is_osr ? LinkageLocation::ForSavedCallerFunction()
322 761418 : : regloc(kJSFunctionRegister, MachineType::AnyTagged());
323 : return new (zone) CallDescriptor( // --
324 : CallDescriptor::kCallJSFunction, // kind
325 : target_type, // target MachineType
326 : target_loc, // target location
327 : locations.Build(), // location_sig
328 : js_parameter_count, // stack_parameter_count
329 : Operator::kNoProperties, // properties
330 : kNoCalleeSaved, // callee-saved
331 : kNoCalleeSaved, // callee-saved fp
332 : CallDescriptor::kCanUseRoots | // flags
333 : flags, // flags
334 1522838 : "js-call");
335 : }
336 :
337 : // TODO(all): Add support for return representations/locations to
338 : // CallInterfaceDescriptor.
339 : // TODO(turbofan): cache call descriptors for code stub calls.
340 2715719 : CallDescriptor* Linkage::GetStubCallDescriptor(
341 : Isolate* isolate, Zone* zone, const CallInterfaceDescriptor& descriptor,
342 : int stack_parameter_count, CallDescriptor::Flags flags,
343 : Operator::Properties properties, MachineType return_type,
344 : size_t return_count, Linkage::ContextSpecification context_spec) {
345 : const int register_parameter_count = descriptor.GetRegisterParameterCount();
346 : const int js_parameter_count =
347 2715719 : register_parameter_count + stack_parameter_count;
348 2715719 : const int context_count = context_spec == kPassContext ? 1 : 0;
349 : const size_t parameter_count =
350 2715719 : static_cast<size_t>(js_parameter_count + context_count);
351 :
352 : LocationSignature::Builder locations(zone, return_count, parameter_count);
353 :
354 : // Add returns.
355 2715736 : if (locations.return_count_ > 0) {
356 : locations.AddReturn(regloc(kReturnRegister0, return_type));
357 : }
358 2715736 : if (locations.return_count_ > 1) {
359 96 : locations.AddReturn(regloc(kReturnRegister1, return_type));
360 : }
361 2715736 : if (locations.return_count_ > 2) {
362 0 : locations.AddReturn(regloc(kReturnRegister2, return_type));
363 : }
364 :
365 : // Add parameters in registers and on the stack.
366 8661786 : for (int i = 0; i < js_parameter_count; i++) {
367 8661786 : if (i < register_parameter_count) {
368 : // The first parameters go in registers.
369 : Register reg = descriptor.GetRegisterParameter(i);
370 : MachineType type = descriptor.GetParameterType(i);
371 : locations.AddParam(regloc(reg, type));
372 : } else {
373 : // The rest of the parameters go on the stack.
374 1360218 : int stack_slot = i - register_parameter_count - stack_parameter_count;
375 : locations.AddParam(LinkageLocation::ForCallerFrameSlot(
376 : stack_slot, MachineType::AnyTagged()));
377 : }
378 : }
379 : // Add context.
380 2715736 : if (context_count) {
381 : locations.AddParam(regloc(kContextRegister, MachineType::AnyTagged()));
382 : }
383 :
384 : // The target for stub calls is a code object.
385 : MachineType target_type = MachineType::AnyTagged();
386 : LinkageLocation target_loc =
387 : LinkageLocation::ForAnyRegister(MachineType::AnyTagged());
388 : return new (zone) CallDescriptor( // --
389 : CallDescriptor::kCallCodeObject, // kind
390 : target_type, // target MachineType
391 : target_loc, // target location
392 : locations.Build(), // location_sig
393 : stack_parameter_count, // stack_parameter_count
394 : properties, // properties
395 : kNoCalleeSaved, // callee-saved registers
396 : kNoCalleeSaved, // callee-saved fp
397 : CallDescriptor::kCanUseRoots | // flags
398 : flags, // flags
399 10862950 : descriptor.DebugName(isolate), descriptor.allocatable_registers());
400 : }
401 :
402 : // static
403 73123 : CallDescriptor* Linkage::GetAllocateCallDescriptor(Zone* zone) {
404 : LocationSignature::Builder locations(zone, 1, 1);
405 :
406 : locations.AddParam(regloc(kAllocateSizeRegister, MachineType::Int32()));
407 :
408 73123 : locations.AddReturn(regloc(kReturnRegister0, MachineType::AnyTagged()));
409 :
410 : // The target for allocate calls is a code object.
411 : MachineType target_type = MachineType::AnyTagged();
412 : LinkageLocation target_loc =
413 : LinkageLocation::ForAnyRegister(MachineType::AnyTagged());
414 : return new (zone) CallDescriptor( // --
415 : CallDescriptor::kCallCodeObject, // kind
416 : target_type, // target MachineType
417 : target_loc, // target location
418 : locations.Build(), // location_sig
419 : 0, // stack_parameter_count
420 : Operator::kNoThrow, // properties
421 : kNoCalleeSaved, // callee-saved registers
422 : kNoCalleeSaved, // callee-saved fp
423 : CallDescriptor::kCanUseRoots, // flags
424 146246 : "Allocate");
425 : }
426 :
427 : // static
428 16616 : CallDescriptor* Linkage::GetBytecodeDispatchCallDescriptor(
429 : Isolate* isolate, Zone* zone, const CallInterfaceDescriptor& descriptor,
430 : int stack_parameter_count) {
431 : const int register_parameter_count = descriptor.GetRegisterParameterCount();
432 16616 : const int parameter_count = register_parameter_count + stack_parameter_count;
433 :
434 16616 : LocationSignature::Builder locations(zone, 0, parameter_count);
435 :
436 : // Add parameters in registers and on the stack.
437 83080 : for (int i = 0; i < parameter_count; i++) {
438 66464 : if (i < register_parameter_count) {
439 : // The first parameters go in registers.
440 : Register reg = descriptor.GetRegisterParameter(i);
441 : MachineType type = descriptor.GetParameterType(i);
442 : locations.AddParam(regloc(reg, type));
443 : } else {
444 : // The rest of the parameters go on the stack.
445 0 : int stack_slot = i - register_parameter_count - stack_parameter_count;
446 : locations.AddParam(LinkageLocation::ForCallerFrameSlot(
447 : stack_slot, MachineType::AnyTagged()));
448 : }
449 : }
450 :
451 : // The target for interpreter dispatches is a code entry address.
452 : MachineType target_type = MachineType::Pointer();
453 : LinkageLocation target_loc = LinkageLocation::ForAnyRegister(target_type);
454 : return new (zone) CallDescriptor( // --
455 : CallDescriptor::kCallAddress, // kind
456 : target_type, // target MachineType
457 : target_loc, // target location
458 : locations.Build(), // location_sig
459 : stack_parameter_count, // stack_parameter_count
460 : Operator::kNoProperties, // properties
461 : kNoCalleeSaved, // callee-saved registers
462 : kNoCalleeSaved, // callee-saved fp
463 : CallDescriptor::kCanUseRoots | // flags
464 : CallDescriptor::kSupportsTailCalls, // flags
465 49848 : descriptor.DebugName(isolate));
466 : }
467 :
468 24445 : LinkageLocation Linkage::GetOsrValueLocation(int index) const {
469 24445 : CHECK(incoming_->IsJSFunctionCall());
470 24445 : int parameter_count = static_cast<int>(incoming_->JSParameterCount() - 1);
471 : int first_stack_slot = OsrHelper::FirstStackSlotIndex(parameter_count);
472 :
473 24445 : if (index == kOsrContextSpillSlotIndex) {
474 : // Context. Use the parameter location of the context spill slot.
475 : // Parameter (arity + 2) is special for the context of the function frame.
476 : // >> context_index = target + receiver + params + new_target + #args
477 5809 : int context_index = 1 + 1 + parameter_count + 1 + 1;
478 5809 : return incoming_->GetInputLocation(context_index);
479 18636 : } else if (index >= first_stack_slot) {
480 : // Local variable stored in this (callee) stack.
481 : int spill_index =
482 9849 : index - first_stack_slot + StandardFrameConstants::kFixedSlotCount;
483 : return LinkageLocation::ForCalleeFrameSlot(spill_index,
484 : MachineType::AnyTagged());
485 : } else {
486 : // Parameter. Use the assigned location from the incoming call descriptor.
487 8787 : int parameter_index = 1 + index; // skip index 0, which is the target.
488 8787 : return incoming_->GetInputLocation(parameter_index);
489 : }
490 : }
491 :
492 :
493 2453496 : bool Linkage::ParameterHasSecondaryLocation(int index) const {
494 2453496 : if (!incoming_->IsJSFunctionCall()) return false;
495 : LinkageLocation loc = GetParameterLocation(index);
496 1520671 : return (loc == regloc(kJSFunctionRegister, MachineType::AnyTagged()) ||
497 1520671 : loc == regloc(kContextRegister, MachineType::AnyTagged()));
498 : }
499 :
500 493943 : LinkageLocation Linkage::GetParameterSecondaryLocation(int index) const {
501 : DCHECK(ParameterHasSecondaryLocation(index));
502 : LinkageLocation loc = GetParameterLocation(index);
503 :
504 493943 : if (loc == regloc(kJSFunctionRegister, MachineType::AnyTagged())) {
505 : return LinkageLocation::ForCalleeFrameSlot(Frame::kJSFunctionSlot,
506 : MachineType::AnyTagged());
507 : } else {
508 : DCHECK(loc == regloc(kContextRegister, MachineType::AnyTagged()));
509 : return LinkageLocation::ForCalleeFrameSlot(Frame::kContextSlot,
510 : MachineType::AnyTagged());
511 : }
512 : }
513 :
514 :
515 : } // namespace compiler
516 : } // namespace internal
517 : } // namespace v8
|