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

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

Issue 2084663004: WIP: prototype ffi support Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 6 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
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 "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
OLDNEW
« no previous file with comments | « src/compiler/ffi-compiler.h ('k') | src/contexts.h » ('j') | src/objects.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698