OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 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/compiler/ffi-compiler.h" | |
6 | |
7 #include "src/isolate-inl.h" | |
8 | |
9 #include "src/code-factory.h" | |
10 #include "src/compiler/access-builder.h" | |
11 #include "src/compiler/common-operator.h" | |
12 #include "src/compiler/graph-visualizer.h" | |
13 #include "src/compiler/graph.h" | |
14 #include "src/compiler/js-graph.h" | |
15 #include "src/compiler/js-operator.h" | |
16 #include "src/compiler/linkage.h" | |
17 #include "src/compiler/pipeline.h" | |
18 #include "src/factory.h" | |
19 #include "src/profiler/cpu-profiler.h" | |
20 | |
21 namespace v8 { | |
22 namespace internal { | |
23 namespace compiler { | |
24 | |
25 namespace { | |
26 | |
27 // TODO(ofrobots): duplicated from wasm-compiler.cc | |
28 static void MergeControlToEnd(JSGraph* jsgraph, Node* node) { | |
29 Graph* g = jsgraph->graph(); | |
30 if (g->end()) { | |
31 NodeProperties::MergeControlToEnd(g, jsgraph->common(), node); | |
32 } else { | |
33 g->SetEnd(g->NewNode(jsgraph->common()->End(1), node)); | |
34 } | |
35 } | |
36 | |
37 } // namespace | |
38 | |
39 FFIGraphBuilder::FFIGraphBuilder(Zone* zone, JSGraph* jsgraph) | |
40 : zone_(zone), | |
41 jsgraph_(jsgraph), | |
42 control_(nullptr), | |
43 effect_(nullptr), | |
44 cur_buffer_(def_buffer_), | |
45 cur_bufsize_(kDefaultBufferSize) { | |
46 DCHECK_NOT_NULL(jsgraph_); | |
47 } | |
48 | |
49 Node* FFIGraphBuilder::Start(unsigned params) { | |
50 Node* start = graph()->NewNode(jsgraph()->common()->Start(params)); | |
51 graph()->SetStart(start); | |
52 return start; | |
53 } | |
54 | |
55 Node* FFIGraphBuilder::BuildCCall(MachineSignature* sig, Node** args) { | |
56 const size_t params = sig->parameter_count(); | |
57 const size_t extra = 2; // effect and control inputs. | |
58 const size_t count = 1 + params + extra; | |
59 | |
60 // Reallocate the buffer to make space for extra inputs. | |
61 args = Realloc(args, 1 + params, count); | |
62 | |
63 // Add effect and control inputs. | |
64 args[params + 1] = *effect_; | |
65 args[params + 2] = *control_; | |
66 | |
67 CallDescriptor* desc = | |
68 Linkage::GetSimplifiedCDescriptor(jsgraph()->zone(), sig); | |
69 | |
70 const Operator* op = jsgraph()->common()->Call(desc); | |
71 Node* call = graph()->NewNode(op, static_cast<int>(count), args); | |
72 *effect_ = call; | |
73 return call; | |
74 } | |
75 | |
76 Node* FFIGraphBuilder::BuildChangeInt32ToTagged(Node* value) { | |
77 MachineOperatorBuilder* machine = jsgraph()->machine(); | |
78 CommonOperatorBuilder* common = jsgraph()->common(); | |
79 | |
80 if (machine->Is64()) { | |
81 return BuildChangeInt32ToSmi(value); | |
82 } | |
83 | |
84 Node* add = graph()->NewNode(machine->Int32AddWithOverflow(), value, value); | |
85 | |
86 Node* ovf = graph()->NewNode(common->Projection(1), add); | |
87 Node* branch = graph()->NewNode(common->Branch(BranchHint::kFalse), ovf, | |
88 graph()->start()); | |
89 | |
90 Node* if_true = graph()->NewNode(common->IfTrue(), branch); | |
91 Node* vtrue = BuildAllocateHeapNumberWithValue( | |
92 graph()->NewNode(machine->ChangeInt32ToFloat64(), value), if_true); | |
93 | |
94 Node* if_false = graph()->NewNode(common->IfFalse(), branch); | |
95 Node* vfalse = graph()->NewNode(common->Projection(0), add); | |
96 | |
97 Node* merge = graph()->NewNode(common->Merge(2), if_true, if_false); | |
98 Node* phi = graph()->NewNode(common->Phi(MachineRepresentation::kTagged, 2), | |
99 vtrue, vfalse, merge); | |
100 return phi; | |
101 } | |
102 | |
103 Node* FFIGraphBuilder::BuildChangeFloat64ToTagged(Node* value) { | |
104 MachineOperatorBuilder* machine = jsgraph()->machine(); | |
105 CommonOperatorBuilder* common = jsgraph()->common(); | |
106 | |
107 Node* value32 = graph()->NewNode(machine->RoundFloat64ToInt32(), value); | |
108 Node* check_same = graph()->NewNode( | |
109 machine->Float64Equal(), value, | |
110 graph()->NewNode(machine->ChangeInt32ToFloat64(), value32)); | |
111 Node* branch_same = | |
112 graph()->NewNode(common->Branch(), check_same, graph()->start()); | |
113 | |
114 Node* if_smi = graph()->NewNode(common->IfTrue(), branch_same); | |
115 Node* vsmi; | |
116 Node* if_box = graph()->NewNode(common->IfFalse(), branch_same); | |
117 Node* vbox; | |
118 | |
119 // We only need to check for -0 if the {value} can potentially contain -0. | |
120 Node* check_zero = graph()->NewNode(machine->Word32Equal(), value32, | |
121 jsgraph()->Int32Constant(0)); | |
122 Node* branch_zero = | |
123 graph()->NewNode(common->Branch(BranchHint::kFalse), check_zero, if_smi); | |
124 | |
125 Node* if_zero = graph()->NewNode(common->IfTrue(), branch_zero); | |
126 Node* if_notzero = graph()->NewNode(common->IfFalse(), branch_zero); | |
127 | |
128 // In case of 0, we need to check the high bits for the IEEE -0 pattern. | |
129 Node* check_negative = graph()->NewNode( | |
130 machine->Int32LessThan(), | |
131 graph()->NewNode(machine->Float64ExtractHighWord32(), value), | |
132 jsgraph()->Int32Constant(0)); | |
133 Node* branch_negative = graph()->NewNode(common->Branch(BranchHint::kFalse), | |
134 check_negative, if_zero); | |
135 | |
136 Node* if_negative = graph()->NewNode(common->IfTrue(), branch_negative); | |
137 Node* if_notnegative = graph()->NewNode(common->IfFalse(), branch_negative); | |
138 | |
139 // We need to create a box for negative 0. | |
140 if_smi = graph()->NewNode(common->Merge(2), if_notzero, if_notnegative); | |
141 if_box = graph()->NewNode(common->Merge(2), if_box, if_negative); | |
142 | |
143 // On 64-bit machines we can just wrap the 32-bit integer in a smi, for 32-bit | |
144 // machines we need to deal with potential overflow and fallback to boxing. | |
145 if (machine->Is64()) { | |
146 vsmi = BuildChangeInt32ToSmi(value32); | |
147 } else { | |
148 Node* smi_tag = | |
149 graph()->NewNode(machine->Int32AddWithOverflow(), value32, value32); | |
150 | |
151 Node* check_ovf = graph()->NewNode(common->Projection(1), smi_tag); | |
152 Node* branch_ovf = | |
153 graph()->NewNode(common->Branch(BranchHint::kFalse), check_ovf, if_smi); | |
154 | |
155 Node* if_ovf = graph()->NewNode(common->IfTrue(), branch_ovf); | |
156 if_box = graph()->NewNode(common->Merge(2), if_ovf, if_box); | |
157 | |
158 if_smi = graph()->NewNode(common->IfFalse(), branch_ovf); | |
159 vsmi = graph()->NewNode(common->Projection(0), smi_tag); | |
160 } | |
161 | |
162 // Allocate the box for the {value}. | |
163 vbox = BuildAllocateHeapNumberWithValue(value, if_box); | |
164 | |
165 Node* control = graph()->NewNode(common->Merge(2), if_smi, if_box); | |
166 value = graph()->NewNode(common->Phi(MachineRepresentation::kTagged, 2), vsmi, | |
167 vbox, control); | |
168 return value; | |
169 } | |
170 | |
171 Node* FFIGraphBuilder::ToJS(Node* node, Node* context, MachineType type) { | |
172 switch (type.representation()) { | |
173 case MachineRepresentation::kWord32: | |
174 return BuildChangeInt32ToTagged(node); | |
175 case MachineRepresentation::kWord64: | |
176 // TODO(titzer): i64->JS has no good solution right now. Using lower 32 | |
177 // bits. | |
178 if (jsgraph()->machine()->Is64()) { | |
179 // On 32 bit platforms we do not have to do the truncation because the | |
180 // node we get in as a parameter only contains the low word anyways. | |
181 node = graph()->NewNode(jsgraph()->machine()->TruncateInt64ToInt32(), | |
182 node); | |
183 } | |
184 return BuildChangeInt32ToTagged(node); | |
185 case MachineRepresentation::kFloat32: | |
186 node = graph()->NewNode(jsgraph()->machine()->ChangeFloat32ToFloat64(), | |
187 node); | |
188 return BuildChangeFloat64ToTagged(node); | |
189 case MachineRepresentation::kFloat64: | |
190 return BuildChangeFloat64ToTagged(node); | |
191 default: | |
192 UNREACHABLE(); | |
193 return nullptr; | |
194 } | |
195 } | |
196 | |
197 Node* FFIGraphBuilder::BuildJavaScriptToNumber(Node* node, Node* context, | |
198 Node* effect, Node* control) { | |
199 Callable callable = CodeFactory::ToNumber(jsgraph()->isolate()); | |
200 CallDescriptor* desc = Linkage::GetStubCallDescriptor( | |
201 jsgraph()->isolate(), jsgraph()->zone(), callable.descriptor(), 0, | |
202 CallDescriptor::kNoFlags, Operator::kNoProperties); | |
203 Node* stub_code = jsgraph()->HeapConstant(callable.code()); | |
204 | |
205 Node* result = graph()->NewNode(jsgraph()->common()->Call(desc), stub_code, | |
206 node, context, effect, control); | |
207 | |
208 *control_ = result; | |
209 *effect_ = result; | |
210 | |
211 return result; | |
212 } | |
213 | |
214 static bool CanCover(Node* value, IrOpcode::Value opcode) { | |
Benedikt Meurer
2016/06/21 03:26:01
You don't need this helper (see below).
ofrobots
2016/06/23 01:02:51
Acknowledged.
| |
215 if (value->opcode() != opcode) return false; | |
216 bool first = true; | |
217 for (Edge const edge : value->use_edges()) { | |
218 if (NodeProperties::IsControlEdge(edge)) continue; | |
219 if (NodeProperties::IsEffectEdge(edge)) continue; | |
220 DCHECK(NodeProperties::IsValueEdge(edge)); | |
221 if (!first) return false; | |
222 first = false; | |
223 } | |
224 return true; | |
225 } | |
226 | |
227 Node* FFIGraphBuilder::BuildChangeTaggedToInt32(Node* value) { | |
228 CommonOperatorBuilder* common = jsgraph()->common(); | |
229 | |
230 Node* check = BuildTestNotSmi(value); | |
231 Node* branch = graph()->NewNode(common->Branch(BranchHint::kFalse), check, | |
232 graph()->start()); | |
233 | |
234 Node* if_smi = graph()->NewNode(common->IfFalse(), branch); | |
235 Node* vfrom_smi = BuildChangeSmiToInt32(value); | |
236 | |
237 // TODO(ofrobots): the not_smi path is too ugly and slow at the moment | |
238 Node* if_not_smi = graph()->NewNode(common->IfTrue(), branch); | |
239 Node* vfloat = BuildChangeTaggedToFloat64(value); | |
240 Node* vnot_smi = | |
241 graph()->NewNode(jsgraph()->machine()->TruncateFloat64ToWord32(), vfloat); | |
242 | |
243 Node* merge = graph()->NewNode(common->Merge(2), if_not_smi, if_smi); | |
244 Node* phi = graph()->NewNode(common->Phi(MachineRepresentation::kWord32, 2), | |
245 vnot_smi, vfrom_smi, merge); | |
246 return phi; | |
247 } | |
248 | |
249 Node* FFIGraphBuilder::BuildChangeTaggedToFloat64(Node* value) { | |
250 MachineOperatorBuilder* machine = jsgraph()->machine(); | |
251 CommonOperatorBuilder* common = jsgraph()->common(); | |
252 | |
253 if (CanCover(value, IrOpcode::kJSToNumber)) { | |
Benedikt Meurer
2016/06/21 03:26:01
You don't need this magic. It will never trigger a
ofrobots
2016/06/23 01:02:51
Acknowledged.
| |
254 // ChangeTaggedToFloat64(JSToNumber(x)) => | |
255 // if IsSmi(x) then ChangeSmiToFloat64(x) | |
256 // else let y = JSToNumber(x) in | |
257 // if IsSmi(y) then ChangeSmiToFloat64(y) | |
258 // else BuildLoadHeapNumberValue(y) | |
259 Node* object = NodeProperties::GetValueInput(value, 0); | |
260 Node* context = NodeProperties::GetContextInput(value); | |
261 Node* frame_state = NodeProperties::GetFrameStateInput(value, 0); | |
262 Node* effect = NodeProperties::GetEffectInput(value); | |
263 Node* control = NodeProperties::GetControlInput(value); | |
264 | |
265 const Operator* merge_op = common->Merge(2); | |
266 const Operator* ephi_op = common->EffectPhi(2); | |
267 const Operator* phi_op = common->Phi(MachineRepresentation::kFloat64, 2); | |
268 | |
269 Node* check1 = BuildTestNotSmi(object); | |
270 Node* branch1 = | |
271 graph()->NewNode(common->Branch(BranchHint::kFalse), check1, control); | |
272 | |
273 Node* if_true1 = graph()->NewNode(common->IfTrue(), branch1); | |
274 Node* vtrue1 = graph()->NewNode(value->op(), object, context, frame_state, | |
275 effect, if_true1); | |
276 Node* etrue1 = vtrue1; | |
277 | |
278 Node* check2 = BuildTestNotSmi(vtrue1); | |
279 Node* branch2 = graph()->NewNode(common->Branch(), check2, if_true1); | |
280 | |
281 Node* if_true2 = graph()->NewNode(common->IfTrue(), branch2); | |
282 Node* vtrue2 = BuildLoadHeapNumberValue(vtrue1, if_true2); | |
283 | |
284 Node* if_false2 = graph()->NewNode(common->IfFalse(), branch2); | |
285 Node* vfalse2 = BuildChangeSmiToFloat64(vtrue1); | |
286 | |
287 if_true1 = graph()->NewNode(merge_op, if_true2, if_false2); | |
288 vtrue1 = graph()->NewNode(phi_op, vtrue2, vfalse2, if_true1); | |
289 | |
290 Node* if_false1 = graph()->NewNode(common->IfFalse(), branch1); | |
291 Node* vfalse1 = BuildChangeSmiToFloat64(object); | |
292 Node* efalse1 = effect; | |
293 | |
294 Node* merge1 = graph()->NewNode(merge_op, if_true1, if_false1); | |
295 Node* ephi1 = graph()->NewNode(ephi_op, etrue1, efalse1, merge1); | |
296 Node* phi1 = graph()->NewNode(phi_op, vtrue1, vfalse1, merge1); | |
297 | |
298 // Wire the new diamond into the graph, {JSToNumber} can still throw. | |
299 NodeProperties::ReplaceUses(value, phi1, ephi1, etrue1, etrue1); | |
300 | |
301 // TODO(mstarzinger): This iteration cuts out the IfSuccess projection from | |
302 // the node and places it inside the diamond. Come up with a helper method! | |
303 for (Node* use : etrue1->uses()) { | |
304 if (use->opcode() == IrOpcode::kIfSuccess) { | |
305 use->ReplaceUses(merge1); | |
306 NodeProperties::ReplaceControlInput(branch2, use); | |
307 } | |
308 } | |
309 return phi1; | |
310 } | |
311 | |
312 Node* check = BuildTestNotSmi(value); | |
313 Node* branch = graph()->NewNode(common->Branch(BranchHint::kFalse), check, | |
314 graph()->start()); | |
315 | |
316 Node* if_not_smi = graph()->NewNode(common->IfTrue(), branch); | |
317 | |
318 Node* vnot_smi; | |
319 Node* check_undefined = graph()->NewNode(machine->WordEqual(), value, | |
320 jsgraph()->UndefinedConstant()); | |
321 Node* branch_undefined = graph()->NewNode(common->Branch(BranchHint::kFalse), | |
322 check_undefined, if_not_smi); | |
323 | |
324 Node* if_undefined = graph()->NewNode(common->IfTrue(), branch_undefined); | |
325 Node* vundefined = | |
326 jsgraph()->Float64Constant(std::numeric_limits<double>::quiet_NaN()); | |
327 | |
328 Node* if_not_undefined = | |
329 graph()->NewNode(common->IfFalse(), branch_undefined); | |
330 Node* vheap_number = BuildLoadHeapNumberValue(value, if_not_undefined); | |
331 | |
332 if_not_smi = | |
333 graph()->NewNode(common->Merge(2), if_undefined, if_not_undefined); | |
334 vnot_smi = graph()->NewNode(common->Phi(MachineRepresentation::kFloat64, 2), | |
335 vundefined, vheap_number, if_not_smi); | |
336 | |
337 Node* if_smi = graph()->NewNode(common->IfFalse(), branch); | |
338 Node* vfrom_smi = BuildChangeSmiToFloat64(value); | |
339 | |
340 Node* merge = graph()->NewNode(common->Merge(2), if_not_smi, if_smi); | |
341 Node* phi = graph()->NewNode(common->Phi(MachineRepresentation::kFloat64, 2), | |
342 vnot_smi, vfrom_smi, merge); | |
343 | |
344 return phi; | |
345 } | |
346 | |
347 Node* FFIGraphBuilder::FromJS(Node* node, Node* context, MachineType type) { | |
348 // Do a JavaScript ToNumber. | |
349 Node* num = BuildJavaScriptToNumber(node, context, *effect_, *control_); | |
350 | |
351 switch (type.representation()) { | |
352 case MachineRepresentation::kWord32: { | |
353 // num = BuildChangeTaggedToFloat64(num); | |
354 // num = graph()->NewNode(jsgraph()->machine()->TruncateFloat64ToWord32(), | |
355 // num); | |
356 num = BuildChangeTaggedToInt32(num); | |
357 break; | |
358 } | |
359 // TODO(ofrobots): handle other types. | |
360 default: | |
361 UNREACHABLE(); | |
362 return nullptr; | |
363 } | |
364 return num; | |
365 } | |
366 | |
367 Node* FFIGraphBuilder::BuildChangeInt32ToSmi(Node* value) { | |
368 if (jsgraph()->machine()->Is64()) { | |
369 value = graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), value); | |
370 } | |
371 return graph()->NewNode(jsgraph()->machine()->WordShl(), value, | |
372 BuildSmiShiftBitsConstant()); | |
373 } | |
374 | |
375 Node* FFIGraphBuilder::BuildChangeSmiToInt32(Node* value) { | |
376 value = graph()->NewNode(jsgraph()->machine()->WordSar(), value, | |
377 BuildSmiShiftBitsConstant()); | |
378 if (jsgraph()->machine()->Is64()) { | |
379 value = | |
380 graph()->NewNode(jsgraph()->machine()->TruncateInt64ToInt32(), value); | |
381 } | |
382 return value; | |
383 } | |
384 | |
385 Node* FFIGraphBuilder::BuildChangeSmiToFloat64(Node* value) { | |
386 return graph()->NewNode(jsgraph()->machine()->ChangeInt32ToFloat64(), | |
387 BuildChangeSmiToInt32(value)); | |
388 } | |
389 | |
390 Node* FFIGraphBuilder::BuildTestNotSmi(Node* value) { | |
391 STATIC_ASSERT(kSmiTag == 0); | |
392 STATIC_ASSERT(kSmiTagMask == 1); | |
393 return graph()->NewNode(jsgraph()->machine()->WordAnd(), value, | |
394 jsgraph()->IntPtrConstant(kSmiTagMask)); | |
395 } | |
396 | |
397 Node* FFIGraphBuilder::BuildSmiShiftBitsConstant() { | |
398 return jsgraph()->IntPtrConstant(kSmiShiftSize + kSmiTagSize); | |
399 } | |
400 | |
401 Node* FFIGraphBuilder::BuildAllocateHeapNumberWithValue(Node* value, | |
402 Node* control) { | |
403 MachineOperatorBuilder* machine = jsgraph()->machine(); | |
404 CommonOperatorBuilder* common = jsgraph()->common(); | |
405 // The AllocateHeapNumberStub does not use the context, so we can safely pass | |
406 // in Smi zero here. | |
407 Callable callable = CodeFactory::AllocateHeapNumber(jsgraph()->isolate()); | |
408 Node* target = jsgraph()->HeapConstant(callable.code()); | |
409 Node* context = jsgraph()->NoContextConstant(); | |
410 Node* effect = | |
411 graph()->NewNode(common->BeginRegion(RegionObservability::kNotObservable), | |
412 graph()->start()); | |
413 if (!allocate_heap_number_operator_.is_set()) { | |
414 CallDescriptor* descriptor = Linkage::GetStubCallDescriptor( | |
415 jsgraph()->isolate(), jsgraph()->zone(), callable.descriptor(), 0, | |
416 CallDescriptor::kNoFlags, Operator::kNoThrow); | |
417 allocate_heap_number_operator_.set(common->Call(descriptor)); | |
418 } | |
419 Node* heap_number = graph()->NewNode(allocate_heap_number_operator_.get(), | |
420 target, context, effect, control); | |
421 Node* store = | |
422 graph()->NewNode(machine->Store(StoreRepresentation( | |
423 MachineRepresentation::kFloat64, kNoWriteBarrier)), | |
424 heap_number, BuildHeapNumberValueIndexConstant(), value, | |
425 heap_number, control); | |
426 return graph()->NewNode(common->FinishRegion(), heap_number, store); | |
427 } | |
428 | |
429 Node* FFIGraphBuilder::BuildLoadHeapNumberValue(Node* value, Node* control) { | |
430 return graph()->NewNode(jsgraph()->machine()->Load(MachineType::Float64()), | |
431 value, BuildHeapNumberValueIndexConstant(), | |
432 graph()->start(), control); | |
433 } | |
434 | |
435 Node* FFIGraphBuilder::BuildHeapNumberValueIndexConstant() { | |
436 return jsgraph()->IntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag); | |
437 } | |
438 | |
439 void FFIGraphBuilder::BuildJSToNativeWrapper(ffi::NativeFunction func) { | |
440 MachineSignature* sig = func.sig; | |
441 int param_count; | |
442 // if (jsgraph()->machine()->Is64()) { | |
443 param_count = static_cast<int>(sig->parameter_count()); | |
444 // } else { | |
445 // param_count = Int64Lowering::GetParameterCountAfterLowering(sig); | |
446 // } | |
447 int count = param_count + 1; // the function is the first arg | |
448 Node** args = Buffer(count); | |
449 | |
450 // Build the start and the JS parameter nodes. | |
451 Node* start = Start(param_count + 5); // FIXME: why 5? | |
452 *control_ = start; | |
453 *effect_ = start; | |
454 | |
455 // Create the context parameter. | |
456 Node* context = graph()->NewNode( | |
457 jsgraph()->common()->Parameter( | |
458 Linkage::GetJSCallContextParamIndex(param_count + 1), "%context"), | |
459 graph()->start()); | |
460 | |
461 int pos = 0; | |
462 ApiFunction api_func(func.start); | |
ofrobots
2016/06/23 01:02:51
Any thoughts on the abuse of 'ApiFunction' here?
Benedikt Meurer
2016/06/23 03:34:06
I think it's OK for prototyping. Long-term you'll
| |
463 ExternalReference ref(&api_func, ExternalReference::DIRECT_API_CALL, | |
464 jsgraph()->isolate()); | |
465 Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref)); | |
466 args[pos++] = function; | |
467 | |
468 // Convert JS parameters to native numbers. | |
469 for (int i = 0; i < param_count; i++) { | |
470 Node* param = | |
471 graph()->NewNode(jsgraph()->common()->Parameter(i + 1), start); | |
472 Node* native_param = FromJS(param, context, sig->GetParam(i)); | |
473 args[pos++] = native_param; | |
474 } | |
475 | |
476 CHECK_EQ(pos, count); | |
477 | |
478 // Call the Native code. | |
479 Node* call = BuildCCall(sig, args); | |
480 | |
481 Node* retval = call; | |
482 Node* jsval = ToJS(retval, context, sig->GetReturn()); | |
483 Node* ret = | |
484 graph()->NewNode(jsgraph()->common()->Return(), jsval, call, start); | |
485 | |
486 MergeControlToEnd(jsgraph(), ret); | |
487 } | |
488 | |
489 void FFIGraphBuilder::PrintDebugName(Node* node) { | |
490 PrintF("#%d:%s", node->id(), node->op()->mnemonic()); | |
491 } | |
492 | |
493 Graph* FFIGraphBuilder::graph() { return jsgraph()->graph(); } | |
494 | |
495 static void RecordFunctionCompilation(Logger::LogEventsAndTags tag, | |
496 CompilationInfo* info, | |
497 const char* message, | |
498 Vector<const char> func_name) { | |
499 Isolate* isolate = info->isolate(); | |
500 if (isolate->logger()->is_logging_code_events() || | |
501 isolate->cpu_profiler()->is_profiling()) { | |
502 ScopedVector<char> buffer(128); | |
503 SNPrintF(buffer, "%s:%.*s", message, func_name.length(), func_name.start()); | |
504 Handle<String> name_str = | |
505 isolate->factory()->NewStringFromAsciiChecked(buffer.start()); | |
506 Handle<String> script_str = | |
507 isolate->factory()->NewStringFromAsciiChecked("(FFI)"); | |
508 Handle<Code> code = info->code(); | |
509 Handle<SharedFunctionInfo> shared = | |
510 isolate->factory()->NewSharedFunctionInfo(name_str, code, false); | |
511 PROFILE(isolate, CodeCreateEvent(tag, AbstractCode::cast(*code), *shared, | |
512 *script_str, 0, 0)); | |
513 } | |
514 } | |
515 | |
516 // TODO(ofrobots): find a better home for this. | |
517 static void Setup(Isolate* isolate, Handle<Context> context) { | |
518 if (!context->get(Context::NATIVE_FUNCTION_MAP_INDEX)->IsMap()) { | |
519 // TODO(ofrobots): move this to boostrapper.cc?? | |
520 Handle<Map> prev_map = Handle<Map>(context->sloppy_function_map(), isolate); | |
521 | |
522 InstanceType instance_type = prev_map->instance_type(); | |
523 int internal_fields = JSObject::GetInternalFieldCount(*prev_map); | |
524 CHECK_EQ(0, internal_fields); | |
525 int pre_allocated = | |
526 prev_map->GetInObjectProperties() - prev_map->unused_property_fields(); | |
527 int instance_size; | |
528 int in_object_properties; | |
529 JSFunction::CalculateInstanceSizeHelper(instance_type, internal_fields, 0, | |
530 &instance_size, | |
531 &in_object_properties); | |
532 int unused_property_fields = in_object_properties - pre_allocated; | |
533 Handle<Map> map = Map::CopyInitialMap( | |
534 prev_map, instance_size, in_object_properties, unused_property_fields); | |
535 context->set_native_function_map(*map); | |
536 } | |
537 } | |
538 | |
539 Handle<JSFunction> CompileJSToNativeWrapper(Isolate* isolate, | |
540 Handle<String> name, | |
541 ffi::NativeFunction func) { | |
542 Handle<Context> context(isolate->context()); | |
543 Setup(isolate, context); | |
544 | |
545 //---------------------------------------------------------------------------- | |
546 // Create the JSFunction object. | |
547 //---------------------------------------------------------------------------- | |
548 Handle<SharedFunctionInfo> shared = isolate->factory()->NewSharedFunctionInfo( | |
549 name, MaybeHandle<Code>(), false); | |
550 int params = static_cast<int>(func.sig->parameter_count()); | |
551 shared->set_length(params); | |
552 shared->set_internal_formal_parameter_count(params); | |
553 Handle<JSFunction> function = isolate->factory()->NewFunction( | |
554 isolate->native_function_map(), name, MaybeHandle<Code>()); | |
555 // function->SetInternalField(0, *module_object); | |
556 function->set_shared(*shared); | |
557 | |
558 //---------------------------------------------------------------------------- | |
559 // Create the Graph | |
560 //---------------------------------------------------------------------------- | |
561 Zone zone(isolate->allocator()); | |
562 Graph graph(&zone); | |
563 CommonOperatorBuilder common(&zone); | |
564 MachineOperatorBuilder machine(&zone); | |
565 JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr, &machine); | |
566 | |
567 // TODO(ofrobots): we only support 64-bit at the moment | |
568 CHECK(machine.Is64()); | |
569 | |
570 Node* control = nullptr; | |
571 Node* effect = nullptr; | |
572 | |
573 FFIGraphBuilder builder(&zone, &jsgraph); | |
574 builder.set_control_ptr(&control); | |
575 builder.set_effect_ptr(&effect); | |
576 builder.BuildJSToNativeWrapper(func); | |
577 | |
578 //---------------------------------------------------------------------------- | |
579 // Run the compilation pipeline. | |
580 //---------------------------------------------------------------------------- | |
581 { | |
582 if (FLAG_trace_turbo_graph) { // Simple textual RPO. | |
583 OFStream os(stdout); | |
584 os << "-- Graph after change lowering -- " << std::endl; | |
585 os << AsRPO(graph); | |
586 } | |
587 | |
588 // Schedule and compile to machine code. | |
589 int params = static_cast<int>(func.sig->parameter_count()); | |
590 CallDescriptor* incoming = Linkage::GetJSCallDescriptor( | |
591 &zone, false, params + 1, CallDescriptor::kNoFlags); | |
592 Code::Flags flags = Code::ComputeFlags(Code::JS_TO_NATIVE_FUNCTION); | |
593 | |
594 int length = 0; | |
595 base::SmartArrayPointer<char> c_str = | |
596 name->ToCString(DISALLOW_NULLS, FAST_STRING_TRAVERSAL, &length); | |
597 ScopedVector<char> buffer(32 + length); | |
598 int chars = SNPrintF(buffer, "js-to-native#%s", c_str.get()); | |
599 Vector<const char> func_name = | |
600 Vector<const char>::cast(buffer.SubVector(0, chars)); | |
601 | |
602 CompilationInfo info(func_name, isolate, &zone, flags); | |
603 Handle<Code> code = | |
604 Pipeline::GenerateCodeForTesting(&info, incoming, &graph); | |
605 #ifdef ENABLE_DISASSEMBLER | |
606 if (FLAG_print_opt_code && !code.is_null()) { | |
607 OFStream os(stdout); | |
608 code->Disassemble(buffer.start(), os); | |
609 } | |
610 #endif | |
611 | |
612 RecordFunctionCompilation(Logger::FUNCTION_TAG, &info, "js-to-native", | |
613 func_name); | |
614 // Set the JSFunction's machine code. | |
615 function->set_code(*code); | |
616 } | |
617 return function; | |
618 } | |
619 | |
620 } // namespace compiler | |
621 } // namespace internal | |
622 } // namespace v8 | |
OLD | NEW |