1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "src/code-stubs.h"
6 #include "src/compiler.h"
7 #include "src/compiler/common-operator.h"
8 #include "src/compiler/linkage.h"
9 #include "src/compiler/node.h"
10 #include "src/compiler/pipeline.h"
11 #include "src/scopes.h"
18 std::ostream& operator<<(std::ostream& os, const CallDescriptor::Kind& k) {
20 case CallDescriptor::kCallCodeObject:
23 case CallDescriptor::kCallJSFunction:
26 case CallDescriptor::kCallAddress:
29 case CallDescriptor::kInterpreterDispatch:
30 os << "InterpreterDispatch";
37 std::ostream& operator<<(std::ostream& os, const CallDescriptor& d) {
38 // TODO(svenpanne) Output properties etc. and be less cryptic.
39 return os << d.kind() << ":" << d.debug_name() << ":r" << d.ReturnCount()
40 << "j" << d.JSParameterCount() << "i" << d.InputCount() << "f"
41 << d.FrameStateCount() << "t" << d.SupportsTailCalls();
45 bool CallDescriptor::HasSameReturnLocationsAs(
46 const CallDescriptor* other) const {
47 if (ReturnCount() != other->ReturnCount()) return false;
48 for (size_t i = 0; i < ReturnCount(); ++i) {
49 if (GetReturnLocation(i) != other->GetReturnLocation(i)) return false;
55 bool CallDescriptor::CanTailCall(const Node* node) const {
56 // Determine the number of stack parameters passed in
57 size_t stack_params = 0;
58 for (size_t i = 0; i < InputCount(); ++i) {
59 if (!GetInputLocation(i).IsRegister()) {
63 // Ensure the input linkage contains the stack parameters in the right order
64 size_t current_stack_param = 0;
65 for (size_t i = 0; i < InputCount(); ++i) {
66 if (!GetInputLocation(i).IsRegister()) {
67 if (GetInputLocation(i) != LinkageLocation::ForCallerFrameSlot(
68 static_cast<int>(current_stack_param) -
69 static_cast<int>(stack_params))) {
72 ++current_stack_param;
75 // Tail calling is currently allowed if return locations match and all
76 // parameters are either in registers or on the stack but match exactly in
77 // number and content.
78 CallDescriptor const* other = OpParameter<CallDescriptor const*>(node);
79 if (!HasSameReturnLocationsAs(other)) return false;
80 size_t current_input = 0;
81 size_t other_input = 0;
83 if (other_input >= other->InputCount()) {
84 while (current_input < InputCount()) {
85 if (!GetInputLocation(current_input).IsRegister()) {
92 if (current_input >= InputCount()) {
93 while (other_input < other->InputCount()) {
94 if (!other->GetInputLocation(other_input).IsRegister()) {
101 if (GetInputLocation(current_input).IsRegister()) {
105 if (other->GetInputLocation(other_input).IsRegister()) {
109 if (GetInputLocation(current_input) !=
110 other->GetInputLocation(other_input)) {
113 Node* input = node->InputAt(static_cast<int>(other_input));
114 if (input->opcode() != IrOpcode::kParameter) {
117 // Make sure that the parameter input passed through to the tail call
118 // corresponds to the correct stack slot.
119 size_t param_index = ParameterIndexOf(input->op());
120 if (param_index != current_input - 1) {
131 CallDescriptor* Linkage::ComputeIncoming(Zone* zone, CompilationInfo* info) {
132 if (info->code_stub() != NULL) {
133 // Use the code stub interface descriptor.
134 CodeStub* stub = info->code_stub();
135 CallInterfaceDescriptor descriptor = stub->GetCallInterfaceDescriptor();
136 return GetStubCallDescriptor(
137 info->isolate(), zone, descriptor, stub->GetStackParameterCount(),
138 CallDescriptor::kNoFlags, Operator::kNoProperties);
140 if (info->function() != NULL) {
141 // If we already have the function literal, use the number of parameters
142 // plus the receiver.
143 return GetJSCallDescriptor(zone, info->is_osr(),
144 1 + info->function()->parameter_count(),
145 CallDescriptor::kNoFlags);
147 if (!info->closure().is_null()) {
148 // If we are compiling a JS function, use a JS call descriptor,
149 // plus the receiver.
150 SharedFunctionInfo* shared = info->closure()->shared();
151 return GetJSCallDescriptor(zone, info->is_osr(),
152 1 + shared->internal_formal_parameter_count(),
153 CallDescriptor::kNoFlags);
155 return NULL; // TODO(titzer): ?
159 FrameOffset Linkage::GetFrameOffset(int spill_slot, Frame* frame,
161 if (frame->GetSpillSlotCount() > 0 || incoming_->IsJSFunctionCall() ||
162 incoming_->kind() == CallDescriptor::kCallAddress) {
164 int register_save_area_size = frame->GetRegisterSaveAreaSize();
165 if (spill_slot >= 0) {
166 // Local or spill slot. Skip the frame pointer, function, and
167 // context in the fixed part of the frame.
169 -(spill_slot + 1) * kPointerSize - register_save_area_size + extra;
171 // Incoming parameter. Skip the return address.
172 offset = -(spill_slot + 1) * kPointerSize + kFPOnStackSize +
173 kPCOnStackSize + extra;
175 return FrameOffset::FromFramePointer(offset);
177 // No frame. Retrieve all parameters relative to stack pointer.
178 DCHECK(spill_slot < 0); // Must be a parameter.
179 int register_save_area_size = frame->GetRegisterSaveAreaSize();
180 int offset = register_save_area_size - (spill_slot + 1) * kPointerSize +
181 kPCOnStackSize + extra;
182 return FrameOffset::FromStackPointer(offset);
188 int Linkage::FrameStateInputCount(Runtime::FunctionId function) {
189 // Most runtime functions need a FrameState. A few chosen ones that we know
190 // not to call into arbitrary JavaScript, not to throw, and not to deoptimize
191 // are blacklisted here and can be called without a FrameState.
193 case Runtime::kAllocateInTargetSpace:
194 case Runtime::kDateField:
195 case Runtime::kFinalizeClassDefinition: // TODO(conradw): Is it safe?
196 case Runtime::kFinalizeClassDefinitionStrong: // TODO(conradw): Is it safe?
197 case Runtime::kDefineClassMethod: // TODO(jarin): Is it safe?
198 case Runtime::kDefineGetterPropertyUnchecked: // TODO(jarin): Is it safe?
199 case Runtime::kDefineSetterPropertyUnchecked: // TODO(jarin): Is it safe?
200 case Runtime::kForInDone:
201 case Runtime::kForInStep:
202 case Runtime::kGetOriginalConstructor:
203 case Runtime::kNewArguments:
204 case Runtime::kNewClosure:
205 case Runtime::kNewFunctionContext:
206 case Runtime::kNewRestParamSlow:
207 case Runtime::kPushBlockContext:
208 case Runtime::kPushCatchContext:
209 case Runtime::kReThrow:
210 case Runtime::kStringCompareRT:
211 case Runtime::kStringEquals:
212 case Runtime::kToFastProperties: // TODO(jarin): Is it safe?
213 case Runtime::kTraceEnter:
214 case Runtime::kTraceExit:
216 case Runtime::kInlineArguments:
217 case Runtime::kInlineCallFunction:
218 case Runtime::kInlineDefaultConstructorCallSuper:
219 case Runtime::kInlineGetCallerJSFunction:
220 case Runtime::kInlineGetPrototype:
221 case Runtime::kInlineRegExpExec:
223 case Runtime::kInlineDeoptimizeNow:
224 case Runtime::kInlineThrowNotDateError:
230 // Most inlined runtime functions (except the ones listed above) can be called
231 // without a FrameState or will be lowered by JSIntrinsicLowering internally.
232 const Runtime::Function* const f = Runtime::FunctionForId(function);
233 if (f->intrinsic_type == Runtime::IntrinsicType::INLINE) return 0;
239 bool CallDescriptor::UsesOnlyRegisters() const {
240 for (size_t i = 0; i < InputCount(); ++i) {
241 if (!GetInputLocation(i).IsRegister()) return false;
243 for (size_t i = 0; i < ReturnCount(); ++i) {
244 if (!GetReturnLocation(i).IsRegister()) return false;
250 //==============================================================================
251 // Provide unimplemented methods on unsupported architectures, to at least link.
252 //==============================================================================
253 #if !V8_TURBOFAN_BACKEND
254 CallDescriptor* Linkage::GetJSCallDescriptor(Zone* zone, bool is_osr,
256 CallDescriptor::Flags flags) {
262 LinkageLocation Linkage::GetOsrValueLocation(int index) const {
264 return LinkageLocation(-1); // Dummy value
268 CallDescriptor* Linkage::GetRuntimeCallDescriptor(
269 Zone* zone, Runtime::FunctionId function, int parameter_count,
270 Operator::Properties properties) {
276 CallDescriptor* Linkage::GetStubCallDescriptor(
277 Isolate* isolate, Zone* zone, const CallInterfaceDescriptor& descriptor,
278 int stack_parameter_count, CallDescriptor::Flags flags,
279 Operator::Properties properties, MachineType return_type) {
285 #endif // !V8_TURBOFAN_BACKEND
286 } // namespace compiler
287 } // namespace internal