linkage.h 14 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 10
#include "src/compiler/frame.h"
#include "src/compiler/operator.h"
11
#include "src/frames.h"
12
#include "src/machine-type.h"
13
#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 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
  static LinkageLocation ForSavedCallerReturnAddress() {
    return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset -
                               StandardFrameConstants::kCallerPCOffset) /
                              kPointerSize);
  }

  static LinkageLocation ForSavedCallerFramePtr() {
    return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset -
                               StandardFrameConstants::kCallerFPOffset) /
                              kPointerSize);
  }

  static LinkageLocation ForSavedCallerConstantPool() {
    DCHECK(V8_EMBEDDED_CONSTANT_POOL);
    return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset -
                               StandardFrameConstants::kConstantPoolOffset) /
                              kPointerSize);
  }

79 80 81 82
  static LinkageLocation ConvertToTailCallerLocation(
      LinkageLocation caller_location, int stack_param_delta) {
    if (!caller_location.IsRegister()) {
      return LinkageLocation(STACK_SLOT,
83
                             caller_location.GetLocation() - stack_param_delta);
84 85 86 87
    }
    return caller_location;
  }

88 89 90
 private:
  friend class CallDescriptor;
  friend class OperandGenerator;
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130

  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_;
131 132
};

133
typedef Signature<LinkageLocation> LocationSignature;
134

135 136
// 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.
137
class CallDescriptor final : public ZoneObject {
138
 public:
139 140
  // Describes the kind of this call, which determines the target.
  enum Kind {
141 142 143 144
    kCallCodeObject,  // target is a Code object
    kCallJSFunction,  // target is a JSFunction object
    kCallAddress,     // target is a machine pointer
    kLazyBailout      // the call is no-op, only used for lazy bailout
145
  };
146

147 148
  enum Flag {
    kNoFlags = 0u,
149 150 151
    kNeedsFrameState = 1u << 0,
    kPatchableCallSite = 1u << 1,
    kNeedsNopAfterCall = 1u << 2,
152
    kHasExceptionHandler = 1u << 3,
153 154
    kHasLocalCatchHandler = 1u << 4,
    kSupportsTailCalls = 1u << 5,
155
    kCanUseRoots = 1u << 6,
156
    // (arm64 only) native stack should be used for arguments.
157
    kUseNativeStack = 1u << 7,
158 159
    // (arm64 only) call instruction has to restore JSSP.
    kRestoreJSSP = 1u << 8,
160 161
    // Causes the code generator to initialize the root register.
    kInitializeRootRegister = 1u << 9,
162
    kPatchableCallSiteWithNop = kPatchableCallSite | kNeedsNopAfterCall
163
  };
164
  typedef base::Flags<Flag> Flags;
165

166
  CallDescriptor(Kind kind, MachineType target_type, LinkageLocation target_loc,
167
                 const MachineSignature* machine_sig,
168
                 LocationSignature* location_sig, size_t stack_param_count,
169
                 Operator::Properties properties,
170 171
                 RegList callee_saved_registers,
                 RegList callee_saved_fp_registers, Flags flags,
172
                 const char* debug_name = "")
173
      : kind_(kind),
174 175 176 177
        target_type_(target_type),
        target_loc_(target_loc),
        machine_sig_(machine_sig),
        location_sig_(location_sig),
178
        stack_param_count_(stack_param_count),
179 180
        properties_(properties),
        callee_saved_registers_(callee_saved_registers),
181
        callee_saved_fp_registers_(callee_saved_fp_registers),
182
        flags_(flags),
183 184 185 186 187
        debug_name_(debug_name) {
    DCHECK(machine_sig->return_count() == location_sig->return_count());
    DCHECK(machine_sig->parameter_count() == location_sig->parameter_count());
  }

188 189 190
  // Returns the kind of this call.
  Kind kind() const { return kind_; }

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

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

197 198 199 200
  bool RequiresFrameAsIncoming() const {
    return IsCFunctionCall() || IsJSFunctionCall();
  }

201 202
  // The number of return values from this call.
  size_t ReturnCount() const { return machine_sig_->return_count(); }
203

204 205 206
  // The number of C parameters to this call.
  size_t CParameterCount() const { return machine_sig_->parameter_count(); }

207 208 209 210 211 212 213 214
  // 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_;
  }
215

216 217 218 219
  // 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(); }
220

221
  size_t FrameStateCount() const { return NeedsFrameState() ? 1 : 0; }
222

223
  Flags flags() const { return flags_; }
224

225
  bool NeedsFrameState() const { return flags() & kNeedsFrameState; }
svenpanne's avatar
svenpanne committed
226
  bool SupportsTailCalls() const { return flags() & kSupportsTailCalls; }
227
  bool UseNativeStack() const { return flags() & kUseNativeStack; }
228 229 230
  bool InitializeRootRegister() const {
    return flags() & kInitializeRootRegister;
  }
231

232 233
  LinkageLocation GetReturnLocation(size_t index) const {
    return location_sig_->GetReturn(index);
234 235
  }

236 237 238 239 240 241 242 243 244 245 246 247 248 249
  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);
250 251 252
  }

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

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

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

261 262
  const char* debug_name() const { return debug_name_; }

svenpanne's avatar
svenpanne committed
263 264 265 266
  bool UsesOnlyRegisters() const;

  bool HasSameReturnLocationsAs(const CallDescriptor* other) const;

267
  bool CanTailCall(const Node* call, int* stack_param_delta) const;
268

269 270 271
 private:
  friend class Linkage;

272 273 274 275 276
  const Kind kind_;
  const MachineType target_type_;
  const LinkageLocation target_loc_;
  const MachineSignature* const machine_sig_;
  const LocationSignature* const location_sig_;
277
  const size_t stack_param_count_;
278 279
  const Operator::Properties properties_;
  const RegList callee_saved_registers_;
280
  const RegList callee_saved_fp_registers_;
281 282 283 284
  const Flags flags_;
  const char* const debug_name_;

  DISALLOW_COPY_AND_ASSIGN(CallDescriptor);
285 286
};

287 288
DEFINE_OPERATORS_FOR_FLAGS(CallDescriptor::Flags)

289 290
std::ostream& operator<<(std::ostream& os, const CallDescriptor& d);
std::ostream& operator<<(std::ostream& os, const CallDescriptor::Kind& k);
291 292 293 294 295 296 297 298

// 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
299
// layouts are supported (where {n} is the number of value inputs):
300 301 302
//
//                  #0          #1     #2     #3     [...]             #n
// Call[CodeStub]   code,       arg 1, arg 2, arg 3, [...],            context
303
// Call[JSFunction] function,   rcvr,  arg 1, arg 2, [...], new, #arg, context
304 305 306
// Call[Runtime]    CEntryStub, arg 1, arg 2, arg 3, [...], fun, #arg, context
class Linkage : public ZoneObject {
 public:
307
  explicit Linkage(CallDescriptor* incoming) : incoming_(incoming) {}
308 309

  static CallDescriptor* ComputeIncoming(Zone* zone, CompilationInfo* info);
310 311 312

  // The call descriptor for this compilation unit describes the locations
  // of incoming parameters and the outgoing return value(s).
313
  CallDescriptor* GetIncomingDescriptor() const { return incoming_; }
314 315
  static CallDescriptor* GetJSCallDescriptor(Zone* zone, bool is_osr,
                                             int parameter_count,
316
                                             CallDescriptor::Flags flags);
317

318
  static CallDescriptor* GetRuntimeCallDescriptor(
319
      Zone* zone, Runtime::FunctionId function, int parameter_count,
320
      Operator::Properties properties, CallDescriptor::Flags flags);
321

322 323
  static CallDescriptor* GetLazyBailoutDescriptor(Zone* zone);

324
  static CallDescriptor* GetStubCallDescriptor(
325 326
      Isolate* isolate, Zone* zone, const CallInterfaceDescriptor& descriptor,
      int stack_parameter_count, CallDescriptor::Flags flags,
327
      Operator::Properties properties = Operator::kNoProperties,
328 329
      MachineType return_type = MachineType::AnyTagged(),
      size_t return_count = 1);
330 331 332 333 334

  // 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.
335 336 337
  static CallDescriptor* GetSimplifiedCDescriptor(
      Zone* zone, const MachineSignature* sig,
      bool set_initialize_root_flag = false);
338 339

  // Get the location of an (incoming) parameter to this function.
340
  LinkageLocation GetParameterLocation(int index) const {
341 342 343 344
    return incoming_->GetInputLocation(index + 1);  // + 1 to skip target.
  }

  // Get the machine type of an (incoming) parameter to this function.
345
  MachineType GetParameterType(int index) const {
346
    return incoming_->GetInputType(index + 1);  // + 1 to skip target.
347 348 349
  }

  // Get the location where this function should place its return value.
350 351
  LinkageLocation GetReturnLocation(size_t index = 0) const {
    return incoming_->GetReturnLocation(index);
352 353
  }

354
  // Get the machine type of this function's return value.
355 356 357
  MachineType GetReturnType(size_t index = 0) const {
    return incoming_->GetReturnType(index);
  }
358

359 360 361
  bool ParameterHasSecondaryLocation(int index) const;
  LinkageLocation GetParameterSecondaryLocation(int index) const;

362
  static int FrameStateInputCount(Runtime::FunctionId function);
363

364 365 366
  // Get the location where an incoming OSR value is stored.
  LinkageLocation GetOsrValueLocation(int index) const;

367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
  // A special {Parameter} index for JSCalls that represents the new target.
  static int GetJSCallNewTargetParamIndex(int parameter_count) {
    return parameter_count + 0;  // Parameter (arity + 0) is special.
  }

  // A special {Parameter} index for JSCalls that represents the argument count.
  static int GetJSCallArgCountParamIndex(int parameter_count) {
    return parameter_count + 1;  // Parameter (arity + 1) is special.
  }

  // A special {Parameter} index for JSCalls that represents the context.
  static int GetJSCallContextParamIndex(int parameter_count) {
    return parameter_count + 2;  // Parameter (arity + 2) is special.
  }

  // A special {Parameter} index for JSCalls that represents the closure.
  static const int kJSCallClosureParamIndex = -1;
384

385 386 387
  // A special {OsrValue} index to indicate the context spill slot.
  static const int kOsrContextSpillSlotIndex = -1;

388
 private:
389 390 391
  CallDescriptor* const incoming_;

  DISALLOW_COPY_AND_ASSIGN(Linkage);
392
};
393 394 395 396

}  // namespace compiler
}  // namespace internal
}  // namespace v8
397 398

#endif  // V8_COMPILER_LINKAGE_H_