blob: d4a366563a1180a137bf688f7ad823a0d1cb660c [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005#include "src/ast/scopes.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006#include "src/code-stubs.h"
7#include "src/compiler.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008#include "src/compiler/common-operator.h"
9#include "src/compiler/frame.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010#include "src/compiler/linkage.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011#include "src/compiler/node.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012#include "src/compiler/osr.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013#include "src/compiler/pipeline.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014
15namespace v8 {
16namespace internal {
17namespace compiler {
18
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019namespace {
20LinkageLocation regloc(Register reg) {
21 return LinkageLocation::ForRegister(reg.code());
22}
23
24
25MachineType reptyp(Representation representation) {
26 switch (representation.kind()) {
27 case Representation::kInteger8:
28 return MachineType::Int8();
29 case Representation::kUInteger8:
30 return MachineType::Uint8();
31 case Representation::kInteger16:
32 return MachineType::Int16();
33 case Representation::kUInteger16:
34 return MachineType::Uint16();
35 case Representation::kInteger32:
36 return MachineType::Int32();
37 case Representation::kSmi:
38 case Representation::kTagged:
39 case Representation::kHeapObject:
40 return MachineType::AnyTagged();
41 case Representation::kDouble:
42 return MachineType::Float64();
43 case Representation::kExternal:
44 return MachineType::Pointer();
45 case Representation::kNone:
46 case Representation::kNumRepresentations:
47 break;
48 }
49 UNREACHABLE();
50 return MachineType::None();
51}
52} // namespace
53
Ben Murdochb8a8cc12014-11-26 15:28:44 +000054
Emily Bernierd0a1eb72015-03-24 16:35:39 -040055std::ostream& operator<<(std::ostream& os, const CallDescriptor::Kind& k) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000056 switch (k) {
57 case CallDescriptor::kCallCodeObject:
58 os << "Code";
59 break;
60 case CallDescriptor::kCallJSFunction:
61 os << "JS";
62 break;
63 case CallDescriptor::kCallAddress:
64 os << "Addr";
65 break;
66 }
67 return os;
68}
69
70
Emily Bernierd0a1eb72015-03-24 16:35:39 -040071std::ostream& operator<<(std::ostream& os, const CallDescriptor& d) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000072 // TODO(svenpanne) Output properties etc. and be less cryptic.
73 return os << d.kind() << ":" << d.debug_name() << ":r" << d.ReturnCount()
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000074 << "s" << d.StackParameterCount() << "i" << d.InputCount() << "f"
75 << d.FrameStateCount() << "t" << d.SupportsTailCalls();
76}
77
78
79bool CallDescriptor::HasSameReturnLocationsAs(
80 const CallDescriptor* other) const {
81 if (ReturnCount() != other->ReturnCount()) return false;
82 for (size_t i = 0; i < ReturnCount(); ++i) {
83 if (GetReturnLocation(i) != other->GetReturnLocation(i)) return false;
84 }
85 return true;
86}
87
88
89bool CallDescriptor::CanTailCall(const Node* node,
90 int* stack_param_delta) const {
91 CallDescriptor const* other = OpParameter<CallDescriptor const*>(node);
92 size_t current_input = 0;
93 size_t other_input = 0;
94 *stack_param_delta = 0;
95 bool more_other = true;
96 bool more_this = true;
97 while (more_other || more_this) {
98 if (other_input < other->InputCount()) {
99 if (!other->GetInputLocation(other_input).IsRegister()) {
100 (*stack_param_delta)--;
101 }
102 } else {
103 more_other = false;
104 }
105 if (current_input < InputCount()) {
106 if (!GetInputLocation(current_input).IsRegister()) {
107 (*stack_param_delta)++;
108 }
109 } else {
110 more_this = false;
111 }
112 ++current_input;
113 ++other_input;
114 }
115 return HasSameReturnLocationsAs(OpParameter<CallDescriptor const*>(node));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000116}
117
118
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400119CallDescriptor* Linkage::ComputeIncoming(Zone* zone, CompilationInfo* info) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100120 DCHECK(!info->IsStub());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000121 if (info->has_literal()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000122 // If we already have the function literal, use the number of parameters
123 // plus the receiver.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000124 return GetJSCallDescriptor(zone, info->is_osr(),
125 1 + info->literal()->parameter_count(),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400126 CallDescriptor::kNoFlags);
127 }
128 if (!info->closure().is_null()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000129 // If we are compiling a JS function, use a JS call descriptor,
130 // plus the receiver.
131 SharedFunctionInfo* shared = info->closure()->shared();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000132 return GetJSCallDescriptor(zone, info->is_osr(),
133 1 + shared->internal_formal_parameter_count(),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400134 CallDescriptor::kNoFlags);
135 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000136 return nullptr; // TODO(titzer): ?
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000137}
138
139
140// static
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000141int Linkage::FrameStateInputCount(Runtime::FunctionId 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 deoptimize
144 // are blacklisted here and can be called without a FrameState.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000145 switch (function) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000146 case Runtime::kAllocateInTargetSpace:
147 case Runtime::kCreateIterResultObject:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100148 case Runtime::kDefineDataPropertyInLiteral:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000149 case Runtime::kDefineGetterPropertyUnchecked: // TODO(jarin): Is it safe?
150 case Runtime::kDefineSetterPropertyUnchecked: // TODO(jarin): Is it safe?
151 case Runtime::kFinalizeClassDefinition: // TODO(conradw): Is it safe?
152 case Runtime::kForInDone:
153 case Runtime::kForInStep:
154 case Runtime::kGetSuperConstructor:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100155 case Runtime::kIsFunction:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000156 case Runtime::kNewClosure:
157 case Runtime::kNewClosure_Tenured:
158 case Runtime::kNewFunctionContext:
159 case Runtime::kPushBlockContext:
160 case Runtime::kPushCatchContext:
161 case Runtime::kReThrow:
162 case Runtime::kStringCompare:
163 case Runtime::kStringEquals:
164 case Runtime::kToFastProperties: // TODO(jarin): Is it safe?
165 case Runtime::kTraceEnter:
166 case Runtime::kTraceExit:
167 return 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000168 case Runtime::kInlineGetPrototype:
169 case Runtime::kInlineRegExpConstructResult:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400170 case Runtime::kInlineRegExpExec:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000171 case Runtime::kInlineSubString:
172 case Runtime::kInlineToInteger:
173 case Runtime::kInlineToLength:
174 case Runtime::kInlineToName:
175 case Runtime::kInlineToNumber:
176 case Runtime::kInlineToObject:
177 case Runtime::kInlineToPrimitive_Number:
178 case Runtime::kInlineToPrimitive_String:
179 case Runtime::kInlineToPrimitive:
180 case Runtime::kInlineToString:
181 return 1;
182 case Runtime::kInlineCall:
183 case Runtime::kInlineTailCall:
184 case Runtime::kInlineDeoptimizeNow:
185 case Runtime::kInlineThrowNotDateError:
186 return 2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000187 default:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000188 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000189 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000190
191 // Most inlined runtime functions (except the ones listed above) can be called
192 // without a FrameState or will be lowered by JSIntrinsicLowering internally.
193 const Runtime::Function* const f = Runtime::FunctionForId(function);
194 if (f->intrinsic_type == Runtime::IntrinsicType::INLINE) return 0;
195
196 return 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000197}
198
199
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000200bool CallDescriptor::UsesOnlyRegisters() const {
201 for (size_t i = 0; i < InputCount(); ++i) {
202 if (!GetInputLocation(i).IsRegister()) return false;
203 }
204 for (size_t i = 0; i < ReturnCount(); ++i) {
205 if (!GetReturnLocation(i).IsRegister()) return false;
206 }
207 return true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000208}
209
210
211CallDescriptor* Linkage::GetRuntimeCallDescriptor(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000212 Zone* zone, Runtime::FunctionId function_id, int js_parameter_count,
213 Operator::Properties properties, CallDescriptor::Flags flags) {
214 const size_t function_count = 1;
215 const size_t num_args_count = 1;
216 const size_t context_count = 1;
217 const size_t parameter_count = function_count +
218 static_cast<size_t>(js_parameter_count) +
219 num_args_count + context_count;
220
221 const Runtime::Function* function = Runtime::FunctionForId(function_id);
222 const size_t return_count = static_cast<size_t>(function->result_size);
223
224 LocationSignature::Builder locations(zone, return_count, parameter_count);
225 MachineSignature::Builder types(zone, return_count, parameter_count);
226
227 // Add returns.
228 if (locations.return_count_ > 0) {
229 locations.AddReturn(regloc(kReturnRegister0));
230 }
231 if (locations.return_count_ > 1) {
232 locations.AddReturn(regloc(kReturnRegister1));
233 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100234 if (locations.return_count_ > 2) {
235 locations.AddReturn(regloc(kReturnRegister2));
236 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000237 for (size_t i = 0; i < return_count; i++) {
238 types.AddReturn(MachineType::AnyTagged());
239 }
240
241 // All parameters to the runtime call go on the stack.
242 for (int i = 0; i < js_parameter_count; i++) {
243 locations.AddParam(
244 LinkageLocation::ForCallerFrameSlot(i - js_parameter_count));
245 types.AddParam(MachineType::AnyTagged());
246 }
247 // Add runtime function itself.
248 locations.AddParam(regloc(kRuntimeCallFunctionRegister));
249 types.AddParam(MachineType::AnyTagged());
250
251 // Add runtime call argument count.
252 locations.AddParam(regloc(kRuntimeCallArgCountRegister));
253 types.AddParam(MachineType::Pointer());
254
255 // Add context.
256 locations.AddParam(regloc(kContextRegister));
257 types.AddParam(MachineType::AnyTagged());
258
259 if (Linkage::FrameStateInputCount(function_id) == 0) {
260 flags = static_cast<CallDescriptor::Flags>(
261 flags & ~CallDescriptor::kNeedsFrameState);
262 }
263
264 // The target for runtime calls is a code object.
265 MachineType target_type = MachineType::AnyTagged();
266 LinkageLocation target_loc = LinkageLocation::ForAnyRegister();
267 return new (zone) CallDescriptor( // --
268 CallDescriptor::kCallCodeObject, // kind
269 target_type, // target MachineType
270 target_loc, // target location
271 types.Build(), // machine_sig
272 locations.Build(), // location_sig
273 js_parameter_count, // stack_parameter_count
274 properties, // properties
275 kNoCalleeSaved, // callee-saved
276 kNoCalleeSaved, // callee-saved fp
277 flags, // flags
278 function->name); // debug name
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000279}
280
281
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000282CallDescriptor* 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 js_parameter_count + new_target_count + num_args_count + context_count;
291
292 LocationSignature::Builder locations(zone, return_count, parameter_count);
293 MachineSignature::Builder types(zone, return_count, parameter_count);
294
295 // All JS calls have exactly one return value.
296 locations.AddReturn(regloc(kReturnRegister0));
297 types.AddReturn(MachineType::AnyTagged());
298
299 // All parameters to JS calls go on the stack.
300 for (int i = 0; i < js_parameter_count; i++) {
301 int spill_slot_index = i - js_parameter_count;
302 locations.AddParam(LinkageLocation::ForCallerFrameSlot(spill_slot_index));
303 types.AddParam(MachineType::AnyTagged());
304 }
305
306 // Add JavaScript call new target value.
307 locations.AddParam(regloc(kJavaScriptCallNewTargetRegister));
308 types.AddParam(MachineType::AnyTagged());
309
310 // Add JavaScript call argument count.
311 locations.AddParam(regloc(kJavaScriptCallArgCountRegister));
312 types.AddParam(MachineType::Int32());
313
314 // Add context.
315 locations.AddParam(regloc(kContextRegister));
316 types.AddParam(MachineType::AnyTagged());
317
318 // The target for JS function calls is the JSFunction object.
319 MachineType target_type = MachineType::AnyTagged();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100320 // When entering into an OSR function from unoptimized code the JSFunction
321 // is not in a register, but it is on the stack in the marker spill slot.
322 LinkageLocation target_loc = is_osr ? LinkageLocation::ForSavedCallerMarker()
323 : regloc(kJSFunctionRegister);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000324 return new (zone) CallDescriptor( // --
325 CallDescriptor::kCallJSFunction, // kind
326 target_type, // target MachineType
327 target_loc, // target location
328 types.Build(), // machine_sig
329 locations.Build(), // location_sig
330 js_parameter_count, // stack_parameter_count
331 Operator::kNoProperties, // properties
332 kNoCalleeSaved, // callee-saved
333 kNoCalleeSaved, // callee-saved fp
334 CallDescriptor::kCanUseRoots | // flags
335 flags, // flags
336 "js-call");
337}
338
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000339// TODO(all): Add support for return representations/locations to
340// CallInterfaceDescriptor.
341// TODO(turbofan): cache call descriptors for code stub calls.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000342CallDescriptor* Linkage::GetStubCallDescriptor(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000343 Isolate* isolate, Zone* zone, const CallInterfaceDescriptor& descriptor,
344 int stack_parameter_count, CallDescriptor::Flags flags,
345 Operator::Properties properties, MachineType return_type,
346 size_t return_count) {
347 const int register_parameter_count = descriptor.GetRegisterParameterCount();
348 const int js_parameter_count =
349 register_parameter_count + stack_parameter_count;
350 const int context_count = 1;
351 const size_t parameter_count =
352 static_cast<size_t>(js_parameter_count + context_count);
353
354 LocationSignature::Builder locations(zone, return_count, parameter_count);
355 MachineSignature::Builder types(zone, return_count, parameter_count);
356
357 // Add returns.
358 if (locations.return_count_ > 0) {
359 locations.AddReturn(regloc(kReturnRegister0));
360 }
361 if (locations.return_count_ > 1) {
362 locations.AddReturn(regloc(kReturnRegister1));
363 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100364 if (locations.return_count_ > 2) {
365 locations.AddReturn(regloc(kReturnRegister2));
366 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000367 for (size_t i = 0; i < return_count; i++) {
368 types.AddReturn(return_type);
369 }
370
371 // Add parameters in registers and on the stack.
372 for (int i = 0; i < js_parameter_count; i++) {
373 if (i < register_parameter_count) {
374 // The first parameters go in registers.
375 Register reg = descriptor.GetRegisterParameter(i);
376 Representation rep =
377 RepresentationFromType(descriptor.GetParameterType(i));
378 locations.AddParam(regloc(reg));
379 types.AddParam(reptyp(rep));
380 } else {
381 // The rest of the parameters go on the stack.
382 int stack_slot = i - register_parameter_count - stack_parameter_count;
383 locations.AddParam(LinkageLocation::ForCallerFrameSlot(stack_slot));
384 types.AddParam(MachineType::AnyTagged());
385 }
386 }
387 // Add context.
388 locations.AddParam(regloc(kContextRegister));
389 types.AddParam(MachineType::AnyTagged());
390
391 // The target for stub calls is a code object.
392 MachineType target_type = MachineType::AnyTagged();
393 LinkageLocation target_loc = LinkageLocation::ForAnyRegister();
394 return new (zone) CallDescriptor( // --
395 CallDescriptor::kCallCodeObject, // kind
396 target_type, // target MachineType
397 target_loc, // target location
398 types.Build(), // machine_sig
399 locations.Build(), // location_sig
400 stack_parameter_count, // stack_parameter_count
401 properties, // properties
402 kNoCalleeSaved, // callee-saved registers
403 kNoCalleeSaved, // callee-saved fp
404 flags, // flags
405 descriptor.DebugName(isolate));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000406}
407
408
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000409LinkageLocation Linkage::GetOsrValueLocation(int index) const {
410 CHECK(incoming_->IsJSFunctionCall());
411 int parameter_count = static_cast<int>(incoming_->JSParameterCount() - 1);
412 int first_stack_slot = OsrHelper::FirstStackSlotIndex(parameter_count);
413
414 if (index == kOsrContextSpillSlotIndex) {
415 // Context. Use the parameter location of the context spill slot.
416 // Parameter (arity + 2) is special for the context of the function frame.
417 // >> context_index = target + receiver + params + new_target + #args
418 int context_index = 1 + 1 + parameter_count + 1 + 1;
419 return incoming_->GetInputLocation(context_index);
420 } else if (index >= first_stack_slot) {
421 // Local variable stored in this (callee) stack.
422 int spill_index =
423 index - first_stack_slot + StandardFrameConstants::kFixedSlotCount;
424 return LinkageLocation::ForCalleeFrameSlot(spill_index);
425 } else {
426 // Parameter. Use the assigned location from the incoming call descriptor.
427 int parameter_index = 1 + index; // skip index 0, which is the target.
428 return incoming_->GetInputLocation(parameter_index);
429 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000430}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000431
432
433bool Linkage::ParameterHasSecondaryLocation(int index) const {
434 if (incoming_->kind() != CallDescriptor::kCallJSFunction) return false;
435 LinkageLocation loc = GetParameterLocation(index);
436 return (loc == regloc(kJSFunctionRegister) ||
437 loc == regloc(kContextRegister));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000438}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000439
440LinkageLocation Linkage::GetParameterSecondaryLocation(int index) const {
441 DCHECK(ParameterHasSecondaryLocation(index));
442 LinkageLocation loc = GetParameterLocation(index);
443
444 if (loc == regloc(kJSFunctionRegister)) {
445 return LinkageLocation::ForCalleeFrameSlot(Frame::kJSFunctionSlot);
446 } else {
447 DCHECK(loc == regloc(kContextRegister));
448 return LinkageLocation::ForCalleeFrameSlot(Frame::kContextSlot);
449 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000450}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000451
452
453} // namespace compiler
454} // namespace internal
455} // namespace v8