blob: d1b06c9ef042315412523880087c96566d923cb5 [file] [log] [blame]
// 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