Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(971)

Unified Diff: src/runtime/runtime-ffi.cc

Issue 2250863002: WIP: prototype ffi support (from 2084663004) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Rebase Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/runtime/runtime.h ('k') | src/snapshot/code-serializer.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
« no previous file with comments | « src/runtime/runtime.h ('k') | src/snapshot/code-serializer.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698