linkage.h 12.4 KB
Newer Older
1 2 3 4 5 6 7
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_COMPILER_LINKAGE_H_
#define V8_COMPILER_LINKAGE_H_

8
#include "src/base/flags.h"
9
#include "src/compiler/frame.h"
10
#include "src/compiler/machine-type.h"
11
#include "src/compiler/operator.h"
12 13
#include "src/frames.h"
#include "src/runtime/runtime.h"
14 15 16 17
#include "src/zone.h"

namespace v8 {
namespace internal {
18 19

class CallInterfaceDescriptor;
20
class CompilationInfo;
21

22 23
namespace compiler {

24 25
const RegList kNoCalleeSaved = 0;

26
class Node;
27 28
class OsrHelper;

29 30 31
// Describes the location for a parameter or a return value to a call.
class LinkageLocation {
 public:
32 33 34
  bool operator==(const LinkageLocation& other) const {
    return bit_field_ == other.bit_field_;
  }
35

36 37
  bool operator!=(const LinkageLocation& other) const {
    return !(*this == other);
svenpanne's avatar
svenpanne committed
38 39
  }

40 41 42
  static LinkageLocation ForAnyRegister() {
    return LinkageLocation(REGISTER, ANY_REGISTER);
  }
43

44 45 46 47
  static LinkageLocation ForRegister(int32_t reg) {
    DCHECK(reg >= 0);
    return LinkageLocation(REGISTER, reg);
  }
48

49 50 51
  static LinkageLocation ForCallerFrameSlot(int32_t slot) {
    DCHECK(slot < 0);
    return LinkageLocation(STACK_SLOT, slot);
svenpanne's avatar
svenpanne committed
52 53
  }

54 55 56 57
  static LinkageLocation ForCalleeFrameSlot(int32_t slot) {
    // TODO(titzer): bailout instead of crashing here.
    DCHECK(slot >= 0 && slot < LinkageLocation::MAX_STACK_SLOT);
    return LinkageLocation(STACK_SLOT, slot);
svenpanne's avatar
svenpanne committed
58 59
  }

60 61 62
 private:
  friend class CallDescriptor;
  friend class OperandGenerator;
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102

  enum LocationType { REGISTER, STACK_SLOT };

  class TypeField : public BitField<LocationType, 0, 1> {};
  class LocationField : public BitField<int32_t, TypeField::kNext, 31> {};

  static const int32_t ANY_REGISTER = -1;
  static const int32_t MAX_STACK_SLOT = 32767;

  LinkageLocation(LocationType type, int32_t location) {
    bit_field_ = TypeField::encode(type) |
                 ((location << LocationField::kShift) & LocationField::kMask);
  }

  int32_t GetLocation() const {
    return static_cast<int32_t>(bit_field_ & LocationField::kMask) >>
           LocationField::kShift;
  }

  bool IsRegister() const { return TypeField::decode(bit_field_) == REGISTER; }
  bool IsAnyRegister() const {
    return IsRegister() && GetLocation() == ANY_REGISTER;
  }
  bool IsCallerFrameSlot() const { return !IsRegister() && GetLocation() < 0; }
  bool IsCalleeFrameSlot() const { return !IsRegister() && GetLocation() >= 0; }

  int32_t AsRegister() const {
    DCHECK(IsRegister());
    return GetLocation();
  }
  int32_t AsCallerFrameSlot() const {
    DCHECK(IsCallerFrameSlot());
    return GetLocation();
  }
  int32_t AsCalleeFrameSlot() const {
    DCHECK(IsCalleeFrameSlot());
    return GetLocation();
  }

  int32_t bit_field_;
103 104
};

105
typedef Signature<LinkageLocation> LocationSignature;
106

107 108
// Describes a call to various parts of the compiler. Every call has the notion
// of a "target", which is the first input to the call.
109
class CallDescriptor final : public ZoneObject {
110
 public:
111 112
  // Describes the kind of this call, which determines the target.
  enum Kind {
113 114 115
    kCallCodeObject,      // target is a Code object
    kCallJSFunction,      // target is a JSFunction object
    kCallAddress,         // target is a machine pointer
116
  };
117

118 119
  enum Flag {
    kNoFlags = 0u,
120 121 122
    kNeedsFrameState = 1u << 0,
    kPatchableCallSite = 1u << 1,
    kNeedsNopAfterCall = 1u << 2,
123
    kHasExceptionHandler = 1u << 3,
124 125
    kHasLocalCatchHandler = 1u << 4,
    kSupportsTailCalls = 1u << 5,
126
    kCanUseRoots = 1u << 6,
127
    kPatchableCallSiteWithNop = kPatchableCallSite | kNeedsNopAfterCall
128
  };
129
  typedef base::Flags<Flag> Flags;
130

131
  CallDescriptor(Kind kind, MachineType target_type, LinkageLocation target_loc,
132
                 const MachineSignature* machine_sig,
133
                 LocationSignature* location_sig, size_t stack_param_count,
134
                 Operator::Properties properties,
135 136
                 RegList callee_saved_registers,
                 RegList callee_saved_fp_registers, Flags flags,
137
                 const char* debug_name = "")
138
      : kind_(kind),
139 140 141 142
        target_type_(target_type),
        target_loc_(target_loc),
        machine_sig_(machine_sig),
        location_sig_(location_sig),
143
        stack_param_count_(stack_param_count),
144 145
        properties_(properties),
        callee_saved_registers_(callee_saved_registers),
146
        callee_saved_fp_registers_(callee_saved_fp_registers),
147
        flags_(flags),
148 149 150 151 152
        debug_name_(debug_name) {
    DCHECK(machine_sig->return_count() == location_sig->return_count());
    DCHECK(machine_sig->parameter_count() == location_sig->parameter_count());
  }

153 154 155
  // Returns the kind of this call.
  Kind kind() const { return kind_; }

156 157 158
  // Returns {true} if this descriptor is a call to a C function.
  bool IsCFunctionCall() const { return kind_ == kCallAddress; }

159 160 161
  // Returns {true} if this descriptor is a call to a JSFunction.
  bool IsJSFunctionCall() const { return kind_ == kCallJSFunction; }

162 163
  // The number of return values from this call.
  size_t ReturnCount() const { return machine_sig_->return_count(); }
164

165 166 167
  // The number of C parameters to this call.
  size_t CParameterCount() const { return machine_sig_->parameter_count(); }

168 169 170 171 172 173 174 175
  // The number of stack parameters to the call.
  size_t StackParameterCount() const { return stack_param_count_; }

  // The number of parameters to the JS function call.
  size_t JSParameterCount() const {
    DCHECK(IsJSFunctionCall());
    return stack_param_count_;
  }
176

177 178 179 180
  // The total number of inputs to this call, which includes the target,
  // receiver, context, etc.
  // TODO(titzer): this should input the framestate input too.
  size_t InputCount() const { return 1 + machine_sig_->parameter_count(); }
181

182
  size_t FrameStateCount() const { return NeedsFrameState() ? 1 : 0; }
183

184
  Flags flags() const { return flags_; }
185

186
  bool NeedsFrameState() const { return flags() & kNeedsFrameState; }
svenpanne's avatar
svenpanne committed
187
  bool SupportsTailCalls() const { return flags() & kSupportsTailCalls; }
188

189 190
  LinkageLocation GetReturnLocation(size_t index) const {
    return location_sig_->GetReturn(index);
191 192
  }

193 194 195 196 197 198 199 200 201 202 203 204 205 206
  LinkageLocation GetInputLocation(size_t index) const {
    if (index == 0) return target_loc_;
    return location_sig_->GetParam(index - 1);
  }

  const MachineSignature* GetMachineSignature() const { return machine_sig_; }

  MachineType GetReturnType(size_t index) const {
    return machine_sig_->GetReturn(index);
  }

  MachineType GetInputType(size_t index) const {
    if (index == 0) return target_type_;
    return machine_sig_->GetParam(index - 1);
207 208 209
  }

  // Operator properties describe how this call can be optimized, if at all.
210
  Operator::Properties properties() const { return properties_; }
211 212

  // Get the callee-saved registers, if any, across this call.
213
  RegList CalleeSavedRegisters() const { return callee_saved_registers_; }
214

215 216 217
  // Get the callee-saved FP registers, if any, across this call.
  RegList CalleeSavedFPRegisters() const { return callee_saved_fp_registers_; }

218 219
  const char* debug_name() const { return debug_name_; }

svenpanne's avatar
svenpanne committed
220 221 222 223
  bool UsesOnlyRegisters() const;

  bool HasSameReturnLocationsAs(const CallDescriptor* other) const;

224 225
  bool CanTailCall(const Node* call) const;

226 227 228
 private:
  friend class Linkage;

229 230 231 232 233
  const Kind kind_;
  const MachineType target_type_;
  const LinkageLocation target_loc_;
  const MachineSignature* const machine_sig_;
  const LocationSignature* const location_sig_;
234
  const size_t stack_param_count_;
235 236
  const Operator::Properties properties_;
  const RegList callee_saved_registers_;
237
  const RegList callee_saved_fp_registers_;
238 239 240 241
  const Flags flags_;
  const char* const debug_name_;

  DISALLOW_COPY_AND_ASSIGN(CallDescriptor);
242 243
};

244 245
DEFINE_OPERATORS_FOR_FLAGS(CallDescriptor::Flags)

246 247
std::ostream& operator<<(std::ostream& os, const CallDescriptor& d);
std::ostream& operator<<(std::ostream& os, const CallDescriptor::Kind& k);
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263

// Defines the linkage for a compilation, including the calling conventions
// for incoming parameters and return value(s) as well as the outgoing calling
// convention for any kind of call. Linkage is generally architecture-specific.
//
// Can be used to translate {arg_index} (i.e. index of the call node input) as
// well as {param_index} (i.e. as stored in parameter nodes) into an operator
// representing the architecture-specific location. The following call node
// layouts are supported (where {n} is the number value inputs):
//
//                  #0          #1     #2     #3     [...]             #n
// Call[CodeStub]   code,       arg 1, arg 2, arg 3, [...],            context
// Call[JSFunction] function,   rcvr,  arg 1, arg 2, [...],            context
// Call[Runtime]    CEntryStub, arg 1, arg 2, arg 3, [...], fun, #arg, context
class Linkage : public ZoneObject {
 public:
264
  explicit Linkage(CallDescriptor* incoming) : incoming_(incoming) {}
265 266

  static CallDescriptor* ComputeIncoming(Zone* zone, CompilationInfo* info);
267 268 269

  // The call descriptor for this compilation unit describes the locations
  // of incoming parameters and the outgoing return value(s).
270
  CallDescriptor* GetIncomingDescriptor() const { return incoming_; }
271 272
  static CallDescriptor* GetJSCallDescriptor(Zone* zone, bool is_osr,
                                             int parameter_count,
273
                                             CallDescriptor::Flags flags);
274
  static CallDescriptor* GetRuntimeCallDescriptor(
275
      Zone* zone, Runtime::FunctionId function, int parameter_count,
276
      Operator::Properties properties, bool needs_frame_state = true);
277

278
  static CallDescriptor* GetStubCallDescriptor(
279 280
      Isolate* isolate, Zone* zone, const CallInterfaceDescriptor& descriptor,
      int stack_parameter_count, CallDescriptor::Flags flags,
281 282
      Operator::Properties properties = Operator::kNoProperties,
      MachineType return_type = kMachAnyTagged);
283 284 285 286 287

  // Creates a call descriptor for simplified C calls that is appropriate
  // for the host platform. This simplified calling convention only supports
  // integers and pointers of one word size each, i.e. no floating point,
  // structs, pointers to members, etc.
288
  static CallDescriptor* GetSimplifiedCDescriptor(Zone* zone,
289
                                                  const MachineSignature* sig);
290

291 292 293
  // Creates a call descriptor for interpreter handler code stubs. These are not
  // intended to be called directly but are instead dispatched to by the
  // interpreter.
294
  static CallDescriptor* GetInterpreterDispatchDescriptor(Zone* zone);
295

296
  // Get the location of an (incoming) parameter to this function.
297
  LinkageLocation GetParameterLocation(int index) const {
298 299 300 301
    return incoming_->GetInputLocation(index + 1);  // + 1 to skip target.
  }

  // Get the machine type of an (incoming) parameter to this function.
302
  MachineType GetParameterType(int index) const {
303
    return incoming_->GetInputType(index + 1);  // + 1 to skip target.
304 305 306
  }

  // Get the location where this function should place its return value.
307
  LinkageLocation GetReturnLocation() const {
308 309 310
    return incoming_->GetReturnLocation(0);
  }

311
  // Get the machine type of this function's return value.
312
  MachineType GetReturnType() const { return incoming_->GetReturnType(0); }
313

314 315 316
  // Get the frame offset for a given spill slot. The location depends on the
  // calling convention and the specific frame layout, and may thus be
  // architecture-specific. Negative spill slots indicate arguments on the
317 318
  // caller's frame.
  FrameOffset GetFrameOffset(int spill_slot, Frame* frame) const;
319

320
  static int FrameStateInputCount(Runtime::FunctionId function);
321

322 323 324
  // Get the location where an incoming OSR value is stored.
  LinkageLocation GetOsrValueLocation(int index) const;

325 326 327
  // A special parameter index for JSCalls that represents the closure.
  static const int kJSFunctionCallClosureParamIndex = -1;

328 329 330
  // A special {OsrValue} index to indicate the context spill slot.
  static const int kOsrContextSpillSlotIndex = -1;

331 332
  // Special parameter indices used to pass fixed register data through
  // interpreter dispatches.
333 334 335 336 337
  static const int kInterpreterAccumulatorParameter = 0;
  static const int kInterpreterRegisterFileParameter = 1;
  static const int kInterpreterBytecodeOffsetParameter = 2;
  static const int kInterpreterBytecodeArrayParameter = 3;
  static const int kInterpreterDispatchTableParameter = 4;
338
  static const int kInterpreterContextParameter = 5;
339

340
 private:
341 342 343
  CallDescriptor* const incoming_;

  DISALLOW_COPY_AND_ASSIGN(Linkage);
344
};
345 346 347 348

}  // namespace compiler
}  // namespace internal
}  // namespace v8
349 350

#endif  // V8_COMPILER_LINKAGE_H_