• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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