blob: c13bd74f40833f62ea6de944d1982ba872496ecc [file] [log] [blame]
// 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_IMPL_H_
#define V8_COMPILER_LINKAGE_IMPL_H_
#include "src/code-stubs.h"
namespace v8 {
namespace internal {
namespace compiler {
// TODO(titzer): replace uses of int with size_t in LinkageHelper.
template <typename LinkageTraits>
class LinkageHelper {
public:
static const RegList kNoCalleeSaved = 0;
static void AddReturnLocations(LocationSignature::Builder* locations) {
DCHECK(locations->return_count_ <= 2);
if (locations->return_count_ > 0) {
locations->AddReturn(regloc(LinkageTraits::ReturnValueReg()));
}
if (locations->return_count_ > 1) {
locations->AddReturn(regloc(LinkageTraits::ReturnValue2Reg()));
}
}
// TODO(turbofan): cache call descriptors for JSFunction calls.
static CallDescriptor* GetJSCallDescriptor(Zone* zone, int js_parameter_count,
CallDescriptor::Flags flags) {
const size_t return_count = 1;
const size_t context_count = 1;
const size_t parameter_count = js_parameter_count + context_count;
LocationSignature::Builder locations(zone, return_count, parameter_count);
MachineSignature::Builder types(zone, return_count, parameter_count);
// Add returns.
AddReturnLocations(&locations);
for (size_t i = 0; i < return_count; i++) {
types.AddReturn(kMachAnyTagged);
}
// All parameters to JS calls go on the stack.
for (int i = 0; i < js_parameter_count; i++) {
int spill_slot_index = i - js_parameter_count;
locations.AddParam(stackloc(spill_slot_index));
types.AddParam(kMachAnyTagged);
}
// Add context.
locations.AddParam(regloc(LinkageTraits::ContextReg()));
types.AddParam(kMachAnyTagged);
// The target for JS function calls is the JSFunction object.
MachineType target_type = kMachAnyTagged;
LinkageLocation target_loc = regloc(LinkageTraits::JSCallFunctionReg());
return new (zone) CallDescriptor( // --
CallDescriptor::kCallJSFunction, // kind
target_type, // target MachineType
target_loc, // target location
types.Build(), // machine_sig
locations.Build(), // location_sig
js_parameter_count, // js_parameter_count
Operator::kNoProperties, // properties
kNoCalleeSaved, // callee-saved
flags, // flags
"js-call");
}
// TODO(turbofan): cache call descriptors for runtime calls.
static CallDescriptor* GetRuntimeCallDescriptor(
Zone* zone, Runtime::FunctionId function_id, int js_parameter_count,
Operator::Properties properties) {
const size_t function_count = 1;
const size_t num_args_count = 1;
const size_t context_count = 1;
const size_t parameter_count = function_count +
static_cast<size_t>(js_parameter_count) +
num_args_count + context_count;
const Runtime::Function* function = Runtime::FunctionForId(function_id);
const size_t return_count = static_cast<size_t>(function->result_size);
LocationSignature::Builder locations(zone, return_count, parameter_count);
MachineSignature::Builder types(zone, return_count, parameter_count);
// Add returns.
AddReturnLocations(&locations);
for (size_t i = 0; i < return_count; i++) {
types.AddReturn(kMachAnyTagged);
}
// All parameters to the runtime call go on the stack.
for (int i = 0; i < js_parameter_count; i++) {
locations.AddParam(stackloc(i - js_parameter_count));
types.AddParam(kMachAnyTagged);
}
// Add runtime function itself.
locations.AddParam(regloc(LinkageTraits::RuntimeCallFunctionReg()));
types.AddParam(kMachAnyTagged);
// Add runtime call argument count.
locations.AddParam(regloc(LinkageTraits::RuntimeCallArgCountReg()));
types.AddParam(kMachPtr);
// Add context.
locations.AddParam(regloc(LinkageTraits::ContextReg()));
types.AddParam(kMachAnyTagged);
CallDescriptor::Flags flags = Linkage::NeedsFrameState(function_id)
? CallDescriptor::kNeedsFrameState
: CallDescriptor::kNoFlags;
// The target for runtime calls is a code object.
MachineType target_type = kMachAnyTagged;
LinkageLocation target_loc = LinkageLocation::AnyRegister();
return new (zone) CallDescriptor( // --
CallDescriptor::kCallCodeObject, // kind
target_type, // target MachineType
target_loc, // target location
types.Build(), // machine_sig
locations.Build(), // location_sig
js_parameter_count, // js_parameter_count
properties, // properties
kNoCalleeSaved, // callee-saved
flags, // flags
function->name); // debug name
}
// TODO(turbofan): cache call descriptors for code stub calls.
static CallDescriptor* GetStubCallDescriptor(
Zone* zone, const CallInterfaceDescriptor& descriptor,
int stack_parameter_count, CallDescriptor::Flags flags,
Operator::Properties properties) {
const int register_parameter_count =
descriptor.GetEnvironmentParameterCount();
const int js_parameter_count =
register_parameter_count + stack_parameter_count;
const int context_count = 1;
const size_t return_count = 1;
const size_t parameter_count =
static_cast<size_t>(js_parameter_count + context_count);
LocationSignature::Builder locations(zone, return_count, parameter_count);
MachineSignature::Builder types(zone, return_count, parameter_count);
// Add return location.
AddReturnLocations(&locations);
types.AddReturn(kMachAnyTagged);
// Add parameters in registers and on the stack.
for (int i = 0; i < js_parameter_count; i++) {
if (i < register_parameter_count) {
// The first parameters go in registers.
Register reg = descriptor.GetEnvironmentParameterRegister(i);
locations.AddParam(regloc(reg));
} else {
// The rest of the parameters go on the stack.
int stack_slot = i - register_parameter_count - stack_parameter_count;
locations.AddParam(stackloc(stack_slot));
}
types.AddParam(kMachAnyTagged);
}
// Add context.
locations.AddParam(regloc(LinkageTraits::ContextReg()));
types.AddParam(kMachAnyTagged);
// The target for stub calls is a code object.
MachineType target_type = kMachAnyTagged;
LinkageLocation target_loc = LinkageLocation::AnyRegister();
return new (zone) CallDescriptor( // --
CallDescriptor::kCallCodeObject, // kind
target_type, // target MachineType
target_loc, // target location
types.Build(), // machine_sig
locations.Build(), // location_sig
js_parameter_count, // js_parameter_count
properties, // properties
kNoCalleeSaved, // callee-saved registers
flags, // flags
descriptor.DebugName(zone->isolate()));
}
static CallDescriptor* GetSimplifiedCDescriptor(Zone* zone,
MachineSignature* msig) {
LocationSignature::Builder locations(zone, msig->return_count(),
msig->parameter_count());
// Add return location(s).
AddReturnLocations(&locations);
// Add register and/or stack parameter(s).
const int parameter_count = static_cast<int>(msig->parameter_count());
for (int i = 0; i < parameter_count; i++) {
if (i < LinkageTraits::CRegisterParametersLength()) {
locations.AddParam(regloc(LinkageTraits::CRegisterParameter(i)));
} else {
locations.AddParam(stackloc(-1 - i));
}
}
// The target for C calls is always an address (i.e. machine pointer).
MachineType target_type = kMachPtr;
LinkageLocation target_loc = LinkageLocation::AnyRegister();
return new (zone) CallDescriptor( // --
CallDescriptor::kCallAddress, // kind
target_type, // target MachineType
target_loc, // target location
msig, // machine_sig
locations.Build(), // location_sig
0, // js_parameter_count
Operator::kNoProperties, // properties
LinkageTraits::CCalleeSaveRegisters(), CallDescriptor::kNoFlags,
"c-call");
}
static LinkageLocation regloc(Register reg) {
return LinkageLocation(Register::ToAllocationIndex(reg));
}
static LinkageLocation stackloc(int i) {
DCHECK_LT(i, 0);
return LinkageLocation(i);
}
};
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_COMPILER_LINKAGE_IMPL_H_