c604909b8a3489010dae544b9cb8c4b71a0b28ee
[platform/upstream/v8.git] / src / compiler / linkage.cc
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.
4
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"
12
13 namespace v8 {
14 namespace internal {
15 namespace compiler {
16
17
18 std::ostream& operator<<(std::ostream& os, const CallDescriptor::Kind& k) {
19   switch (k) {
20     case CallDescriptor::kCallCodeObject:
21       os << "Code";
22       break;
23     case CallDescriptor::kCallJSFunction:
24       os << "JS";
25       break;
26     case CallDescriptor::kCallAddress:
27       os << "Addr";
28       break;
29     case CallDescriptor::kInterpreterDispatch:
30       os << "InterpreterDispatch";
31       break;
32   }
33   return os;
34 }
35
36
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();
42 }
43
44
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;
50   }
51   return true;
52 }
53
54
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()) {
60       ++stack_params;
61     }
62   }
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))) {
70         return false;
71       }
72       ++current_stack_param;
73     }
74   }
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;
82   while (true) {
83     if (other_input >= other->InputCount()) {
84       while (current_input < InputCount()) {
85         if (!GetInputLocation(current_input).IsRegister()) {
86           return false;
87         }
88         ++current_input;
89       }
90       return true;
91     }
92     if (current_input >= InputCount()) {
93       while (other_input < other->InputCount()) {
94         if (!other->GetInputLocation(other_input).IsRegister()) {
95           return false;
96         }
97         ++other_input;
98       }
99       return true;
100     }
101     if (GetInputLocation(current_input).IsRegister()) {
102       ++current_input;
103       continue;
104     }
105     if (other->GetInputLocation(other_input).IsRegister()) {
106       ++other_input;
107       continue;
108     }
109     if (GetInputLocation(current_input) !=
110         other->GetInputLocation(other_input)) {
111       return false;
112     }
113     Node* input = node->InputAt(static_cast<int>(other_input));
114     if (input->opcode() != IrOpcode::kParameter) {
115       return false;
116     }
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) {
121       return false;
122     }
123     ++current_input;
124     ++other_input;
125   }
126   UNREACHABLE();
127   return false;
128 }
129
130
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);
139   }
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);
146   }
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);
154   }
155   return NULL;  // TODO(titzer): ?
156 }
157
158
159 FrameOffset Linkage::GetFrameOffset(int spill_slot, Frame* frame,
160                                     int extra) const {
161   if (frame->GetSpillSlotCount() > 0 || incoming_->IsJSFunctionCall() ||
162       incoming_->kind() == CallDescriptor::kCallAddress) {
163     int offset;
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.
168       offset =
169           -(spill_slot + 1) * kPointerSize - register_save_area_size + extra;
170     } else {
171       // Incoming parameter. Skip the return address.
172       offset = -(spill_slot + 1) * kPointerSize + kFPOnStackSize +
173                kPCOnStackSize + extra;
174     }
175     return FrameOffset::FromFramePointer(offset);
176   } else {
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);
183   }
184 }
185
186
187 // static
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.
192   switch (function) {
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:
215       return 0;
216     case Runtime::kInlineArguments:
217     case Runtime::kInlineCallFunction:
218     case Runtime::kInlineDefaultConstructorCallSuper:
219     case Runtime::kInlineGetCallerJSFunction:
220     case Runtime::kInlineGetPrototype:
221     case Runtime::kInlineRegExpExec:
222       return 1;
223     case Runtime::kInlineDeoptimizeNow:
224     case Runtime::kInlineThrowNotDateError:
225       return 2;
226     default:
227       break;
228   }
229
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;
234
235   return 1;
236 }
237
238
239 bool CallDescriptor::UsesOnlyRegisters() const {
240   for (size_t i = 0; i < InputCount(); ++i) {
241     if (!GetInputLocation(i).IsRegister()) return false;
242   }
243   for (size_t i = 0; i < ReturnCount(); ++i) {
244     if (!GetReturnLocation(i).IsRegister()) return false;
245   }
246   return true;
247 }
248
249
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,
255                                              int parameter_count,
256                                              CallDescriptor::Flags flags) {
257   UNIMPLEMENTED();
258   return NULL;
259 }
260
261
262 LinkageLocation Linkage::GetOsrValueLocation(int index) const {
263   UNIMPLEMENTED();
264   return LinkageLocation(-1);  // Dummy value
265 }
266
267
268 CallDescriptor* Linkage::GetRuntimeCallDescriptor(
269     Zone* zone, Runtime::FunctionId function, int parameter_count,
270     Operator::Properties properties) {
271   UNIMPLEMENTED();
272   return NULL;
273 }
274
275
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) {
280   UNIMPLEMENTED();
281   return NULL;
282 }
283
284
285 #endif  // !V8_TURBOFAN_BACKEND
286 }  // namespace compiler
287 }  // namespace internal
288 }  // namespace v8