Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(130)

Side by Side Diff: src/compiler/ffi-compiler.cc

Issue 2250863002: WIP: prototype ffi support (from 2084663004) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Rebase Created 3 years, 12 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/compiler/ffi-compiler.h ('k') | src/contexts.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 "include/v8-ffi.h"
8 #include "include/v8.h"
9
10 #include "src/isolate-inl.h"
11
12 #include "src/api.h"
13 #include "src/code-factory.h"
14 #include "src/compilation-info.h"
15 #include "src/compiler/access-builder.h"
16 #include "src/compiler/common-operator.h"
17 #include "src/compiler/graph-visualizer.h"
18 #include "src/compiler/graph.h"
19 #include "src/compiler/js-graph.h"
20 #include "src/compiler/js-operator.h"
21 #include "src/compiler/linkage.h"
22 #include "src/compiler/pipeline.h"
23 #include "src/factory.h"
24 #include "src/profiler/cpu-profiler.h"
25
26 namespace v8 {
27
28 namespace ffi {
29
30 Local<Function> CompileJSToNativeWrapper(Isolate* isolate, Local<String> name,
31 NativeFunction func) {
32 EscapableHandleScope handle_scope(isolate);
33 i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
34 i::Handle<i::String> internal_name = Utils::OpenHandle(*name);
35 internal::ffi::FFISignature internal_sig(
36 func.sig->return_count, func.sig->param_count, func.sig->representations);
37 internal::ffi::NativeFunction internal_func = {&internal_sig, func.start};
38 i::Handle<i::JSFunction> internal_function =
39 internal::compiler::CompileJSToNativeWrapper(
40 internal_isolate, internal_name, internal_func);
41 Local<Function> result;
42 if (!ToLocal<Function>(internal_function, &result)) {
43 return Local<Function>();
44 }
45 return handle_scope.Escape(result);
46 }
47
48 void* FFIFunctionBind(Isolate* isolate, NativeFunction func, Object* args) {
49 HandleScope handle_scope(isolate);
50 i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
51 internal::ffi::FFISignature internal_sig(
52 func.sig->return_count, func.sig->param_count, func.sig->representations);
53 internal::ffi::NativeFunction internal_func = {&internal_sig, func.start};
54 return internal::compiler::FFIFunctionBind(
55 internal_isolate, internal_func,
56 i::Handle<i::JSReceiver>::New(reinterpret_cast<i::JSReceiver*>(args),
57 internal_isolate));
58 }
59
60 void* BuildFFIArgumentSerializer(Isolate* isolate, NativeFunction func) {
61 HandleScope handle_scope(isolate);
62 i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
63 internal::ffi::FFISignature internal_sig(
64 func.sig->return_count, func.sig->param_count, func.sig->representations);
65 internal::ffi::NativeFunction internal_func = {&internal_sig, func.start};
66 return internal::compiler::BuildFFISerializer(internal_isolate,
67 internal_func);
68 }
69
70 void* BuildFFIArgumentDeserializer(Isolate* isolate, NativeFunction func) {
71 HandleScope handle_scope(isolate);
72 i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
73 internal::ffi::FFISignature internal_sig(
74 func.sig->return_count, func.sig->param_count, func.sig->representations);
75 internal::ffi::NativeFunction internal_func = {&internal_sig, func.start};
76 return internal::compiler::BuildFFIDeserializedExecutor(internal_isolate,
77 internal_func);
78 }
79
80 } // namespace ffi
81
82 namespace internal {
83 namespace compiler {
84
85 int TypeSize(ffi::FFIType type) {
86 switch (type) {
87 case ffi::FFIType::kInt32:
88 case ffi::FFIType::kFloat32:
89 return 4;
90 case ffi::FFIType::kInt64:
91 case ffi::FFIType::kFloat64:
92 case ffi::FFIType::kCharPtr:
93 case ffi::FFIType::kTypedArray:
94 case ffi::FFIType::kBufferNoCopy:
95 case ffi::FFIType::kFunction:
96 case ffi::FFIType::kStructPtr:
97 case ffi::FFIType::kForeign:
98 return 8;
99 case ffi::FFIType::kRawJS:
100 UNREACHABLE();
101 return sizeof(Handle<JSObject>);
102 }
103 }
104
105 void WriteObject(Handle<Object> value, ffi::FFIType type, char* dest) {
106 int size = TypeSize(type);
107 // TODO(mattloring): finish supporting all types
108 // TODO(mattloring): deduplicate translation with those in runtime-ffi.cc
109 switch (type) {
110 case ffi::FFIType::kInt32: {
111 int int32_value = static_cast<int>(value->Number());
112 memcpy(dest, &int32_value, size);
113 break;
114 }
115 case ffi::FFIType::kFloat32: {
116 float float_value = static_cast<float>(value->Number());
117 memcpy(dest, &float_value, size);
118 break;
119 }
120 case ffi::FFIType::kInt64: {
121 int64_t int64_value = static_cast<int64_t>(value->Number());
122 memcpy(dest, &int64_value, size);
123 break;
124 }
125 case ffi::FFIType::kFloat64: {
126 double double_value = value->Number();
127 memcpy(dest, &double_value, size);
128 break;
129 }
130 case ffi::FFIType::kCharPtr:
131 break;
132 case ffi::FFIType::kTypedArray:
133 break;
134 case ffi::FFIType::kBufferNoCopy: {
135 Handle<JSTypedArray> array(JSTypedArray::cast(*value));
136 uint8_t* contents =
137 reinterpret_cast<uint8_t*>(array->GetBuffer()->backing_store());
138 size_t offset = NumberToSize(array->byte_offset());
139 uint8_t* base = contents + offset;
140 memcpy(dest, &base, size);
141 break;
142 }
143 case ffi::FFIType::kFunction:
144 break;
145 case ffi::FFIType::kStructPtr:
146 break;
147 case ffi::FFIType::kForeign:
148 break;
149 case ffi::FFIType::kRawJS:
150 break;
151 }
152 }
153
154 MachineType FFITypeToMachineType(ffi::FFITypeElement elem) {
155 switch (elem.type) {
156 case ffi::FFIType::kInt32:
157 return MachineType::Int32();
158 case ffi::FFIType::kInt64:
159 return MachineType::Int64();
160 case ffi::FFIType::kFloat32:
161 return MachineType::Float32();
162 case ffi::FFIType::kFloat64:
163 return MachineType::Float64();
164 case ffi::FFIType::kCharPtr:
165 case ffi::FFIType::kTypedArray:
166 case ffi::FFIType::kBufferNoCopy:
167 case ffi::FFIType::kFunction:
168 case ffi::FFIType::kStructPtr:
169 case ffi::FFIType::kForeign:
170 return MachineType::Pointer();
171 case ffi::FFIType::kRawJS:
172 return MachineType::TaggedPointer();
173 }
174 }
175
176 MachineType* TranslateSignature(ffi::FFISignature* sig) {
177 const size_t params = sig->parameter_count();
178 const size_t returns = sig->return_count();
179 MachineType* reps = new MachineType[params + returns];
180 for (size_t i = 0; i < returns; i++) {
181 reps[i] = FFITypeToMachineType(sig->GetReturn(i));
182 }
183 for (size_t i = 0; i < params; i++) {
184 reps[returns + i] = FFITypeToMachineType(sig->GetParam(i));
185 }
186 return reps;
187 }
188
189 namespace {
190
191 // TODO(ofrobots): duplicated from wasm-compiler.cc
192 static void MergeControlToEnd(JSGraph* jsgraph, Node* node) {
193 Graph* g = jsgraph->graph();
194 if (g->end()) {
195 NodeProperties::MergeControlToEnd(g, jsgraph->common(), node);
196 } else {
197 g->SetEnd(g->NewNode(jsgraph->common()->End(1), node));
198 }
199 }
200
201 } // namespace
202
203 static Node* BuildCallToRuntime(Runtime::FunctionId f, JSGraph* jsgraph,
204 Node* context, Node** parameters,
205 int parameter_count, Node** effect_ptr,
206 Node** control_ptr) {
207 // At the moment we only allow 2 parameters. If more parameters are needed,
208 // then the size of {inputs} below has to be increased accordingly.
209 DCHECK(parameter_count <= 2);
210 const Runtime::Function* fun = Runtime::FunctionForId(f);
211 // fun->nargs may be negative for Runtime::kCall (variable arg count)
212 CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor(
213 jsgraph->zone(), f, fun->nargs < 0 ? parameter_count : fun->nargs,
214 Operator::kNoProperties, CallDescriptor::kNoFlags);
215 DCHECK_EQ(1, fun->result_size);
216 Node* inputs[8];
217 int count = 0;
218 inputs[count++] = jsgraph->CEntryStubConstant(fun->result_size);
219 for (int i = 0; i < parameter_count; i++) {
220 inputs[count++] = parameters[i];
221 }
222 inputs[count++] = jsgraph->ExternalConstant(
223 ExternalReference(f, jsgraph->isolate())); // ref
224 inputs[count++] = jsgraph->Int32Constant(fun->nargs); // arity
225 inputs[count++] = context; // context
226 inputs[count++] = *effect_ptr;
227 inputs[count++] = *control_ptr;
228
229 Node* node =
230 jsgraph->graph()->NewNode(jsgraph->common()->Call(desc), count, inputs);
231 *effect_ptr = node;
232 *control_ptr =
233 jsgraph->graph()->NewNode(jsgraph->common()->IfSuccess(), node);
234 return node;
235 }
236
237 FFIGraphBuilder::FFIGraphBuilder(Zone* zone, JSGraph* jsgraph)
238 : zone_(zone),
239 jsgraph_(jsgraph),
240 control_(nullptr),
241 effect_(nullptr),
242 cur_buffer_(def_buffer_),
243 cur_bufsize_(kDefaultBufferSize) {
244 DCHECK_NOT_NULL(jsgraph_);
245 }
246
247 Node* FFIGraphBuilder::Start(unsigned params) {
248 Node* start = graph()->NewNode(jsgraph()->common()->Start(params));
249 graph()->SetStart(start);
250 return start;
251 }
252
253 MachineType* FFIGraphBuilder::GetMachineTypes(ffi::FFISignature* sig) {
254 return TranslateSignature(sig);
255 }
256
257 Node* FFIGraphBuilder::BuildCCall(ffi::FFISignature* sig, Node** args) {
258 const size_t params = sig->parameter_count();
259 const size_t returns = sig->return_count();
260 const size_t extra = 2; // effect and control inputs.
261 const size_t count = 1 + params + extra;
262
263 // Reallocate the buffer to make space for extra inputs.
264 args = Realloc(args, 1 + params, count);
265
266 // Add effect and control inputs.
267 args[params + 1] = *effect_;
268 args[params + 2] = *control_;
269
270 MachineType* reps = TranslateSignature(sig);
271 MachineSignature mach_sig(returns, params, reps);
272
273 CallDescriptor* desc =
274 Linkage::GetSimplifiedCDescriptor(jsgraph()->zone(), &mach_sig);
275
276 const Operator* op = jsgraph()->common()->Call(desc);
277 Node* call = graph()->NewNode(op, static_cast<int>(count), args);
278 *effect_ = call;
279 *control_ = graph()->NewNode(jsgraph()->common()->IfSuccess(), call);
280 delete[] reps;
281 return call;
282 }
283
284 Node* FFIGraphBuilder::BuildChangeInt32ToTagged(Node* value) {
285 MachineOperatorBuilder* machine = jsgraph()->machine();
286 CommonOperatorBuilder* common = jsgraph()->common();
287
288 if (machine->Is64()) {
289 return BuildChangeInt32ToSmi(value);
290 }
291
292 Node* add = graph()->NewNode(machine->Int32AddWithOverflow(), value, value);
293
294 Node* ovf = graph()->NewNode(common->Projection(1), add);
295 Node* branch = graph()->NewNode(common->Branch(BranchHint::kFalse), ovf,
296 graph()->start());
297
298 Node* if_true = graph()->NewNode(common->IfTrue(), branch);
299 Node* vtrue = BuildAllocateHeapNumberWithValue(
300 graph()->NewNode(machine->ChangeInt32ToFloat64(), value), if_true);
301
302 Node* if_false = graph()->NewNode(common->IfFalse(), branch);
303 Node* vfalse = graph()->NewNode(common->Projection(0), add);
304
305 Node* merge = graph()->NewNode(common->Merge(2), if_true, if_false);
306 Node* phi = graph()->NewNode(common->Phi(MachineRepresentation::kTagged, 2),
307 vtrue, vfalse, merge);
308 return phi;
309 }
310
311 Node* FFIGraphBuilder::BuildChangeFloat64ToTagged(Node* value) {
312 MachineOperatorBuilder* machine = jsgraph()->machine();
313 CommonOperatorBuilder* common = jsgraph()->common();
314
315 Node* value32 = graph()->NewNode(machine->RoundFloat64ToInt32(), value);
316 Node* check_same = graph()->NewNode(
317 machine->Float64Equal(), value,
318 graph()->NewNode(machine->ChangeInt32ToFloat64(), value32));
319 Node* branch_same =
320 graph()->NewNode(common->Branch(), check_same, graph()->start());
321
322 Node* if_smi = graph()->NewNode(common->IfTrue(), branch_same);
323 Node* vsmi;
324 Node* if_box = graph()->NewNode(common->IfFalse(), branch_same);
325 Node* vbox;
326
327 // We only need to check for -0 if the {value} can potentially contain -0.
328 Node* check_zero = graph()->NewNode(machine->Word32Equal(), value32,
329 jsgraph()->Int32Constant(0));
330 Node* branch_zero =
331 graph()->NewNode(common->Branch(BranchHint::kFalse), check_zero, if_smi);
332
333 Node* if_zero = graph()->NewNode(common->IfTrue(), branch_zero);
334 Node* if_notzero = graph()->NewNode(common->IfFalse(), branch_zero);
335
336 // In case of 0, we need to check the high bits for the IEEE -0 pattern.
337 Node* check_negative = graph()->NewNode(
338 machine->Int32LessThan(),
339 graph()->NewNode(machine->Float64ExtractHighWord32(), value),
340 jsgraph()->Int32Constant(0));
341 Node* branch_negative = graph()->NewNode(common->Branch(BranchHint::kFalse),
342 check_negative, if_zero);
343
344 Node* if_negative = graph()->NewNode(common->IfTrue(), branch_negative);
345 Node* if_notnegative = graph()->NewNode(common->IfFalse(), branch_negative);
346
347 // We need to create a box for negative 0.
348 if_smi = graph()->NewNode(common->Merge(2), if_notzero, if_notnegative);
349 if_box = graph()->NewNode(common->Merge(2), if_box, if_negative);
350
351 // On 64-bit machines we can just wrap the 32-bit integer in a smi, for 32-bit
352 // machines we need to deal with potential overflow and fallback to boxing.
353 if (machine->Is64()) {
354 vsmi = BuildChangeInt32ToSmi(value32);
355 } else {
356 Node* smi_tag =
357 graph()->NewNode(machine->Int32AddWithOverflow(), value32, value32);
358
359 Node* check_ovf = graph()->NewNode(common->Projection(1), smi_tag);
360 Node* branch_ovf =
361 graph()->NewNode(common->Branch(BranchHint::kFalse), check_ovf, if_smi);
362
363 Node* if_ovf = graph()->NewNode(common->IfTrue(), branch_ovf);
364 if_box = graph()->NewNode(common->Merge(2), if_ovf, if_box);
365
366 if_smi = graph()->NewNode(common->IfFalse(), branch_ovf);
367 vsmi = graph()->NewNode(common->Projection(0), smi_tag);
368 }
369
370 // Allocate the box for the {value}.
371 vbox = BuildAllocateHeapNumberWithValue(value, if_box);
372
373 Node* control = graph()->NewNode(common->Merge(2), if_smi, if_box);
374 value = graph()->NewNode(common->Phi(MachineRepresentation::kTagged, 2), vsmi,
375 vbox, control);
376 return value;
377 }
378
379 Node* FFIGraphBuilder::ToJS(Node* node, Node* context,
380 ffi::FFITypeElement elem) {
381 switch (elem.type) {
382 case ffi::FFIType::kInt32:
383 return BuildChangeInt32ToTagged(node);
384 case ffi::FFIType::kInt64:
385 // TODO(titzer): i64->JS has no good solution right now. Using lower 32
386 // bits.
387 if (jsgraph()->machine()->Is64()) {
388 // On 32 bit platforms we do not have to do the truncation because the
389 // node we get in as a parameter only contains the low word anyways.
390 node = graph()->NewNode(jsgraph()->machine()->TruncateInt64ToInt32(),
391 node);
392 }
393 return BuildChangeInt32ToTagged(node);
394 case ffi::FFIType::kFloat32:
395 node = graph()->NewNode(jsgraph()->machine()->ChangeFloat32ToFloat64(),
396 node);
397 return BuildChangeFloat64ToTagged(node);
398 case ffi::FFIType::kFloat64:
399 return BuildChangeFloat64ToTagged(node);
400 case ffi::FFIType::kCharPtr:
401 return CharPtrToJSString(node, context, *effect_, *control_);
402 case ffi::FFIType::kTypedArray: {
403 UNREACHABLE();
404 return nullptr;
405 }
406 case ffi::FFIType::kBufferNoCopy: {
407 UNREACHABLE();
408 return nullptr;
409 }
410 case ffi::FFIType::kFunction: {
411 UNREACHABLE();
412 return nullptr;
413 }
414 case ffi::FFIType::kStructPtr: {
415 UNREACHABLE();
416 return nullptr;
417 }
418 case ffi::FFIType::kForeign: {
419 return PointerToForeign(node, context, *effect_, *control_);
420 }
421 case ffi::FFIType::kRawJS: {
422 return node;
423 }
424 }
425 }
426
427 Node* FFIGraphBuilder::BuildJavaScriptToNumber(Node* node, Node* context,
428 Node* effect, Node* control) {
429 Callable callable = CodeFactory::ToNumber(jsgraph()->isolate());
430 CallDescriptor* desc = Linkage::GetStubCallDescriptor(
431 jsgraph()->isolate(), jsgraph()->zone(), callable.descriptor(), 0,
432 CallDescriptor::kNoFlags, Operator::kNoProperties);
433 Node* stub_code = jsgraph()->HeapConstant(callable.code());
434
435 Node* result = graph()->NewNode(jsgraph()->common()->Call(desc), stub_code,
436 node, context, effect, control);
437
438 *control_ = graph()->NewNode(jsgraph()->common()->IfSuccess(), result);
439 *effect_ = result;
440
441 return result;
442 }
443
444 Node* FFIGraphBuilder::JSStringToCharPtr(Node* node, Node* context,
445 Node* effect, Node* control) {
446 Node* parameters[] = {node};
447 return BuildCallToRuntime(Runtime::kJSStringToCharPtr, jsgraph(), context,
448 parameters, arraysize(parameters), &effect,
449 &control);
450 }
451
452 Node* FFIGraphBuilder::TypedArrayToUint8Ptr(Node* node, Node* context,
453 Node* effect, Node* control) {
454 Node* parameters[] = {node};
455 return BuildCallToRuntime(Runtime::kTypedArrayToUint8Ptr, jsgraph(), context,
456 parameters, arraysize(parameters), &effect,
457 &control);
458 }
459
460 Node* FFIGraphBuilder::BufferToPtrNoCopy(Node* node, Node* context,
461 Node* effect, Node* control) {
462 Node* parameters[] = {node};
463 return BuildCallToRuntime(Runtime::kBufferToPtrNoCopy, jsgraph(), context,
464 parameters, arraysize(parameters), &effect,
465 &control);
466 }
467
468 v8::ffi::FFISignature* CopySignature(ffi::FFISignature* sig) {
469 size_t param_count = sig->parameter_count();
470 size_t return_count = sig->return_count();
471 ffi::FFITypeElement* reps =
472 new ffi::FFITypeElement[param_count + return_count];
473 for (size_t i = 0; i < return_count; i++) {
474 ffi::FFITypeElement elem = sig->GetReturn(i);
475 // TODO(mattloring): handle structs
476 if (elem.type == ffi::FFIType::kFunction) {
477 internal::ffi::FFISignature internal_sig(
478 elem.info->function_signature->return_count,
479 elem.info->function_signature->param_count,
480 elem.info->function_signature->representations);
481 v8::ffi::FFISupplementalInfo* info = new v8::ffi::FFISupplementalInfo{
482 .function_signature = CopySignature(&internal_sig)};
483 reps[i] = {elem.type, info};
484 } else {
485 reps[i] = elem;
486 }
487 }
488 for (size_t i = 0; i < param_count; i++) {
489 ffi::FFITypeElement elem = sig->GetParam(i);
490 // TODO(mattloring): handle structs
491 if (elem.type == ffi::FFIType::kFunction) {
492 internal::ffi::FFISignature internal_sig(
493 elem.info->function_signature->return_count,
494 elem.info->function_signature->param_count,
495 elem.info->function_signature->representations);
496 v8::ffi::FFISupplementalInfo* info = new v8::ffi::FFISupplementalInfo{
497 .function_signature = CopySignature(&internal_sig)};
498 reps[i] = {elem.type, info};
499 } else {
500 reps[i] = elem;
501 }
502 }
503 return new v8::ffi::FFISignature{return_count, param_count, reps};
504 }
505
506 Node* FFIGraphBuilder::JSFunctionToFnPtr(Node* node, Node* context,
507 ffi::FFISignature* sig, Node* effect,
508 Node* control) {
509 // TODO(mattloring): free ffi signature
510 v8::ffi::FFISignature* allocated_sig = CopySignature(sig);
511 ExternalReference ref(reinterpret_cast<Address>(allocated_sig),
512 jsgraph()->isolate());
513 Node* sig_reference =
514 graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
515 Node* parameters[] = {node, sig_reference};
516 return BuildCallToRuntime(Runtime::kJSFunctionToFnPtr, jsgraph(), context,
517 parameters, arraysize(parameters), &effect,
518 &control);
519 }
520
521 Node* FFIGraphBuilder::JSObjectToStructPtr(Node* node, Node* context,
522 ffi::FFIStructSignature* sig,
523 Node* effect, Node* control) {
524 v8::ffi::FFIStructElement* reps =
525 new v8::ffi::FFIStructElement[sig->elem_count];
526 // TODO(mattloring): if there are nested signatures they must be allocated as
527 // well
528 for (size_t i = 0; i < sig->elem_count; i++) {
529 reps[i] = sig->elems[i];
530 }
531 v8::ffi::FFIStructSignature* allocated_sig =
532 new v8::ffi::FFIStructSignature{sig->elem_count, reps};
533 ExternalReference ref(reinterpret_cast<Address>(allocated_sig),
534 jsgraph()->isolate());
535 Node* sig_reference =
536 graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
537 Node* parameters[] = {node, sig_reference};
538 return BuildCallToRuntime(Runtime::kJSObjectToStructPtr, jsgraph(), context,
539 parameters, arraysize(parameters), &effect,
540 &control);
541 }
542
543 Node* FFIGraphBuilder::ForeignToPointer(Node* node, Node* context, Node* effect,
544 Node* control) {
545 Node* parameters[] = {node};
546 return BuildCallToRuntime(Runtime::kForeignToPointer, jsgraph(), context,
547 parameters, arraysize(parameters), &effect,
548 &control);
549 }
550
551 Node* FFIGraphBuilder::CharPtrToJSString(Node* node, Node* context,
552 Node* effect, Node* control) {
553 Node* parameters[] = {node};
554 return BuildCallToRuntime(Runtime::kCharPtrToJSString, jsgraph(), context,
555 parameters, arraysize(parameters), &effect,
556 &control);
557 }
558
559 Node* FFIGraphBuilder::PointerToForeign(Node* node, Node* context, Node* effect,
560 Node* control) {
561 Node* parameters[] = {node};
562 return BuildCallToRuntime(Runtime::kPointerToForeign, jsgraph(), context,
563 parameters, arraysize(parameters), &effect,
564 &control);
565 }
566
567 static bool CanCover(Node* value, IrOpcode::Value opcode) {
568 if (value->opcode() != opcode) return false;
569 bool first = true;
570 for (Edge const edge : value->use_edges()) {
571 if (NodeProperties::IsControlEdge(edge)) continue;
572 if (NodeProperties::IsEffectEdge(edge)) continue;
573 DCHECK(NodeProperties::IsValueEdge(edge));
574 if (!first) return false;
575 first = false;
576 }
577 return true;
578 }
579
580 Node* FFIGraphBuilder::BuildChangeTaggedToInt32(Node* value) {
581 CommonOperatorBuilder* common = jsgraph()->common();
582
583 Node* check = BuildTestNotSmi(value);
584 Node* branch = graph()->NewNode(common->Branch(BranchHint::kFalse), check,
585 graph()->start());
586
587 Node* if_smi = graph()->NewNode(common->IfFalse(), branch);
588 Node* vfrom_smi = BuildChangeSmiToInt32(value);
589
590 // TODO(ofrobots): the not_smi path is too ugly and slow at the moment
591 Node* if_not_smi = graph()->NewNode(common->IfTrue(), branch);
592 Node* vfloat = BuildChangeTaggedToFloat64(value);
593 Node* vnot_smi =
594 graph()->NewNode(jsgraph()->machine()->TruncateFloat64ToWord32(), vfloat);
595
596 Node* merge = graph()->NewNode(common->Merge(2), if_not_smi, if_smi);
597 Node* phi = graph()->NewNode(common->Phi(MachineRepresentation::kWord32, 2),
598 vnot_smi, vfrom_smi, merge);
599 return phi;
600 }
601
602 Node* FFIGraphBuilder::BuildChangeTaggedToFloat64(Node* value) {
603 MachineOperatorBuilder* machine = jsgraph()->machine();
604 CommonOperatorBuilder* common = jsgraph()->common();
605
606 if (CanCover(value, IrOpcode::kJSToNumber)) {
607 // ChangeTaggedToFloat64(JSToNumber(x)) =>
608 // if IsSmi(x) then ChangeSmiToFloat64(x)
609 // else let y = JSToNumber(x) in
610 // if IsSmi(y) then ChangeSmiToFloat64(y)
611 // else BuildLoadHeapNumberValue(y)
612 Node* object = NodeProperties::GetValueInput(value, 0);
613 Node* context = NodeProperties::GetContextInput(value);
614 Node* frame_state = NodeProperties::GetFrameStateInput(value);
615 Node* effect = NodeProperties::GetEffectInput(value);
616 Node* control = NodeProperties::GetControlInput(value);
617
618 const Operator* merge_op = common->Merge(2);
619 const Operator* ephi_op = common->EffectPhi(2);
620 const Operator* phi_op = common->Phi(MachineRepresentation::kFloat64, 2);
621
622 Node* check1 = BuildTestNotSmi(object);
623 Node* branch1 =
624 graph()->NewNode(common->Branch(BranchHint::kFalse), check1, control);
625
626 Node* if_true1 = graph()->NewNode(common->IfTrue(), branch1);
627 Node* vtrue1 = graph()->NewNode(value->op(), object, context, frame_state,
628 effect, if_true1);
629 Node* etrue1 = vtrue1;
630
631 Node* check2 = BuildTestNotSmi(vtrue1);
632 Node* branch2 = graph()->NewNode(common->Branch(), check2, if_true1);
633
634 Node* if_true2 = graph()->NewNode(common->IfTrue(), branch2);
635 Node* vtrue2 = BuildLoadHeapNumberValue(vtrue1, if_true2);
636
637 Node* if_false2 = graph()->NewNode(common->IfFalse(), branch2);
638 Node* vfalse2 = BuildChangeSmiToFloat64(vtrue1);
639
640 if_true1 = graph()->NewNode(merge_op, if_true2, if_false2);
641 vtrue1 = graph()->NewNode(phi_op, vtrue2, vfalse2, if_true1);
642
643 Node* if_false1 = graph()->NewNode(common->IfFalse(), branch1);
644 Node* vfalse1 = BuildChangeSmiToFloat64(object);
645 Node* efalse1 = effect;
646
647 Node* merge1 = graph()->NewNode(merge_op, if_true1, if_false1);
648 Node* ephi1 = graph()->NewNode(ephi_op, etrue1, efalse1, merge1);
649 Node* phi1 = graph()->NewNode(phi_op, vtrue1, vfalse1, merge1);
650
651 // Wire the new diamond into the graph, {JSToNumber} can still throw.
652 NodeProperties::ReplaceUses(value, phi1, ephi1, etrue1, etrue1);
653
654 // TODO(mstarzinger): This iteration cuts out the IfSuccess projection from
655 // the node and places it inside the diamond. Come up with a helper method!
656 for (Node* use : etrue1->uses()) {
657 if (use->opcode() == IrOpcode::kIfSuccess) {
658 use->ReplaceUses(merge1);
659 NodeProperties::ReplaceControlInput(branch2, use);
660 }
661 }
662 return phi1;
663 }
664
665 Node* check = BuildTestNotSmi(value);
666 Node* branch = graph()->NewNode(common->Branch(BranchHint::kFalse), check,
667 graph()->start());
668
669 Node* if_not_smi = graph()->NewNode(common->IfTrue(), branch);
670
671 Node* vnot_smi;
672 Node* check_undefined = graph()->NewNode(machine->WordEqual(), value,
673 jsgraph()->UndefinedConstant());
674 Node* branch_undefined = graph()->NewNode(common->Branch(BranchHint::kFalse),
675 check_undefined, if_not_smi);
676
677 Node* if_undefined = graph()->NewNode(common->IfTrue(), branch_undefined);
678 Node* vundefined =
679 jsgraph()->Float64Constant(std::numeric_limits<double>::quiet_NaN());
680
681 Node* if_not_undefined =
682 graph()->NewNode(common->IfFalse(), branch_undefined);
683 Node* vheap_number = BuildLoadHeapNumberValue(value, if_not_undefined);
684
685 if_not_smi =
686 graph()->NewNode(common->Merge(2), if_undefined, if_not_undefined);
687 vnot_smi = graph()->NewNode(common->Phi(MachineRepresentation::kFloat64, 2),
688 vundefined, vheap_number, if_not_smi);
689
690 Node* if_smi = graph()->NewNode(common->IfFalse(), branch);
691 Node* vfrom_smi = BuildChangeSmiToFloat64(value);
692
693 Node* merge = graph()->NewNode(common->Merge(2), if_not_smi, if_smi);
694 Node* phi = graph()->NewNode(common->Phi(MachineRepresentation::kFloat64, 2),
695 vnot_smi, vfrom_smi, merge);
696
697 return phi;
698 }
699
700 Node* FFIGraphBuilder::FromJS(Node* node, Node* context,
701 ffi::FFITypeElement elem) {
702 Node* result = nullptr;
703
704 switch (elem.type) {
705 case ffi::FFIType::kInt32: {
706 // num = BuildChangeTaggedToFloat64(num);
707 // num = graph()->NewNode(jsgraph()->machine()->TruncateFloat64ToWord32(),
708 // num);
709 // Do a JavaScript ToNumber.
710 Node* num = BuildJavaScriptToNumber(node, context, *effect_, *control_);
711 result = BuildChangeTaggedToInt32(num);
712 break;
713 }
714 case ffi::FFIType::kInt64: {
715 UNREACHABLE();
716 break;
717 }
718 case ffi::FFIType::kFloat32: {
719 UNREACHABLE();
720 break;
721 }
722 case ffi::FFIType::kFloat64: {
723 UNREACHABLE();
724 break;
725 }
726 case ffi::FFIType::kCharPtr: {
727 result = JSStringToCharPtr(node, context, *effect_, *control_);
728 break;
729 }
730 case ffi::FFIType::kTypedArray: {
731 result = TypedArrayToUint8Ptr(node, context, *effect_, *control_);
732 break;
733 }
734 case ffi::FFIType::kBufferNoCopy: {
735 result = BufferToPtrNoCopy(node, context, *effect_, *control_);
736 break;
737 }
738 case ffi::FFIType::kFunction: {
739 result = JSFunctionToFnPtr(
740 node, context, (ffi::FFISignature*)elem.info->function_signature,
741 *effect_, *control_);
742 break;
743 }
744 case ffi::FFIType::kStructPtr: {
745 result = JSObjectToStructPtr(
746 node, context, (ffi::FFIStructSignature*)elem.info->struct_elements,
747 *effect_, *control_);
748 break;
749 }
750 case ffi::FFIType::kForeign: {
751 result = ForeignToPointer(node, context, *effect_, *control_);
752 break;
753 }
754 case ffi::FFIType::kRawJS: {
755 result = node;
756 break;
757 }
758 }
759 return result;
760 }
761
762 Node* FFIGraphBuilder::BuildChangeInt32ToSmi(Node* value) {
763 if (jsgraph()->machine()->Is64()) {
764 value = graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), value);
765 }
766 return graph()->NewNode(jsgraph()->machine()->WordShl(), value,
767 BuildSmiShiftBitsConstant());
768 }
769
770 Node* FFIGraphBuilder::BuildChangeSmiToInt32(Node* value) {
771 value = graph()->NewNode(jsgraph()->machine()->WordSar(), value,
772 BuildSmiShiftBitsConstant());
773 if (jsgraph()->machine()->Is64()) {
774 value =
775 graph()->NewNode(jsgraph()->machine()->TruncateInt64ToInt32(), value);
776 }
777 return value;
778 }
779
780 Node* FFIGraphBuilder::BuildChangeSmiToFloat64(Node* value) {
781 return graph()->NewNode(jsgraph()->machine()->ChangeInt32ToFloat64(),
782 BuildChangeSmiToInt32(value));
783 }
784
785 Node* FFIGraphBuilder::BuildTestNotSmi(Node* value) {
786 STATIC_ASSERT(kSmiTag == 0);
787 STATIC_ASSERT(kSmiTagMask == 1);
788 return graph()->NewNode(jsgraph()->machine()->WordAnd(), value,
789 jsgraph()->IntPtrConstant(kSmiTagMask));
790 }
791
792 Node* FFIGraphBuilder::BuildSmiShiftBitsConstant() {
793 return jsgraph()->IntPtrConstant(kSmiShiftSize + kSmiTagSize);
794 }
795
796 Node* FFIGraphBuilder::BuildAllocateHeapNumberWithValue(Node* value,
797 Node* control) {
798 MachineOperatorBuilder* machine = jsgraph()->machine();
799 CommonOperatorBuilder* common = jsgraph()->common();
800 // The AllocateHeapNumberStub does not use the context, so we can safely pass
801 // in Smi zero here.
802 Callable callable = CodeFactory::AllocateHeapNumber(jsgraph()->isolate());
803 Node* target = jsgraph()->HeapConstant(callable.code());
804 Node* context = jsgraph()->NoContextConstant();
805 Node* effect =
806 graph()->NewNode(common->BeginRegion(RegionObservability::kNotObservable),
807 graph()->start());
808 if (!allocate_heap_number_operator_.is_set()) {
809 CallDescriptor* descriptor = Linkage::GetStubCallDescriptor(
810 jsgraph()->isolate(), jsgraph()->zone(), callable.descriptor(), 0,
811 CallDescriptor::kNoFlags, Operator::kNoThrow);
812 allocate_heap_number_operator_.set(common->Call(descriptor));
813 }
814 Node* heap_number = graph()->NewNode(allocate_heap_number_operator_.get(),
815 target, context, effect, control);
816 Node* store =
817 graph()->NewNode(machine->Store(StoreRepresentation(
818 MachineRepresentation::kFloat64, kNoWriteBarrier)),
819 heap_number, BuildHeapNumberValueIndexConstant(), value,
820 heap_number, control);
821 return graph()->NewNode(common->FinishRegion(), heap_number, store);
822 }
823
824 Node* FFIGraphBuilder::BuildLoadHeapNumberValue(Node* value, Node* control) {
825 return graph()->NewNode(jsgraph()->machine()->Load(MachineType::Float64()),
826 value, BuildHeapNumberValueIndexConstant(),
827 graph()->start(), control);
828 }
829
830 Node* FFIGraphBuilder::BuildHeapNumberValueIndexConstant() {
831 return jsgraph()->IntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag);
832 }
833
834 void FFIGraphBuilder::BuildJSToNativeWrapper(ffi::NativeFunction func) {
835 ffi::FFISignature* sig = func.sig;
836 int param_count;
837 // if (jsgraph()->machine()->Is64()) {
838 param_count = static_cast<int>(sig->parameter_count());
839 // } else {
840 // param_count = Int64Lowering::GetParameterCountAfterLowering(sig);
841 // }
842 int count = param_count + 1; // the function is the first arg
843 Node** args = Buffer(count);
844
845 // Build the start and the JS parameter nodes.
846 Node* start = Start(param_count + 5); // FIXME: why 5?
847 *control_ = start;
848 *effect_ = start;
849
850 // Create the context parameter.
851 Node* context = graph()->NewNode(
852 jsgraph()->common()->Parameter(
853 Linkage::GetJSCallContextParamIndex(param_count + 1), "%context"),
854 graph()->start());
855
856 int pos = 0;
857 ApiFunction api_func(func.start);
858 ExternalReference ref(&api_func, ExternalReference::DIRECT_API_CALL,
859 jsgraph()->isolate());
860 Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
861 args[pos++] = function;
862
863 // Convert JS parameters to native numbers.
864 for (int i = 0; i < param_count; i++) {
865 Node* param =
866 graph()->NewNode(jsgraph()->common()->Parameter(i + 1), start);
867 Node* native_param = FromJS(param, context, sig->GetParam(i));
868 args[pos++] = native_param;
869 }
870
871 CHECK_EQ(pos, count);
872
873 // Call the Native code.
874 Node* native_call = BuildCCall(sig, args);
875 Node* cleaned_call =
876 BuildCallToRuntime(Runtime::kReleaseFFIMemPool, jsgraph(), context, NULL,
877 0, effect_, control_);
878
879 Node* retval;
880 if (sig->return_count() != 0) {
881 retval = ToJS(native_call, context, sig->GetReturn());
882 } else {
883 retval = jsgraph()->UndefinedConstant();
884 }
885 Node* ret = graph()->NewNode(jsgraph()->common()->Return(),
886 jsgraph()->Int32Constant(0), retval,
887 cleaned_call, start);
888
889 MergeControlToEnd(jsgraph(), ret);
890 }
891
892 void FFIGraphBuilder::PrintDebugName(Node* node) {
893 PrintF("#%d:%s", node->id(), node->op()->mnemonic());
894 }
895
896 Graph* FFIGraphBuilder::graph() { return jsgraph()->graph(); }
897
898 static void RecordFunctionCompilation(Logger::LogEventsAndTags tag,
899 CompilationInfo* info,
900 const char* message,
901 Vector<const char> func_name) {
902 Isolate* isolate = info->isolate();
903 if (isolate->logger()->is_logging_code_events() || isolate->is_profiling()) {
904 ScopedVector<char> buffer(128);
905 SNPrintF(buffer, "%s:%.*s", message, func_name.length(), func_name.start());
906 Handle<String> name_str =
907 isolate->factory()->NewStringFromAsciiChecked(buffer.start());
908 Handle<String> script_str =
909 isolate->factory()->NewStringFromAsciiChecked("(FFI)");
910 Handle<Code> code = info->code();
911 Handle<SharedFunctionInfo> shared =
912 isolate->factory()->NewSharedFunctionInfo(name_str, code, false);
913 PROFILE(isolate, CodeCreateEvent(tag, AbstractCode::cast(*code), *shared,
914 *script_str, 0, 0));
915 }
916 }
917
918 // TODO(ofrobots): find a better home for this.
919 static void Setup(Isolate* isolate, Handle<Context> context) {
920 if (!context->get(Context::NATIVE_FUNCTION_MAP_INDEX)->IsMap()) {
921 // TODO(ofrobots): move this to boostrapper.cc??
922 Handle<Map> prev_map = Handle<Map>(context->sloppy_function_map(), isolate);
923
924 InstanceType instance_type = prev_map->instance_type();
925 int internal_fields = JSObject::GetInternalFieldCount(*prev_map);
926 CHECK_EQ(0, internal_fields);
927 int pre_allocated =
928 prev_map->GetInObjectProperties() - prev_map->unused_property_fields();
929 int instance_size;
930 int in_object_properties;
931 JSFunction::CalculateInstanceSizeHelper(instance_type, internal_fields, 0,
932 &instance_size,
933 &in_object_properties);
934 int unused_property_fields = in_object_properties - pre_allocated;
935 Handle<Map> map = Map::CopyInitialMap(
936 prev_map, instance_size, in_object_properties, unused_property_fields);
937 context->set_native_function_map(*map);
938 }
939 }
940
941 Handle<JSFunction> CompileJSToNativeWrapper(Isolate* isolate,
942 Handle<String> name,
943 ffi::NativeFunction func) {
944 Handle<Context> context(isolate->context());
945 Setup(isolate, context);
946
947 //----------------------------------------------------------------------------
948 // Create the JSFunction object.
949 //----------------------------------------------------------------------------
950 Handle<SharedFunctionInfo> shared = isolate->factory()->NewSharedFunctionInfo(
951 name, MaybeHandle<Code>(), false);
952 int params = static_cast<int>(func.sig->parameter_count());
953 shared->set_length(params);
954 shared->set_internal_formal_parameter_count(params);
955 Handle<JSFunction> function = isolate->factory()->NewFunction(
956 isolate->native_function_map(), name, MaybeHandle<Code>());
957 // function->SetInternalField(0, *module_object);
958 function->set_shared(*shared);
959
960 //----------------------------------------------------------------------------
961 // Create the Graph
962 //----------------------------------------------------------------------------
963 Zone zone(isolate->allocator(), ZONE_NAME);
964 Graph graph(&zone);
965 CommonOperatorBuilder common(&zone);
966 MachineOperatorBuilder machine(&zone);
967 JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr, &machine);
968
969 // TODO(ofrobots): we only support 64-bit at the moment
970 CHECK(machine.Is64());
971
972 Node* control = nullptr;
973 Node* effect = nullptr;
974
975 FFIGraphBuilder builder(&zone, &jsgraph);
976 builder.set_control_ptr(&control);
977 builder.set_effect_ptr(&effect);
978 builder.BuildJSToNativeWrapper(func);
979
980 //----------------------------------------------------------------------------
981 // Run the compilation pipeline.
982 //----------------------------------------------------------------------------
983 {
984 if (FLAG_trace_turbo_graph) { // Simple textual RPO.
985 OFStream os(stdout);
986 os << "-- Graph after change lowering -- " << std::endl;
987 os << AsRPO(graph);
988 }
989
990 // Schedule and compile to machine code.
991 int params = static_cast<int>(func.sig->parameter_count());
992 CallDescriptor* incoming = Linkage::GetJSCallDescriptor(
993 &zone, false, params + 1, CallDescriptor::kNoFlags);
994 Code::Flags flags = Code::ComputeFlags(Code::JS_TO_NATIVE_FUNCTION);
995
996 int length = 0;
997 std::unique_ptr<char[]> c_str =
998 name->ToCString(DISALLOW_NULLS, FAST_STRING_TRAVERSAL, &length);
999 ScopedVector<char> buffer(32 + length);
1000 int chars = SNPrintF(buffer, "js-to-native#%s", c_str.get());
1001 Vector<const char> func_name =
1002 Vector<const char>::cast(buffer.SubVector(0, chars));
1003
1004 CompilationInfo info(func_name, isolate, &zone, flags);
1005 Handle<Code> code =
1006 Pipeline::GenerateCodeForTesting(&info, incoming, &graph);
1007 #ifdef ENABLE_DISASSEMBLER
1008 if (FLAG_print_opt_code && !code.is_null()) {
1009 OFStream os(stdout);
1010 code->Disassemble(buffer.start(), os);
1011 }
1012 #endif
1013
1014 RecordFunctionCompilation(Logger::FUNCTION_TAG, &info, "js-to-native",
1015 func_name);
1016 // Set the JSFunction's machine code.
1017 function->set_code(*code);
1018 }
1019 return function;
1020 }
1021
1022 void WriteArgs(Isolate* isolate, ffi::FFISignature* sig,
1023 Handle<JSReceiver> packed_args, char* arg_dest) {
1024 const int params = static_cast<int>(sig->parameter_count());
1025 char* write_pos = arg_dest;
1026 for (int i = 0; i < params; i++) {
1027 ffi::FFITypeElement elem = sig->GetParam(i);
1028 LookupIterator it(isolate, packed_args, i, packed_args);
1029 Handle<Object> value = Object::GetProperty(&it).ToHandleChecked();
1030 WriteObject(value, elem.type, write_pos);
1031 write_pos += TypeSize(elem.type);
1032 }
1033 }
1034
1035 void* FFIFunctionBind(Isolate* isolate, ffi::NativeFunction func,
1036 Handle<JSReceiver> packed_args) {
1037 // TODO(mattloring): free this
1038 // TODO(mattloring): compute precise size
1039 char* arguments = reinterpret_cast<char*>(malloc(64));
1040
1041 WriteArgs(isolate, func.sig, packed_args, arguments);
1042
1043 const int params = static_cast<int>(func.sig->parameter_count());
1044 const int returns = static_cast<int>(func.sig->return_count());
1045
1046 Zone zone(isolate->allocator(), ZONE_NAME);
1047 Graph graph(&zone);
1048 CommonOperatorBuilder common(&zone);
1049 MachineOperatorBuilder machine(&zone);
1050
1051 MachineType* ffi_reps = TranslateSignature(func.sig);
1052 MachineSignature ffi_mach_sig(returns, params, ffi_reps);
1053
1054 CallDescriptor* ffi_desc =
1055 Linkage::GetSimplifiedCDescriptor(&zone, &ffi_mach_sig);
1056
1057 Node* start = graph.NewNode(common.Start(4)); // 4 + param count
1058 graph.SetStart(start);
1059 Node* function = graph.NewNode(
1060 common.Int64Constant(reinterpret_cast<int64_t>(func.start)));
1061 Node** args =
1062 reinterpret_cast<Node**>(zone.New((3 + params) * sizeof(Node*)));
1063 int index = 0;
1064 args[index++] = function;
1065 char* write_pos = arguments;
1066 Node* load_effect = start;
1067 for (int i = 0; i < params; i++) {
1068 ffi::FFITypeElement elem = func.sig->GetParam(i);
1069 MachineType mach_type = FFITypeToMachineType(elem);
1070 args[index] = graph.NewNode(
1071 machine.Load(mach_type), graph.NewNode(common.Int64Constant(
1072 reinterpret_cast<int64_t>(write_pos))),
1073 graph.NewNode(common.Int64Constant(0)), load_effect, start);
1074 load_effect = args[index++];
1075 write_pos += TypeSize(elem.type);
1076 }
1077 args[index++] = load_effect;
1078 args[index++] = start;
1079 Node* call = graph.NewNode(common.Call(ffi_desc), (3 + params), args);
1080 Node* pop_size = graph.NewNode(common.Int32Constant(0));
1081 Node* ret = graph.NewNode(common.Return(), pop_size, call, call, start);
1082 graph.SetEnd(graph.NewNode(common.End(1),
1083 ret)); // No clue what this number should be.
1084
1085 MachineSignature mach_sig(1, 0, ffi_reps);
1086
1087 CallDescriptor* desc = Linkage::GetSimplifiedCDescriptor(&zone, &mach_sig);
1088
1089 Code::Flags flags = Code::ComputeFlags(Code::STUB);
1090
1091 CompilationInfo info(ArrayVector("FFIFunctionBind"), isolate, &zone, flags);
1092 Handle<Code> code = Pipeline::GenerateCodeForTesting(&info, desc, &graph);
1093 return reinterpret_cast<void*>(code->entry());
1094 }
1095
1096 void* BuildFFISerializer(Isolate* isolate, ffi::NativeFunction func) {
1097 const int params = static_cast<int>(func.sig->parameter_count());
1098
1099 Zone zone(isolate->allocator(), ZONE_NAME);
1100 Graph graph(&zone);
1101 CommonOperatorBuilder common(&zone);
1102 MachineOperatorBuilder machine(&zone);
1103
1104 Node* start = graph.NewNode(common.Start(4 + params)); // 4 + param count
1105 graph.SetStart(start);
1106
1107 // Begin Malloc Call
1108 Node** args = reinterpret_cast<Node**>(zone.New((4) * sizeof(Node*)));
1109 ExternalReference malloc_ptr(reinterpret_cast<Address>(malloc), isolate);
1110 args[0] = graph.NewNode(common.ExternalConstant(malloc_ptr));
1111 // TODO(mattloring): compute precise size
1112 args[1] = graph.NewNode(common.Int32Constant(64));
1113 args[2] = start;
1114 args[3] = start;
1115 MachineType malloc_reps[] = {MachineType::Pointer(), MachineType::Int32()};
1116 MachineSignature malloc_sig(1, 1, malloc_reps);
1117 CallDescriptor* malloc_desc =
1118 Linkage::GetSimplifiedCDescriptor(&zone, &malloc_sig);
1119
1120 Node* malloc_call = graph.NewNode(common.Call(malloc_desc), 4, args);
1121 Node* malloc_control = graph.NewNode(common.IfSuccess(), malloc_call);
1122 // End Malloc Call
1123
1124 Node* store_effect = malloc_call;
1125 int write_offset = 0;
1126 for (int i = 0; i < params; i++) {
1127 ffi::FFITypeElement elem = func.sig->GetParam(i);
1128 MachineType mach_type = FFITypeToMachineType(elem);
1129 Node* param = graph.NewNode(common.Parameter(i, "%param"), start);
1130 store_effect = graph.NewNode(
1131 machine.Store(
1132 StoreRepresentation(mach_type.representation(), kNoWriteBarrier)),
1133 malloc_call, graph.NewNode(common.Int64Constant(write_offset)), param,
1134 store_effect, malloc_control);
1135 write_offset += TypeSize(elem.type);
1136 }
1137 Node* ret =
1138 graph.NewNode(common.Return(), graph.NewNode(common.Int32Constant(0)),
1139 malloc_call, store_effect, malloc_control);
1140 graph.SetEnd(graph.NewNode(common.End(1),
1141 ret)); // No clue what this number should be.
1142
1143 MachineSignature::Builder builder(&zone, 1, params);
1144 builder.AddReturn(MachineType::Pointer()); // Pointer to the argument storage
1145 for (int i = 0; i < params; i++) {
1146 builder.AddParam(FFITypeToMachineType(func.sig->GetParam(i)));
1147 }
1148 MachineSignature* mach_sig = builder.Build();
1149 CallDescriptor* desc = Linkage::GetSimplifiedCDescriptor(&zone, mach_sig);
1150
1151 Code::Flags flags = Code::ComputeFlags(Code::STUB);
1152
1153 CompilationInfo info(ArrayVector("FFISerialize"), isolate, &zone, flags);
1154 Handle<Code> code = Pipeline::GenerateCodeForTesting(&info, desc, &graph);
1155 return reinterpret_cast<void*>(code->entry());
1156 }
1157
1158 void* BuildFFIDeserializedExecutor(Isolate* isolate, ffi::NativeFunction func) {
1159 const int params = static_cast<int>(func.sig->parameter_count());
1160 const int returns = static_cast<int>(func.sig->return_count());
1161
1162 Zone zone(isolate->allocator(), ZONE_NAME);
1163 Graph graph(&zone);
1164 CommonOperatorBuilder common(&zone);
1165 MachineOperatorBuilder machine(&zone);
1166
1167 MachineType* ffi_reps = TranslateSignature(func.sig);
1168 MachineSignature ffi_mach_sig(returns, params, ffi_reps);
1169
1170 CallDescriptor* ffi_desc =
1171 Linkage::GetSimplifiedCDescriptor(&zone, &ffi_mach_sig);
1172
1173 Node* start = graph.NewNode(common.Start(4 + 1)); // 4 + param count
1174 graph.SetStart(start);
1175 Node* function = graph.NewNode(
1176 common.Int64Constant(reinterpret_cast<int64_t>(func.start)));
1177 Node** args =
1178 reinterpret_cast<Node**>(zone.New((3 + params) * sizeof(Node*)));
1179 int index = 0;
1180 args[index++] = function;
1181 int load_offset = 0;
1182 Node* load_effect = start;
1183 for (int i = 0; i < params; i++) {
1184 ffi::FFITypeElement elem = func.sig->GetParam(i);
1185 MachineType mach_type = FFITypeToMachineType(elem);
1186 Node* base = graph.NewNode(common.Parameter(0, "%param"), start);
1187 args[index] = graph.NewNode(
1188 machine.Load(mach_type), base,
1189 graph.NewNode(common.Int64Constant(load_offset)), load_effect, start);
1190 load_effect = args[index++];
1191 load_offset += TypeSize(elem.type);
1192 }
1193 args[index++] = load_effect;
1194 args[index++] = start;
1195 Node* call = graph.NewNode(common.Call(ffi_desc), (3 + params), args);
1196 Node* call_control = graph.NewNode(common.IfSuccess(), call);
1197
1198 // Begin Free Call
1199 Node** free_args = reinterpret_cast<Node**>(zone.New((4) * sizeof(Node*)));
1200 ExternalReference free_ptr(reinterpret_cast<Address>(free), isolate);
1201 free_args[0] = graph.NewNode(common.ExternalConstant(free_ptr));
1202 free_args[1] = graph.NewNode(common.Parameter(0, "%param"), start);
1203 free_args[2] = call;
1204 free_args[3] = call_control;
1205 MachineType free_reps[] = {MachineType::Pointer()};
1206 MachineSignature free_sig(0, 1, free_reps);
1207 CallDescriptor* free_desc =
1208 Linkage::GetSimplifiedCDescriptor(&zone, &free_sig);
1209
1210 Node* free_call = graph.NewNode(common.Call(free_desc), 4, free_args);
1211 Node* free_control = graph.NewNode(common.IfSuccess(), free_call);
1212 // End Free Call
1213
1214 Node* pop_size = graph.NewNode(common.Int32Constant(0));
1215 Node* ret =
1216 graph.NewNode(common.Return(), pop_size, call, free_call, free_control);
1217 graph.SetEnd(graph.NewNode(common.End(1),
1218 ret)); // No clue what this number should be.
1219
1220 MachineSignature::Builder builder(&zone, 1, 1);
1221 builder.AddParam(MachineType::Pointer());
1222 builder.AddReturn(ffi_mach_sig.GetReturn(0));
1223 MachineSignature* mach_sig = builder.Build();
1224
1225 CallDescriptor* desc = Linkage::GetSimplifiedCDescriptor(&zone, mach_sig);
1226
1227 Code::Flags flags = Code::ComputeFlags(Code::STUB);
1228
1229 CompilationInfo info(ArrayVector("FFIFunctionDeserialize"), isolate, &zone,
1230 flags);
1231 Handle<Code> code = Pipeline::GenerateCodeForTesting(&info, desc, &graph);
1232 return reinterpret_cast<void*>(code->entry());
1233 }
1234
1235 } // namespace compiler
1236 } // namespace internal
1237 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/ffi-compiler.h ('k') | src/contexts.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698