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/ast/scopes.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
17namespace v8 {
18namespace internal {
19namespace compiler {
20
21namespace {
22
23LinkageLocation regloc(Register reg, MachineType type) {
24  return LinkageLocation::ForRegister(reg.code(), type);
25}
26
27}  // namespace
28
29
30std::ostream& operator<<(std::ostream& os, const CallDescriptor::Kind& k) {
31  switch (k) {
32    case CallDescriptor::kCallCodeObject:
33      os << "Code";
34      break;
35    case CallDescriptor::kCallJSFunction:
36      os << "JS";
37      break;
38    case CallDescriptor::kCallAddress:
39      os << "Addr";
40      break;
41  }
42  return os;
43}
44
45
46std::ostream& operator<<(std::ostream& os, const CallDescriptor& d) {
47  // TODO(svenpanne) Output properties etc. and be less cryptic.
48  return os << d.kind() << ":" << d.debug_name() << ":r" << d.ReturnCount()
49            << "s" << d.StackParameterCount() << "i" << d.InputCount() << "f"
50            << d.FrameStateCount() << "t" << d.SupportsTailCalls();
51}
52
53MachineSignature* CallDescriptor::GetMachineSignature(Zone* zone) const {
54  size_t param_count = ParameterCount();
55  size_t return_count = ReturnCount();
56  MachineType* types = zone->NewArray<MachineType>(param_count + return_count);
57  int current = 0;
58  for (size_t i = 0; i < return_count; ++i) {
59    types[current++] = GetReturnType(i);
60  }
61  for (size_t i = 0; i < param_count; ++i) {
62    types[current++] = GetParameterType(i);
63  }
64  return new (zone) MachineSignature(return_count, param_count, types);
65}
66
67bool CallDescriptor::HasSameReturnLocationsAs(
68    const CallDescriptor* other) const {
69  if (ReturnCount() != other->ReturnCount()) return false;
70  for (size_t i = 0; i < ReturnCount(); ++i) {
71    if (GetReturnLocation(i) != other->GetReturnLocation(i)) return false;
72  }
73  return true;
74}
75
76int CallDescriptor::GetStackParameterDelta(
77    CallDescriptor const* tail_caller) const {
78  int callee_slots_above_sp = 0;
79  for (size_t i = 0; i < InputCount(); ++i) {
80    LinkageLocation operand = GetInputLocation(i);
81    if (!operand.IsRegister()) {
82      int new_candidate =
83          -operand.GetLocation() + operand.GetSizeInPointers() - 1;
84      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  if (tail_caller != nullptr) {
91    for (size_t i = 0; i < tail_caller->InputCount(); ++i) {
92      LinkageLocation operand = tail_caller->GetInputLocation(i);
93      if (!operand.IsRegister()) {
94        int new_candidate =
95            -operand.GetLocation() + operand.GetSizeInPointers() - 1;
96        if (new_candidate > tail_caller_slots_above_sp) {
97          tail_caller_slots_above_sp = new_candidate;
98        }
99      }
100    }
101  }
102  return callee_slots_above_sp - tail_caller_slots_above_sp;
103}
104
105bool CallDescriptor::CanTailCall(const Node* node) const {
106  return HasSameReturnLocationsAs(CallDescriptorOf(node->op()));
107}
108
109int CallDescriptor::CalculateFixedFrameSize() const {
110  switch (kind_) {
111    case kCallJSFunction:
112      return PushArgumentCount()
113                 ? OptimizedBuiltinFrameConstants::kFixedSlotCount
114                 : StandardFrameConstants::kFixedSlotCount;
115      break;
116    case kCallAddress:
117      return CommonFrameConstants::kFixedSlotCountAboveFp +
118             CommonFrameConstants::kCPSlotCount;
119      break;
120    case kCallCodeObject:
121      return TypedFrameConstants::kFixedSlotCount;
122  }
123  UNREACHABLE();
124  return 0;
125}
126
127CallDescriptor* Linkage::ComputeIncoming(Zone* zone, CompilationInfo* info) {
128  DCHECK(!info->IsStub());
129  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                               CallDescriptor::kNoFlags);
136  }
137  return nullptr;  // TODO(titzer): ?
138}
139
140
141// static
142bool Linkage::NeedsFrameStateInput(Runtime::FunctionId function) {
143  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  return true;
194}
195
196
197bool CallDescriptor::UsesOnlyRegisters() const {
198  for (size_t i = 0; i < InputCount(); ++i) {
199    if (!GetInputLocation(i).IsRegister()) return false;
200  }
201  for (size_t i = 0; i < ReturnCount(); ++i) {
202    if (!GetReturnLocation(i).IsRegister()) return false;
203  }
204  return true;
205}
206
207
208CallDescriptor* Linkage::GetRuntimeCallDescriptor(
209    Zone* zone, Runtime::FunctionId function_id, int js_parameter_count,
210    Operator::Properties properties, CallDescriptor::Flags flags) {
211  const Runtime::Function* function = Runtime::FunctionForId(function_id);
212  const int return_count = function->result_size;
213  const char* debug_name = function->name;
214
215  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                                     debug_name, properties, flags);
222}
223
224CallDescriptor* 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                                 num_args_count + context_count;
234
235  LocationSignature::Builder locations(zone, static_cast<size_t>(return_count),
236                                       static_cast<size_t>(parameter_count));
237
238  // Add returns.
239  if (locations.return_count_ > 0) {
240    locations.AddReturn(regloc(kReturnRegister0, MachineType::AnyTagged()));
241  }
242  if (locations.return_count_ > 1) {
243    locations.AddReturn(regloc(kReturnRegister1, MachineType::AnyTagged()));
244  }
245  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  for (int i = 0; i < js_parameter_count; i++) {
251    locations.AddParam(LinkageLocation::ForCallerFrameSlot(
252        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      debug_name);                      // debug name
280}
281
282CallDescriptor* 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
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  for (int i = 0; i < js_parameter_count; i++) {
299    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             : 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      "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.
339CallDescriptor* 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      register_parameter_count + stack_parameter_count;
347  const int context_count = 1;
348  const size_t parameter_count =
349      static_cast<size_t>(js_parameter_count + context_count);
350
351  LocationSignature::Builder locations(zone, return_count, parameter_count);
352
353  // Add returns.
354  if (locations.return_count_ > 0) {
355    locations.AddReturn(regloc(kReturnRegister0, return_type));
356  }
357  if (locations.return_count_ > 1) {
358    locations.AddReturn(regloc(kReturnRegister1, return_type));
359  }
360  if (locations.return_count_ > 2) {
361    locations.AddReturn(regloc(kReturnRegister2, return_type));
362  }
363
364  // Add parameters in registers and on the stack.
365  for (int i = 0; i < js_parameter_count; i++) {
366    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      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      descriptor.DebugName(isolate));
397}
398
399// static
400CallDescriptor* 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      "Allocate");
422}
423
424// static
425CallDescriptor* Linkage::GetBytecodeDispatchCallDescriptor(
426    Isolate* isolate, Zone* zone, const CallInterfaceDescriptor& descriptor,
427    int stack_parameter_count) {
428  const int register_parameter_count = descriptor.GetRegisterParameterCount();
429  const int parameter_count = register_parameter_count + stack_parameter_count;
430
431  LocationSignature::Builder locations(zone, 0, parameter_count);
432
433  // Add parameters in registers and on the stack.
434  for (int i = 0; i < parameter_count; i++) {
435    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      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      descriptor.DebugName(isolate));
463}
464
465LinkageLocation Linkage::GetOsrValueLocation(int index) const {
466  CHECK(incoming_->IsJSFunctionCall());
467  int parameter_count = static_cast<int>(incoming_->JSParameterCount() - 1);
468  int first_stack_slot = OsrHelper::FirstStackSlotIndex(parameter_count);
469
470  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    int context_index = 1 + 1 + parameter_count + 1 + 1;
475    return incoming_->GetInputLocation(context_index);
476  } else if (index >= first_stack_slot) {
477    // Local variable stored in this (callee) stack.
478    int spill_index =
479        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    int parameter_index = 1 + index;  // skip index 0, which is the target.
485    return incoming_->GetInputLocation(parameter_index);
486  }
487}
488
489
490bool Linkage::ParameterHasSecondaryLocation(int index) const {
491  if (!incoming_->IsJSFunctionCall()) return false;
492  LinkageLocation loc = GetParameterLocation(index);
493  return (loc == regloc(kJSFunctionRegister, MachineType::AnyTagged()) ||
494          loc == regloc(kContextRegister, MachineType::AnyTagged()));
495}
496
497LinkageLocation Linkage::GetParameterSecondaryLocation(int index) const {
498  DCHECK(ParameterHasSecondaryLocation(index));
499  LinkageLocation loc = GetParameterLocation(index);
500
501  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
515