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