Home | History | Annotate | Download | only in ffi
      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 
     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:
     37   explicit FFIAssembler(CodeAssemblerState* state) : CodeStubAssembler(state) {}
     38 
     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 
     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 
     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 
     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 
     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 
    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