| Index: src/runtime/runtime-ffi.cc
|
| diff --git a/src/runtime/runtime-ffi.cc b/src/runtime/runtime-ffi.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..8d047f472f1e3434dea334c1c8a6c678220dbeef
|
| --- /dev/null
|
| +++ b/src/runtime/runtime-ffi.cc
|
| @@ -0,0 +1,267 @@
|
| +// Copyright 2016 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/runtime/runtime-utils.h"
|
| +
|
| +#include "src/arguments.h"
|
| +#include "src/assembler.h"
|
| +#include "src/code-factory.h"
|
| +#include "src/compilation-info.h"
|
| +#include "src/compiler/common-operator.h"
|
| +#include "src/compiler/ffi-compiler.h"
|
| +#include "src/compiler/graph.h"
|
| +#include "src/compiler/js-graph.h"
|
| +#include "src/compiler/linkage.h"
|
| +#include "src/compiler/machine-operator.h"
|
| +#include "src/compiler/pipeline.h"
|
| +
|
| +namespace v8 {
|
| +namespace internal {
|
| +
|
| +using namespace v8::internal::compiler;
|
| +
|
| +#define WORD_SIZE 8
|
| +
|
| +// TODO(mattloring): need pool per function, not global
|
| +List<char *> mem_pool(10);
|
| +std::map<int, void *> callback_compilations;
|
| +
|
| +static int StructSize(ffi::FFIStructSignature *sig) {
|
| + int total_size = 0;
|
| + int curr_alignment = 0;
|
| + for (size_t i = 0; i < sig->elem_count; i++) {
|
| + int elem_size = TypeSize(sig->elems[i].type->type);
|
| + // Account for padding
|
| + if (elem_size + curr_alignment > WORD_SIZE) {
|
| + total_size += WORD_SIZE - curr_alignment;
|
| + curr_alignment = 0;
|
| + }
|
| + curr_alignment += elem_size;
|
| + total_size += elem_size;
|
| + }
|
| + return total_size;
|
| +}
|
| +
|
| +RUNTIME_FUNCTION(Runtime_JSStringToCharPtr) {
|
| + HandleScope scope(isolate);
|
| + DCHECK_EQ(1, args.length());
|
| + Handle<String> string;
|
| + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| + isolate, string, Object::ToString(isolate, args.at<Object>(0)));
|
| + int length = string->length() + 1;
|
| + char *str = reinterpret_cast<char *>(malloc(length));
|
| + snprintf(str, length, "%s", ((*string)->ToCString()).release());
|
| + mem_pool.Add(str);
|
| + // TODO(mattloring): should this be a foreign somehow? this cast is not
|
| + // correct
|
| + return reinterpret_cast<Object *>(str);
|
| +}
|
| +
|
| +RUNTIME_FUNCTION(Runtime_TypedArrayToUint8Ptr) {
|
| + HandleScope scope(isolate);
|
| + DCHECK_EQ(1, args.length());
|
| + CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, input_obj, 0);
|
| + Handle<JSTypedArray> array(JSTypedArray::cast(*input_obj));
|
| + uint8_t *contents =
|
| + reinterpret_cast<uint8_t *>(array->GetBuffer()->backing_store());
|
| + size_t offset = NumberToSize(array->byte_offset());
|
| + size_t length = NumberToSize(array->byte_length());
|
| + char *result = reinterpret_cast<char *>(malloc(length));
|
| + memcpy(result, contents + offset, length);
|
| + mem_pool.Add(result);
|
| + // TODO(mattloring): should this be a foreign somehow? this cast is not
|
| + // correct
|
| + return reinterpret_cast<Object *>(result);
|
| +}
|
| +
|
| +RUNTIME_FUNCTION(Runtime_BufferToPtrNoCopy) {
|
| + HandleScope scope(isolate);
|
| + DCHECK_EQ(1, args.length());
|
| + CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, input_obj, 0);
|
| + Handle<JSTypedArray> array(JSTypedArray::cast(*input_obj));
|
| + uint8_t *contents =
|
| + reinterpret_cast<uint8_t *>(array->GetBuffer()->backing_store());
|
| + size_t offset = NumberToSize(array->byte_offset());
|
| + // TODO(mattloring): should this be a foreign somehow? this cast is not
|
| + // correct
|
| + return reinterpret_cast<Object *>(contents + offset);
|
| +}
|
| +
|
| +RUNTIME_FUNCTION(Runtime_CharPtrToJSString) {
|
| + HandleScope scope(isolate);
|
| + DCHECK_EQ(1, args.length());
|
| + char *str = reinterpret_cast<char *>(args[0]);
|
| + Handle<String> name = isolate->factory()->InternalizeUtf8String(str);
|
| + free(str);
|
| + return *name;
|
| +}
|
| +
|
| +static void CallNoReturn(Isolate *isolate, Object *callable, Object *receiver,
|
| + int argc, Object *argv[]) {
|
| + HandleScope scope(isolate);
|
| + Handle<Object> call_handle(callable, isolate);
|
| + Handle<Object> rec_handle(receiver, isolate);
|
| + Handle<Object> *argv_handles = new Handle<Object>[ argc ];
|
| + for (int i = 0; i < argc; i++) {
|
| + Handle<Object> arg_handle(argv[i], isolate);
|
| + argv_handles[i] = arg_handle;
|
| + }
|
| + // TODO(mattloring): retrieve return value instead of USE
|
| + USE(i::Execution::Call(isolate, call_handle, rec_handle, argc, argv_handles));
|
| +}
|
| +
|
| +RUNTIME_FUNCTION(Runtime_JSFunctionToFnPtr) {
|
| + HandleScope scope(isolate);
|
| + DCHECK_EQ(2, args.length());
|
| + CONVERT_ARG_HANDLE_CHECKED(JSFunction, input_obj, 0);
|
| + Handle<JSFunction> func(JSFunction::cast(*input_obj));
|
| +
|
| + if (callback_compilations[func->shared()->start_position()]) {
|
| + // Use cached result
|
| + // TODO(mattloring): cache on better property than start position
|
| + return reinterpret_cast<Object *>(
|
| + callback_compilations[func->shared()->start_position()]);
|
| + }
|
| +
|
| + ffi::FFISignature *sig = reinterpret_cast<ffi::FFISignature *>(args[1]);
|
| + Zone zone(isolate->allocator(), ZONE_NAME);
|
| + Graph graph(&zone);
|
| + CommonOperatorBuilder common(&zone);
|
| + MachineOperatorBuilder machine(&zone);
|
| + JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr, &machine);
|
| +
|
| + int param_count = static_cast<int>(sig->parameter_count());
|
| +
|
| + MachineType invoke_reps[] = {MachineType::Pointer(), MachineType::Pointer(),
|
| + MachineType::Pointer(), MachineType::Int64(),
|
| + MachineType::Pointer()};
|
| + MachineSignature invoke_sig(0, 5, invoke_reps);
|
| + CallDescriptor *invoke_desc =
|
| + Linkage::GetSimplifiedCDescriptor(&zone, &invoke_sig);
|
| +
|
| + // Unmarshall arguments coming from C going to JS
|
| + // Marshall value returned from JS back to C
|
| + Node *start =
|
| + graph.NewNode(common.Start(3 + param_count)); // 4 + param count
|
| +
|
| + FFIGraphBuilder builder(&zone, &jsgraph);
|
| + builder.set_control_ptr(&start);
|
| + builder.set_effect_ptr(&start);
|
| +
|
| + graph.SetStart(start);
|
| +
|
| + Node *context = jsgraph.HeapConstant(Handle<Context>(func->context()));
|
| + Object **call_args = new Object *[param_count];
|
| + Node *call_args_node = graph.NewNode(common.ExternalConstant(
|
| + ExternalReference(reinterpret_cast<Address>(call_args), isolate)));
|
| + Node *prev_arg_translation = start;
|
| + if (param_count > 0) {
|
| + for (int i = 0; i < param_count; i++) { // Arguments
|
| + Node *translated_param = builder.ToJS(
|
| + graph.NewNode(common.Parameter(i), start), context, sig->GetParam(i));
|
| + prev_arg_translation = graph.NewNode(
|
| + machine.Store(StoreRepresentation(
|
| + MachineRepresentation::kTaggedPointer, kNoWriteBarrier)),
|
| + call_args_node, jsgraph.Int32Constant(i), translated_param,
|
| + prev_arg_translation, start);
|
| + }
|
| + }
|
| +
|
| + int index = 0;
|
| + Node **arguments = zone.NewArray<Node *>(8);
|
| + arguments[index++] = graph.NewNode(
|
| + common.Int64Constant(reinterpret_cast<int64_t>(&CallNoReturn)));
|
| + arguments[index++] = graph.NewNode(common.ExternalConstant(
|
| + ExternalReference(reinterpret_cast<Address>(isolate), isolate)));
|
| + arguments[index++] = jsgraph.HeapConstant(func);
|
| + arguments[index++] = jsgraph.UndefinedConstant();
|
| + arguments[index++] = jsgraph.Int64Constant(param_count);
|
| + arguments[index++] = call_args_node;
|
| + arguments[index++] = prev_arg_translation;
|
| + arguments[index++] = start;
|
| + Node *call = graph.NewNode(common.Call(invoke_desc), index, arguments);
|
| + Node *call_control = graph.NewNode(common.IfSuccess(), call);
|
| + // TODO(mattloring): retval = call;
|
| + Node *retval = jsgraph.Constant(42);
|
| + if (sig->return_count() != 0) {
|
| + retval = builder.FromJS(retval, context, sig->GetReturn());
|
| + }
|
| + Node *ret = graph.NewNode(common.Return(), jsgraph.Int32Constant(0), retval,
|
| + call, call_control);
|
| + graph.SetEnd(graph.NewNode(common.End(1), ret));
|
| +
|
| + MachineType *reps = builder.GetMachineTypes(sig);
|
| + MachineSignature mach_sig(sig->return_count(), param_count, reps);
|
| +
|
| + CallDescriptor *desc = Linkage::GetSimplifiedCDescriptor(&zone, &mach_sig);
|
| +
|
| + Code::Flags flags = Code::ComputeFlags(Code::STUB);
|
| +
|
| + CompilationInfo info(ArrayVector("js-to-native-cb"), jsgraph.isolate(), &zone,
|
| + flags);
|
| + Handle<Code> code = Pipeline::GenerateCodeForTesting(&info, desc, &graph);
|
| + callback_compilations[func->shared()->start_position()] = code->entry();
|
| + // TODO(mattloring): should this be a foreign somehow? this cast is not
|
| + // correct
|
| + return reinterpret_cast<Object *>(code->entry());
|
| +}
|
| +
|
| +RUNTIME_FUNCTION(Runtime_JSObjectToStructPtr) {
|
| + HandleScope scope(isolate);
|
| + DCHECK_EQ(2, args.length());
|
| + Handle<JSObject> obj(JSObject::cast(args[0]));
|
| + ffi::FFIStructSignature *sig =
|
| + reinterpret_cast<ffi::FFIStructSignature *>(args[1]);
|
| + char *result = reinterpret_cast<char *>(malloc(StructSize(sig)));
|
| + char *write_pos = result;
|
| + int alignment = 0;
|
| + for (size_t i = 0; i < sig->elem_count; i++) {
|
| + v8::ffi::FFIStructElement elem = sig->elems[i];
|
| + int elem_size = TypeSize(elem.type->type);
|
| + Handle<String> name = isolate->factory()->InternalizeUtf8String(elem.name);
|
| + LookupIterator it(obj, name);
|
| + Handle<Object> value = Object::GetProperty(&it).ToHandleChecked();
|
| + if (elem_size + alignment > WORD_SIZE) {
|
| + memset(write_pos, 0, WORD_SIZE - alignment);
|
| + write_pos += (WORD_SIZE - alignment);
|
| + alignment = 0;
|
| + }
|
| + WriteObject(value, elem.type->type, write_pos);
|
| + write_pos += elem_size;
|
| + alignment += elem_size;
|
| + }
|
| + mem_pool.Add(result);
|
| + // TODO(mattloring): should this be a foreign somehow? this cast is not
|
| + // correct
|
| + return reinterpret_cast<Object *>(result);
|
| +}
|
| +
|
| +RUNTIME_FUNCTION(Runtime_PointerToForeign) {
|
| + HandleScope scope(isolate);
|
| + DCHECK_EQ(1, args.length());
|
| + intptr_t *ptr = reinterpret_cast<intptr_t *>(args[0]);
|
| + Handle<Foreign> foreign =
|
| + isolate->factory()->NewForeign(reinterpret_cast<Address>(ptr));
|
| + return *foreign;
|
| +}
|
| +
|
| +RUNTIME_FUNCTION(Runtime_ForeignToPointer) {
|
| + HandleScope scope(isolate);
|
| + DCHECK_EQ(1, args.length());
|
| + Handle<Foreign> foreign(Foreign::cast(args[0]));
|
| + // TODO(mattloring): should this be a foreign somehow? this cast is not
|
| + // correct
|
| + return reinterpret_cast<Object *>(foreign->foreign_address());
|
| +}
|
| +
|
| +RUNTIME_FUNCTION(Runtime_ReleaseFFIMemPool) {
|
| + HandleScope scope(isolate);
|
| + for (char *addr : mem_pool) {
|
| + free(addr);
|
| + }
|
| + mem_pool.Clear();
|
| + return isolate->heap()->ToBoolean(true);
|
| +}
|
| +} // namespace internal
|
| +} // namespace v8
|
|
|