summaryrefslogtreecommitdiff
path: root/deps/v8/src/compiler/linkage.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/compiler/linkage.cc')
-rw-r--r--deps/v8/src/compiler/linkage.cc360
1 files changed, 303 insertions, 57 deletions
diff --git a/deps/v8/src/compiler/linkage.cc b/deps/v8/src/compiler/linkage.cc
index 6ef014246d..2bbedaceb2 100644
--- a/deps/v8/src/compiler/linkage.cc
+++ b/deps/v8/src/compiler/linkage.cc
@@ -5,8 +5,10 @@
#include "src/code-stubs.h"
#include "src/compiler.h"
#include "src/compiler/common-operator.h"
+#include "src/compiler/frame.h"
#include "src/compiler/linkage.h"
#include "src/compiler/node.h"
+#include "src/compiler/osr.h"
#include "src/compiler/pipeline.h"
#include "src/scopes.h"
@@ -14,6 +16,41 @@ namespace v8 {
namespace internal {
namespace compiler {
+namespace {
+LinkageLocation regloc(Register reg) {
+ return LinkageLocation::ForRegister(Register::ToAllocationIndex(reg));
+}
+
+
+MachineType reptyp(Representation representation) {
+ switch (representation.kind()) {
+ case Representation::kInteger8:
+ return kMachInt8;
+ case Representation::kUInteger8:
+ return kMachUint8;
+ case Representation::kInteger16:
+ return kMachInt16;
+ case Representation::kUInteger16:
+ return kMachUint16;
+ case Representation::kInteger32:
+ return kMachInt32;
+ case Representation::kSmi:
+ case Representation::kTagged:
+ case Representation::kHeapObject:
+ return kMachAnyTagged;
+ case Representation::kDouble:
+ return kMachFloat64;
+ case Representation::kExternal:
+ return kMachPtr;
+ case Representation::kNone:
+ case Representation::kNumRepresentations:
+ break;
+ }
+ UNREACHABLE();
+ return kMachNone;
+}
+} // namespace
+
std::ostream& operator<<(std::ostream& os, const CallDescriptor::Kind& k) {
switch (k) {
@@ -34,7 +71,7 @@ std::ostream& operator<<(std::ostream& os, const CallDescriptor::Kind& k) {
std::ostream& operator<<(std::ostream& os, const CallDescriptor& d) {
// TODO(svenpanne) Output properties etc. and be less cryptic.
return os << d.kind() << ":" << d.debug_name() << ":r" << d.ReturnCount()
- << "j" << d.JSParameterCount() << "i" << d.InputCount() << "f"
+ << "s" << d.StackParameterCount() << "i" << d.InputCount() << "f"
<< d.FrameStateCount() << "t" << d.SupportsTailCalls();
}
@@ -50,6 +87,25 @@ bool CallDescriptor::HasSameReturnLocationsAs(
bool CallDescriptor::CanTailCall(const Node* node) const {
+ // Determine the number of stack parameters passed in
+ size_t stack_params = 0;
+ for (size_t i = 0; i < InputCount(); ++i) {
+ if (!GetInputLocation(i).IsRegister()) {
+ ++stack_params;
+ }
+ }
+ // Ensure the input linkage contains the stack parameters in the right order
+ size_t current_stack_param = 0;
+ for (size_t i = 0; i < InputCount(); ++i) {
+ if (!GetInputLocation(i).IsRegister()) {
+ if (GetInputLocation(i) != LinkageLocation::ForCallerFrameSlot(
+ static_cast<int>(current_stack_param) -
+ static_cast<int>(stack_params))) {
+ return false;
+ }
+ ++current_stack_param;
+ }
+ }
// Tail calling is currently allowed if return locations match and all
// parameters are either in registers or on the stack but match exactly in
// number and content.
@@ -57,11 +113,10 @@ bool CallDescriptor::CanTailCall(const Node* node) const {
if (!HasSameReturnLocationsAs(other)) return false;
size_t current_input = 0;
size_t other_input = 0;
- size_t stack_parameter = 0;
while (true) {
if (other_input >= other->InputCount()) {
- while (current_input <= InputCount()) {
- if (!GetInputLocation(current_input).is_register()) {
+ while (current_input < InputCount()) {
+ if (!GetInputLocation(current_input).IsRegister()) {
return false;
}
++current_input;
@@ -70,18 +125,18 @@ bool CallDescriptor::CanTailCall(const Node* node) const {
}
if (current_input >= InputCount()) {
while (other_input < other->InputCount()) {
- if (!other->GetInputLocation(other_input).is_register()) {
+ if (!other->GetInputLocation(other_input).IsRegister()) {
return false;
}
++other_input;
}
return true;
}
- if (GetInputLocation(current_input).is_register()) {
+ if (GetInputLocation(current_input).IsRegister()) {
++current_input;
continue;
}
- if (other->GetInputLocation(other_input).is_register()) {
+ if (other->GetInputLocation(other_input).IsRegister()) {
++other_input;
continue;
}
@@ -93,11 +148,12 @@ bool CallDescriptor::CanTailCall(const Node* node) const {
if (input->opcode() != IrOpcode::kParameter) {
return false;
}
+ // Make sure that the parameter input passed through to the tail call
+ // corresponds to the correct stack slot.
size_t param_index = ParameterIndexOf(input->op());
- if (param_index != stack_parameter) {
+ if (param_index != current_input - 1) {
return false;
}
- ++stack_parameter;
++current_input;
++other_input;
}
@@ -115,11 +171,11 @@ CallDescriptor* Linkage::ComputeIncoming(Zone* zone, CompilationInfo* info) {
info->isolate(), zone, descriptor, stub->GetStackParameterCount(),
CallDescriptor::kNoFlags, Operator::kNoProperties);
}
- if (info->function() != NULL) {
+ if (info->has_literal()) {
// If we already have the function literal, use the number of parameters
// plus the receiver.
return GetJSCallDescriptor(zone, info->is_osr(),
- 1 + info->function()->parameter_count(),
+ 1 + info->literal()->parameter_count(),
CallDescriptor::kNoFlags);
}
if (!info->closure().is_null()) {
@@ -134,30 +190,22 @@ CallDescriptor* Linkage::ComputeIncoming(Zone* zone, CompilationInfo* info) {
}
-FrameOffset Linkage::GetFrameOffset(int spill_slot, Frame* frame,
- int extra) const {
- if (frame->GetSpillSlotCount() > 0 || incoming_->IsJSFunctionCall() ||
- incoming_->kind() == CallDescriptor::kCallAddress) {
- int offset;
- int register_save_area_size = frame->GetRegisterSaveAreaSize();
- if (spill_slot >= 0) {
- // Local or spill slot. Skip the frame pointer, function, and
- // context in the fixed part of the frame.
- offset =
- -(spill_slot + 1) * kPointerSize - register_save_area_size + extra;
- } else {
- // Incoming parameter. Skip the return address.
- offset = -(spill_slot + 1) * kPointerSize + kFPOnStackSize +
- kPCOnStackSize + extra;
- }
+FrameOffset Linkage::GetFrameOffset(int spill_slot, Frame* frame) const {
+ bool has_frame = frame->GetSpillSlotCount() > 0 ||
+ incoming_->IsJSFunctionCall() ||
+ incoming_->kind() == CallDescriptor::kCallAddress;
+ const int offset =
+ (StandardFrameConstants::kFixedSlotCountAboveFp - spill_slot - 1) *
+ kPointerSize;
+ if (has_frame) {
return FrameOffset::FromFramePointer(offset);
} else {
// No frame. Retrieve all parameters relative to stack pointer.
DCHECK(spill_slot < 0); // Must be a parameter.
- int register_save_area_size = frame->GetRegisterSaveAreaSize();
- int offset = register_save_area_size - (spill_slot + 1) * kPointerSize +
- kPCOnStackSize + extra;
- return FrameOffset::FromStackPointer(offset);
+ int offsetSpToFp =
+ kPointerSize * (StandardFrameConstants::kFixedSlotCountAboveFp -
+ frame->GetTotalFrameSlotCount());
+ return FrameOffset::FromStackPointer(offset - offsetSpToFp);
}
}
@@ -170,6 +218,7 @@ int Linkage::FrameStateInputCount(Runtime::FunctionId function) {
switch (function) {
case Runtime::kAllocateInTargetSpace:
case Runtime::kDateField:
+ case Runtime::kFinalizeClassDefinition: // TODO(conradw): Is it safe?
case Runtime::kDefineClassMethod: // TODO(jarin): Is it safe?
case Runtime::kDefineGetterPropertyUnchecked: // TODO(jarin): Is it safe?
case Runtime::kDefineSetterPropertyUnchecked: // TODO(jarin): Is it safe?
@@ -183,7 +232,7 @@ int Linkage::FrameStateInputCount(Runtime::FunctionId function) {
case Runtime::kPushBlockContext:
case Runtime::kPushCatchContext:
case Runtime::kReThrow:
- case Runtime::kStringCompareRT:
+ case Runtime::kStringCompare:
case Runtime::kStringEquals:
case Runtime::kToFastProperties: // TODO(jarin): Is it safe?
case Runtime::kTraceEnter:
@@ -191,9 +240,11 @@ int Linkage::FrameStateInputCount(Runtime::FunctionId function) {
return 0;
case Runtime::kInlineArguments:
case Runtime::kInlineCallFunction:
+ case Runtime::kInlineDefaultConstructorCallSuper:
case Runtime::kInlineGetCallerJSFunction:
case Runtime::kInlineGetPrototype:
case Runtime::kInlineRegExpExec:
+ case Runtime::kInlineToObject:
return 1;
case Runtime::kInlineDeoptimizeNow:
case Runtime::kInlineThrowNotDateError:
@@ -213,56 +264,251 @@ int Linkage::FrameStateInputCount(Runtime::FunctionId function) {
bool CallDescriptor::UsesOnlyRegisters() const {
for (size_t i = 0; i < InputCount(); ++i) {
- if (!GetInputLocation(i).is_register()) return false;
+ if (!GetInputLocation(i).IsRegister()) return false;
}
for (size_t i = 0; i < ReturnCount(); ++i) {
- if (!GetReturnLocation(i).is_register()) return false;
+ if (!GetReturnLocation(i).IsRegister()) return false;
}
return true;
}
-//==============================================================================
-// Provide unimplemented methods on unsupported architectures, to at least link.
-//==============================================================================
-#if !V8_TURBOFAN_BACKEND
+CallDescriptor* Linkage::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.
+ if (locations.return_count_ > 0) {
+ locations.AddReturn(regloc(kReturnRegister0));
+ }
+ if (locations.return_count_ > 1) {
+ locations.AddReturn(regloc(kReturnRegister1));
+ }
+ 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(
+ LinkageLocation::ForCallerFrameSlot(i - js_parameter_count));
+ types.AddParam(kMachAnyTagged);
+ }
+ // Add runtime function itself.
+ locations.AddParam(regloc(kRuntimeCallFunctionRegister));
+ types.AddParam(kMachAnyTagged);
+
+ // Add runtime call argument count.
+ locations.AddParam(regloc(kRuntimeCallArgCountRegister));
+ types.AddParam(kMachPtr);
+
+ // Add context.
+ locations.AddParam(regloc(kContextRegister));
+ types.AddParam(kMachAnyTagged);
+
+ CallDescriptor::Flags flags = Linkage::FrameStateInputCount(function_id) > 0
+ ? CallDescriptor::kNeedsFrameState
+ : CallDescriptor::kNoFlags;
+
+ // The target for runtime calls is a code object.
+ MachineType target_type = kMachAnyTagged;
+ LinkageLocation target_loc = LinkageLocation::ForAnyRegister();
+ 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, // stack_parameter_count
+ properties, // properties
+ kNoCalleeSaved, // callee-saved
+ kNoCalleeSaved, // callee-saved fp
+ flags, // flags
+ function->name); // debug name
+}
+
+
CallDescriptor* Linkage::GetJSCallDescriptor(Zone* zone, bool is_osr,
- int parameter_count,
+ int js_parameter_count,
CallDescriptor::Flags flags) {
- UNIMPLEMENTED();
- return NULL;
-}
+ 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);
-LinkageLocation Linkage::GetOsrValueLocation(int index) const {
- UNIMPLEMENTED();
- return LinkageLocation(-1); // Dummy value
+ // All JS calls have exactly one return value.
+ locations.AddReturn(regloc(kReturnRegister0));
+ 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(LinkageLocation::ForCallerFrameSlot(spill_slot_index));
+ types.AddParam(kMachAnyTagged);
+ }
+ // Add context.
+ locations.AddParam(regloc(kContextRegister));
+ types.AddParam(kMachAnyTagged);
+
+ // The target for JS function calls is the JSFunction object.
+ MachineType target_type = kMachAnyTagged;
+ // TODO(titzer): When entering into an OSR function from unoptimized code,
+ // the JSFunction is not in a register, but it is on the stack in an
+ // unaddressable spill slot. We hack this in the OSR prologue. Fix.
+ LinkageLocation target_loc = regloc(kJSFunctionRegister);
+ 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, // stack_parameter_count
+ Operator::kNoProperties, // properties
+ kNoCalleeSaved, // callee-saved
+ kNoCalleeSaved, // callee-saved fp
+ CallDescriptor::kCanUseRoots | // flags
+ flags, // flags
+ "js-call");
}
-CallDescriptor* Linkage::GetRuntimeCallDescriptor(
- Zone* zone, Runtime::FunctionId function, int parameter_count,
- Operator::Properties properties) {
- UNIMPLEMENTED();
- return NULL;
+CallDescriptor* Linkage::GetInterpreterDispatchDescriptor(Zone* zone) {
+ MachineSignature::Builder types(zone, 0, 5);
+ LocationSignature::Builder locations(zone, 0, 5);
+
+ // Add registers for fixed parameters passed via interpreter dispatch.
+ STATIC_ASSERT(0 == Linkage::kInterpreterAccumulatorParameter);
+ types.AddParam(kMachAnyTagged);
+ locations.AddParam(regloc(kInterpreterAccumulatorRegister));
+
+ STATIC_ASSERT(1 == Linkage::kInterpreterRegisterFileParameter);
+ types.AddParam(kMachPtr);
+ locations.AddParam(regloc(kInterpreterRegisterFileRegister));
+
+ STATIC_ASSERT(2 == Linkage::kInterpreterBytecodeOffsetParameter);
+ types.AddParam(kMachIntPtr);
+ locations.AddParam(regloc(kInterpreterBytecodeOffsetRegister));
+
+ STATIC_ASSERT(3 == Linkage::kInterpreterBytecodeArrayParameter);
+ types.AddParam(kMachAnyTagged);
+ locations.AddParam(regloc(kInterpreterBytecodeArrayRegister));
+
+ STATIC_ASSERT(4 == Linkage::kInterpreterDispatchTableParameter);
+ types.AddParam(kMachPtr);
+ locations.AddParam(regloc(kInterpreterDispatchTableRegister));
+
+ LinkageLocation target_loc = LinkageLocation::ForAnyRegister();
+ return new (zone) CallDescriptor( // --
+ CallDescriptor::kCallCodeObject, // kind
+ kMachNone, // target MachineType
+ target_loc, // target location
+ types.Build(), // machine_sig
+ locations.Build(), // location_sig
+ 0, // stack_parameter_count
+ Operator::kNoProperties, // properties
+ kNoCalleeSaved, // callee-saved registers
+ kNoCalleeSaved, // callee-saved fp regs
+ CallDescriptor::kSupportsTailCalls | // flags
+ CallDescriptor::kCanUseRoots, // flags
+ "interpreter-dispatch");
}
+// TODO(all): Add support for return representations/locations to
+// CallInterfaceDescriptor.
+// TODO(turbofan): cache call descriptors for code stub calls.
CallDescriptor* Linkage::GetStubCallDescriptor(
Isolate* isolate, Zone* zone, const CallInterfaceDescriptor& descriptor,
int stack_parameter_count, CallDescriptor::Flags flags,
Operator::Properties properties, MachineType return_type) {
- UNIMPLEMENTED();
- return NULL;
+ const int register_parameter_count = descriptor.GetRegisterParameterCount();
+ 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.
+ locations.AddReturn(regloc(kReturnRegister0));
+ types.AddReturn(return_type);
+
+ // 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.GetRegisterParameter(i);
+ Representation rep =
+ RepresentationFromType(descriptor.GetParameterType(i));
+ locations.AddParam(regloc(reg));
+ types.AddParam(reptyp(rep));
+ } else {
+ // The rest of the parameters go on the stack.
+ int stack_slot = i - register_parameter_count - stack_parameter_count;
+ locations.AddParam(LinkageLocation::ForCallerFrameSlot(stack_slot));
+ types.AddParam(kMachAnyTagged);
+ }
+ }
+ // Add context.
+ locations.AddParam(regloc(kContextRegister));
+ types.AddParam(kMachAnyTagged);
+
+ // The target for stub calls is a code object.
+ MachineType target_type = kMachAnyTagged;
+ LinkageLocation target_loc = LinkageLocation::ForAnyRegister();
+ return new (zone) CallDescriptor( // --
+ CallDescriptor::kCallCodeObject, // kind
+ target_type, // target MachineType
+ target_loc, // target location
+ types.Build(), // machine_sig
+ locations.Build(), // location_sig
+ stack_parameter_count, // stack_parameter_count
+ properties, // properties
+ kNoCalleeSaved, // callee-saved registers
+ kNoCalleeSaved, // callee-saved fp
+ flags, // flags
+ descriptor.DebugName(isolate));
}
-CallDescriptor* Linkage::GetSimplifiedCDescriptor(Zone* zone,
- const MachineSignature* sig) {
- UNIMPLEMENTED();
- return NULL;
+LinkageLocation Linkage::GetOsrValueLocation(int index) const {
+ CHECK(incoming_->IsJSFunctionCall());
+ int parameter_count = static_cast<int>(incoming_->JSParameterCount() - 1);
+ int first_stack_slot = OsrHelper::FirstStackSlotIndex(parameter_count);
+
+ if (index == kOsrContextSpillSlotIndex) {
+ // Context. Use the parameter location of the context spill slot.
+ // Parameter (arity + 1) is special for the context of the function frame.
+ int context_index = 1 + 1 + parameter_count; // target + receiver + params
+ return incoming_->GetInputLocation(context_index);
+ } else if (index >= first_stack_slot) {
+ // Local variable stored in this (callee) stack.
+ int spill_index =
+ index - first_stack_slot + StandardFrameConstants::kFixedSlotCount;
+ return LinkageLocation::ForCalleeFrameSlot(spill_index);
+ } else {
+ // Parameter. Use the assigned location from the incoming call descriptor.
+ int parameter_index = 1 + index; // skip index 0, which is the target.
+ return incoming_->GetInputLocation(parameter_index);
+ }
}
-#endif // !V8_TURBOFAN_BACKEND
} // namespace compiler
} // namespace internal
} // namespace v8