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