linkage.h 17.3 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/compiler-specific.h"
9
#include "src/base/flags.h"
10 11
#include "src/compiler/frame.h"
#include "src/compiler/operator.h"
12
#include "src/globals.h"
13
#include "src/interface-descriptors.h"
14
#include "src/machine-type.h"
15
#include "src/reglist.h"
16
#include "src/runtime/runtime.h"
17
#include "src/zone/zone.h"
18 19 20

namespace v8 {
namespace internal {
21 22

class CallInterfaceDescriptor;
23
class OptimizedCompilationInfo;
24

25 26
namespace compiler {

27 28
const RegList kNoCalleeSaved = 0;

29
class Node;
30 31
class OsrHelper;

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

39 40
  bool operator!=(const LinkageLocation& other) const {
    return !(*this == other);
svenpanne's avatar
svenpanne committed
41 42
  }

43 44 45
  static LinkageLocation ForAnyRegister(
      MachineType type = MachineType::None()) {
    return LinkageLocation(REGISTER, ANY_REGISTER, type);
46
  }
47

48 49
  static LinkageLocation ForRegister(int32_t reg,
                                     MachineType type = MachineType::None()) {
50
    DCHECK_LE(0, reg);
51
    return LinkageLocation(REGISTER, reg, type);
52
  }
53

54
  static LinkageLocation ForCallerFrameSlot(int32_t slot, MachineType type) {
55
    DCHECK_GT(0, slot);
56
    return LinkageLocation(STACK_SLOT, slot, type);
svenpanne's avatar
svenpanne committed
57 58
  }

59
  static LinkageLocation ForCalleeFrameSlot(int32_t slot, MachineType type) {
60 61
    // TODO(titzer): bailout instead of crashing here.
    DCHECK(slot >= 0 && slot < LinkageLocation::MAX_STACK_SLOT);
62
    return LinkageLocation(STACK_SLOT, slot, type);
svenpanne's avatar
svenpanne committed
63 64
  }

65 66 67
  static LinkageLocation ForSavedCallerReturnAddress() {
    return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset -
                               StandardFrameConstants::kCallerPCOffset) /
68 69
                                  kPointerSize,
                              MachineType::Pointer());
70 71 72 73 74
  }

  static LinkageLocation ForSavedCallerFramePtr() {
    return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset -
                               StandardFrameConstants::kCallerFPOffset) /
75 76
                                  kPointerSize,
                              MachineType::Pointer());
77 78 79 80 81 82
  }

  static LinkageLocation ForSavedCallerConstantPool() {
    DCHECK(V8_EMBEDDED_CONSTANT_POOL);
    return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset -
                               StandardFrameConstants::kConstantPoolOffset) /
83 84
                                  kPointerSize,
                              MachineType::AnyTagged());
85 86
  }

87
  static LinkageLocation ForSavedCallerFunction() {
88
    return ForCalleeFrameSlot((StandardFrameConstants::kCallerPCOffset -
89
                               StandardFrameConstants::kFunctionOffset) /
90 91
                                  kPointerSize,
                              MachineType::AnyTagged());
92 93
  }

94 95 96 97
  static LinkageLocation ConvertToTailCallerLocation(
      LinkageLocation caller_location, int stack_param_delta) {
    if (!caller_location.IsRegister()) {
      return LinkageLocation(STACK_SLOT,
98 99
                             caller_location.GetLocation() + stack_param_delta,
                             caller_location.GetType());
100 101 102 103
    }
    return caller_location;
  }

104 105 106 107 108 109 110 111 112
  MachineType GetType() const { return machine_type_; }

  int GetSize() const {
    return 1 << ElementSizeLog2Of(GetType().representation());
  }

  int GetSizeInPointers() const {
    // Round up
    return (GetSize() + kPointerSize - 1) / kPointerSize;
113 114 115
  }

  int32_t GetLocation() const {
116 117
    // We can't use LocationField::decode here because it doesn't work for
    // negative values!
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
    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();
  }

142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
 private:
  enum LocationType { REGISTER, STACK_SLOT };

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

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

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

158
  int32_t bit_field_;
159
  MachineType machine_type_;
160 161
};

162
typedef Signature<LinkageLocation> LocationSignature;
163

164 165
// 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.
166 167
class V8_EXPORT_PRIVATE CallDescriptor final
    : public NON_EXPORTED_BASE(ZoneObject) {
168
 public:
169 170
  // Describes the kind of this call, which determines the target.
  enum Kind {
171 172 173 174
    kCallCodeObject,   // target is a Code object
    kCallJSFunction,   // target is a JSFunction object
    kCallAddress,      // target is a machine pointer
    kCallWasmFunction  // target is a wasm function
175
  };
176

177 178
  enum Flag {
    kNoFlags = 0u,
179
    kNeedsFrameState = 1u << 0,
180
    kHasExceptionHandler = 1u << 1,
181
    kCanUseRoots = 1u << 2,
182
    // Causes the code generator to initialize the root register.
183
    kInitializeRootRegister = 1u << 3,
184
    // Does not ever try to allocate space on our heap.
185
    kNoAllocate = 1u << 4,
186
    // Push argument count as part of function prologue.
187 188
    kPushArgumentCount = 1u << 5,
    // Use retpoline for this call if indirect.
189 190 191 192
    kRetpoline = 1u << 6,
    // Use the kJavaScriptCallCodeStartRegister (fixed) register for the
    // indirect target address when calling.
    kFixedTargetRegister = 1u << 7
193
  };
194
  typedef base::Flags<Flag> Flags;
195

196
  CallDescriptor(Kind kind, MachineType target_type, LinkageLocation target_loc,
197
                 LocationSignature* location_sig, size_t stack_param_count,
198
                 Operator::Properties properties,
199 200
                 RegList callee_saved_registers,
                 RegList callee_saved_fp_registers, Flags flags,
201
                 const char* debug_name = "",
202 203
                 const RegList allocatable_registers = 0,
                 size_t stack_return_count = 0)
204
      : kind_(kind),
205 206 207
        target_type_(target_type),
        target_loc_(target_loc),
        location_sig_(location_sig),
208
        stack_param_count_(stack_param_count),
209
        stack_return_count_(stack_return_count),
210 211
        properties_(properties),
        callee_saved_registers_(callee_saved_registers),
212
        callee_saved_fp_registers_(callee_saved_fp_registers),
213
        allocatable_registers_(allocatable_registers),
214
        flags_(flags),
215
        debug_name_(debug_name) {}
216

217 218 219
  // Returns the kind of this call.
  Kind kind() const { return kind_; }

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

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

226 227 228
  // Returns {true} if this descriptor is a call to a WebAssembly function.
  bool IsWasmFunctionCall() const { return kind_ == kCallWasmFunction; }

229
  bool RequiresFrameAsIncoming() const {
230
    return IsCFunctionCall() || IsJSFunctionCall() || IsWasmFunctionCall();
231 232
  }

233
  // The number of return values from this call.
234
  size_t ReturnCount() const { return location_sig_->return_count(); }
235

236
  // The number of C parameters to this call.
237
  size_t ParameterCount() const { return location_sig_->parameter_count(); }
238

239 240 241
  // The number of stack parameters to the call.
  size_t StackParameterCount() const { return stack_param_count_; }

242 243 244
  // The number of stack return values from the call.
  size_t StackReturnCount() const { return stack_return_count_; }

245 246 247 248 249
  // The number of parameters to the JS function call.
  size_t JSParameterCount() const {
    DCHECK(IsJSFunctionCall());
    return stack_param_count_;
  }
250

251 252 253
  // The total number of inputs to this call, which includes the target,
  // receiver, context, etc.
  // TODO(titzer): this should input the framestate input too.
254
  size_t InputCount() const { return 1 + location_sig_->parameter_count(); }
255

256
  size_t FrameStateCount() const { return NeedsFrameState() ? 1 : 0; }
257

258
  Flags flags() const { return flags_; }
259

260
  bool NeedsFrameState() const { return flags() & kNeedsFrameState; }
261
  bool PushArgumentCount() const { return flags() & kPushArgumentCount; }
262 263 264
  bool InitializeRootRegister() const {
    return flags() & kInitializeRootRegister;
  }
265

266 267
  LinkageLocation GetReturnLocation(size_t index) const {
    return location_sig_->GetReturn(index);
268 269
  }

270 271 272 273 274
  LinkageLocation GetInputLocation(size_t index) const {
    if (index == 0) return target_loc_;
    return location_sig_->GetParam(index - 1);
  }

275
  MachineSignature* GetMachineSignature(Zone* zone) const;
276 277

  MachineType GetReturnType(size_t index) const {
278
    return location_sig_->GetReturn(index).GetType();
279 280 281 282
  }

  MachineType GetInputType(size_t index) const {
    if (index == 0) return target_type_;
283 284 285 286 287
    return location_sig_->GetParam(index - 1).GetType();
  }

  MachineType GetParameterType(size_t index) const {
    return location_sig_->GetParam(index).GetType();
288 289 290
  }

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

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

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

299 300
  const char* debug_name() const { return debug_name_; }

svenpanne's avatar
svenpanne committed
301 302 303 304
  bool UsesOnlyRegisters() const;

  bool HasSameReturnLocationsAs(const CallDescriptor* other) const;

305 306 307
  // Returns the first stack slot that is not used by the stack parameters.
  int GetFirstUnusedStackSlot() const;

308
  int GetStackParameterDelta(const CallDescriptor* tail_caller) const;
309 310

  bool CanTailCall(const Node* call) const;
311 312

  int CalculateFixedFrameSize() const;
313

314 315 316 317 318 319
  RegList AllocatableRegisters() const { return allocatable_registers_; }

  bool HasRestrictedAllocatableRegisters() const {
    return allocatable_registers_ != 0;
  }

320 321 322 323
  void set_save_fp_mode(SaveFPRegsMode mode) { save_fp_mode_ = mode; }

  SaveFPRegsMode get_save_fp_mode() const { return save_fp_mode_; }

324 325
 private:
  friend class Linkage;
326
  SaveFPRegsMode save_fp_mode_ = kSaveFPRegs;
327

328 329 330 331
  const Kind kind_;
  const MachineType target_type_;
  const LinkageLocation target_loc_;
  const LocationSignature* const location_sig_;
332
  const size_t stack_param_count_;
333
  const size_t stack_return_count_;
334 335
  const Operator::Properties properties_;
  const RegList callee_saved_registers_;
336
  const RegList callee_saved_fp_registers_;
337 338 339
  // Non-zero value means restricting the set of allocatable registers for
  // register allocator to use.
  const RegList allocatable_registers_;
340 341 342 343
  const Flags flags_;
  const char* const debug_name_;

  DISALLOW_COPY_AND_ASSIGN(CallDescriptor);
344 345
};

346 347
DEFINE_OPERATORS_FOR_FLAGS(CallDescriptor::Flags)

348
std::ostream& operator<<(std::ostream& os, const CallDescriptor& d);
349 350
V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
                                           const CallDescriptor::Kind& k);
351 352 353 354 355 356 357 358

// 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
359
// layouts are supported (where {n} is the number of value inputs):
360
//
361 362 363 364
//                        #0          #1     #2     [...]             #n
// Call[CodeStub]         code,       arg 1, arg 2, [...],            context
// Call[JSFunction]       function,   rcvr,  arg 1, [...], new, #arg, context
// Call[Runtime]          CEntryStub, arg 1, arg 2, [...], fun, #arg, context
365
// Call[BytecodeDispatch] address,    arg 1, arg 2, [...]
366
class V8_EXPORT_PRIVATE Linkage : public NON_EXPORTED_BASE(ZoneObject) {
367
 public:
368 369
  enum ContextSpecification { kNoContext, kPassContext };

370
  explicit Linkage(CallDescriptor* incoming) : incoming_(incoming) {}
371

372 373
  static CallDescriptor* ComputeIncoming(Zone* zone,
                                         OptimizedCompilationInfo* info);
374 375 376

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

382
  static CallDescriptor* GetRuntimeCallDescriptor(
383
      Zone* zone, Runtime::FunctionId function, int js_parameter_count,
384
      Operator::Properties properties, CallDescriptor::Flags flags);
385

386 387 388 389 390
  static CallDescriptor* GetCEntryStubCallDescriptor(
      Zone* zone, int return_count, int js_parameter_count,
      const char* debug_name, Operator::Properties properties,
      CallDescriptor::Flags flags);

391
  static CallDescriptor* GetStubCallDescriptor(
392 393
      Isolate* isolate, Zone* zone, const CallInterfaceDescriptor& descriptor,
      int stack_parameter_count, CallDescriptor::Flags flags,
394
      Operator::Properties properties = Operator::kNoProperties,
395
      MachineType return_type = MachineType::AnyTagged(),
396 397
      size_t return_count = 1,
      ContextSpecification context_spec = kPassContext);
398

399
  static CallDescriptor* GetAllocateCallDescriptor(Zone* zone);
400 401 402 403
  static CallDescriptor* GetBytecodeDispatchCallDescriptor(
      Isolate* isolate, Zone* zone, const CallInterfaceDescriptor& descriptor,
      int stack_parameter_count);

404 405 406 407
  // 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.
408 409 410
  static CallDescriptor* GetSimplifiedCDescriptor(
      Zone* zone, const MachineSignature* sig,
      bool set_initialize_root_flag = false);
411 412

  // Get the location of an (incoming) parameter to this function.
413
  LinkageLocation GetParameterLocation(int index) const {
414 415 416 417
    return incoming_->GetInputLocation(index + 1);  // + 1 to skip target.
  }

  // Get the machine type of an (incoming) parameter to this function.
418
  MachineType GetParameterType(int index) const {
419
    return incoming_->GetInputType(index + 1);  // + 1 to skip target.
420 421 422
  }

  // Get the location where this function should place its return value.
423 424
  LinkageLocation GetReturnLocation(size_t index = 0) const {
    return incoming_->GetReturnLocation(index);
425 426
  }

427
  // Get the machine type of this function's return value.
428 429 430
  MachineType GetReturnType(size_t index = 0) const {
    return incoming_->GetReturnType(index);
  }
431

432 433 434
  bool ParameterHasSecondaryLocation(int index) const;
  LinkageLocation GetParameterSecondaryLocation(int index) const;

435
  static bool NeedsFrameStateInput(Runtime::FunctionId function);
436

437 438 439
  // Get the location where an incoming OSR value is stored.
  LinkageLocation GetOsrValueLocation(int index) const;

440 441 442 443 444
  // A special {Parameter} index for Stub Calls that represents context.
  static int GetStubCallContextParamIndex(int parameter_count) {
    return parameter_count + 0;  // Parameter (arity + 0) is special.
  }

445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461
  // 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;
462

463 464 465
  // A special {OsrValue} index to indicate the context spill slot.
  static const int kOsrContextSpillSlotIndex = -1;

466 467 468
  // A special {OsrValue} index to indicate the accumulator register.
  static const int kOsrAccumulatorRegisterIndex = -1;

469
 private:
470 471 472
  CallDescriptor* const incoming_;

  DISALLOW_COPY_AND_ASSIGN(Linkage);
473
};
474 475 476 477

}  // namespace compiler
}  // namespace internal
}  // namespace v8
478 479

#endif  // V8_COMPILER_LINKAGE_H_