1 // Copyright 2017 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/ffi/ffi-compiler.h"
6 #include "src/api.h"
7 #include "src/code-factory.h"
8 #include "src/objects-inl.h"
9
10 namespace v8 {
11 namespace internal {
12
InstallFFIMap(Isolate * isolate)13 void InstallFFIMap(Isolate* isolate) {
14 Handle<Context> context(isolate->context());
15 DCHECK(!context->get(Context::NATIVE_FUNCTION_MAP_INDEX)->IsMap());
16 Handle<Map> prev_map = Handle<Map>(context->sloppy_function_map(), isolate);
17
18 InstanceType instance_type = prev_map->instance_type();
19 int internal_fields = JSObject::GetInternalFieldCount(*prev_map);
20 CHECK_EQ(0, internal_fields);
21 int pre_allocated =
22 prev_map->GetInObjectProperties() - prev_map->unused_property_fields();
23 int instance_size;
24 int in_object_properties;
25 JSFunction::CalculateInstanceSizeHelper(
26 instance_type, internal_fields, 0, &instance_size, &in_object_properties);
27 int unused_property_fields = in_object_properties - pre_allocated;
28 Handle<Map> map = Map::CopyInitialMap(
29 prev_map, instance_size, in_object_properties, unused_property_fields);
30 context->set_native_function_map(*map);
31 }
32
33 namespace ffi {
34
35 class FFIAssembler : public CodeStubAssembler {
36 public:
FFIAssembler(CodeAssemblerState * state)37 explicit FFIAssembler(CodeAssemblerState* state) : CodeStubAssembler(state) {}
38
ToJS(Node * node,Node * context,FFIType type)39 Node* ToJS(Node* node, Node* context, FFIType type) {
40 switch (type) {
41 case FFIType::kInt32:
42 return ChangeInt32ToTagged(node);
43 }
44 UNREACHABLE();
45 return nullptr;
46 }
47
FromJS(Node * node,Node * context,FFIType type)48 Node* FromJS(Node* node, Node* context, FFIType type) {
49 switch (type) {
50 case FFIType::kInt32:
51 return TruncateTaggedToWord32(context, node);
52 }
53 UNREACHABLE();
54 return nullptr;
55 }
56
FFIToMachineType(FFIType type)57 MachineType FFIToMachineType(FFIType type) {
58 switch (type) {
59 case FFIType::kInt32:
60 return MachineType::Int32();
61 }
62 UNREACHABLE();
63 return MachineType::None();
64 }
65
FFIToMachineSignature(FFISignature * sig)66 Signature<MachineType>* FFIToMachineSignature(FFISignature* sig) {
67 Signature<MachineType>::Builder sig_builder(zone(), sig->return_count(),
68 sig->parameter_count());
69 for (size_t i = 0; i < sig->return_count(); i++) {
70 sig_builder.AddReturn(FFIToMachineType(sig->GetReturn(i)));
71 }
72 for (size_t j = 0; j < sig->parameter_count(); j++) {
73 sig_builder.AddParam(FFIToMachineType(sig->GetParam(j)));
74 }
75 return sig_builder.Build();
76 }
77
GenerateJSToNativeWrapper(NativeFunction * func)78 void GenerateJSToNativeWrapper(NativeFunction* func) {
79 int params = static_cast<int>(func->sig->parameter_count());
80 int returns = static_cast<int>(func->sig->return_count());
81 ApiFunction api_func(func->start);
82 ExternalReference ref(&api_func, ExternalReference::BUILTIN_CALL,
83 isolate());
84
85 Node* context_param = GetJSContextParameter();
86
87 Node** inputs = zone()->NewArray<Node*>(params + 1);
88 int input_count = 0;
89 inputs[input_count++] = ExternalConstant(ref);
90 for (int i = 0; i < params; i++) {
91 inputs[input_count++] =
92 FromJS(Parameter(i), context_param, func->sig->GetParam(i));
93 }
94
95 Node* call =
96 CallCFunctionN(FFIToMachineSignature(func->sig), input_count, inputs);
97 Node* return_val = UndefinedConstant();
98 if (returns == 1) {
99 return_val = ToJS(call, context_param, func->sig->GetReturn());
100 }
101 Return(return_val);
102 }
103 };
104
CompileJSToNativeWrapper(Isolate * isolate,Handle<String> name,NativeFunction func)105 Handle<JSFunction> CompileJSToNativeWrapper(Isolate* isolate,
106 Handle<String> name,
107 NativeFunction func) {
108 int params = static_cast<int>(func.sig->parameter_count());
109 Zone zone(isolate->allocator(), ZONE_NAME);
110 CodeAssemblerState state(isolate, &zone, params,
111 Code::ComputeFlags(Code::BUILTIN), "js-to-native");
112 FFIAssembler assembler(&state);
113 assembler.GenerateJSToNativeWrapper(&func);
114 Handle<Code> code = assembler.GenerateCode(&state);
115
116 Handle<SharedFunctionInfo> shared =
117 isolate->factory()->NewSharedFunctionInfo(name, code, false);
118 shared->set_length(params);
119 shared->set_internal_formal_parameter_count(params);
120 Handle<JSFunction> function = isolate->factory()->NewFunction(
121 isolate->native_function_map(), name, code);
122 function->set_shared(*shared);
123 return function;
124 }
125
126 } // namespace ffi
127 } // namespace internal
128 } // namespace v8
129