| // Copyright 2017 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/ffi/ffi-compiler.h" |
| #include "src/api.h" |
| #include "src/code-factory.h" |
| #include "src/objects-inl.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| void InstallFFIMap(Isolate* isolate) { |
| Handle<Context> context(isolate->context()); |
| DCHECK(!context->get(Context::NATIVE_FUNCTION_MAP_INDEX)->IsMap()); |
| Handle<Map> prev_map = Handle<Map>(context->sloppy_function_map(), isolate); |
| |
| InstanceType instance_type = prev_map->instance_type(); |
| int embedder_fields = JSObject::GetEmbedderFieldCount(*prev_map); |
| CHECK_EQ(0, embedder_fields); |
| int pre_allocated = |
| prev_map->GetInObjectProperties() - prev_map->unused_property_fields(); |
| int instance_size; |
| int in_object_properties; |
| JSFunction::CalculateInstanceSizeHelper( |
| instance_type, embedder_fields, 0, &instance_size, &in_object_properties); |
| int unused_property_fields = in_object_properties - pre_allocated; |
| Handle<Map> map = Map::CopyInitialMap( |
| prev_map, instance_size, in_object_properties, unused_property_fields); |
| context->set_native_function_map(*map); |
| } |
| |
| namespace ffi { |
| |
| class FFIAssembler : public CodeStubAssembler { |
| public: |
| explicit FFIAssembler(CodeAssemblerState* state) : CodeStubAssembler(state) {} |
| |
| Node* ToJS(Node* node, Node* context, FFIType type) { |
| switch (type) { |
| case FFIType::kInt32: |
| return ChangeInt32ToTagged(node); |
| } |
| UNREACHABLE(); |
| } |
| |
| Node* FromJS(Node* node, Node* context, FFIType type) { |
| switch (type) { |
| case FFIType::kInt32: |
| return TruncateTaggedToWord32(context, node); |
| } |
| UNREACHABLE(); |
| } |
| |
| MachineType FFIToMachineType(FFIType type) { |
| switch (type) { |
| case FFIType::kInt32: |
| return MachineType::Int32(); |
| } |
| UNREACHABLE(); |
| } |
| |
| Signature<MachineType>* FFIToMachineSignature(FFISignature* sig) { |
| Signature<MachineType>::Builder sig_builder(zone(), sig->return_count(), |
| sig->parameter_count()); |
| for (size_t i = 0; i < sig->return_count(); i++) { |
| sig_builder.AddReturn(FFIToMachineType(sig->GetReturn(i))); |
| } |
| for (size_t j = 0; j < sig->parameter_count(); j++) { |
| sig_builder.AddParam(FFIToMachineType(sig->GetParam(j))); |
| } |
| return sig_builder.Build(); |
| } |
| |
| void GenerateJSToNativeWrapper(NativeFunction* func) { |
| int params = static_cast<int>(func->sig->parameter_count()); |
| int returns = static_cast<int>(func->sig->return_count()); |
| ApiFunction api_func(func->start); |
| ExternalReference ref(&api_func, ExternalReference::BUILTIN_CALL, |
| isolate()); |
| |
| Node* context_param = GetJSContextParameter(); |
| |
| Node** inputs = zone()->NewArray<Node*>(params + 1); |
| int input_count = 0; |
| inputs[input_count++] = ExternalConstant(ref); |
| for (int i = 0; i < params; i++) { |
| inputs[input_count++] = |
| FromJS(Parameter(i), context_param, func->sig->GetParam(i)); |
| } |
| |
| Node* call = |
| CallCFunctionN(FFIToMachineSignature(func->sig), input_count, inputs); |
| Node* return_val = UndefinedConstant(); |
| if (returns == 1) { |
| return_val = ToJS(call, context_param, func->sig->GetReturn()); |
| } |
| Return(return_val); |
| } |
| }; |
| |
| Handle<JSFunction> CompileJSToNativeWrapper(Isolate* isolate, |
| Handle<String> name, |
| NativeFunction func) { |
| int params = static_cast<int>(func.sig->parameter_count()); |
| Zone zone(isolate->allocator(), ZONE_NAME); |
| CodeAssemblerState state(isolate, &zone, params, Code::BUILTIN, |
| "js-to-native"); |
| FFIAssembler assembler(&state); |
| assembler.GenerateJSToNativeWrapper(&func); |
| Handle<Code> code = assembler.GenerateCode(&state); |
| |
| Handle<SharedFunctionInfo> shared = |
| isolate->factory()->NewSharedFunctionInfo(name, code, false); |
| shared->set_length(params); |
| shared->set_internal_formal_parameter_count(params); |
| Handle<JSFunction> function = isolate->factory()->NewFunction( |
| isolate->native_function_map(), name, code); |
| function->set_shared(*shared); |
| return function; |
| } |
| |
| } // namespace ffi |
| } // namespace internal |
| } // namespace v8 |