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

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

Issue 2084663004: WIP: prototype ffi support Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 6 months 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/compiler/ffi-compiler.h ('k') | src/contexts.h » ('j') | src/objects.h » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/compiler/ffi-compiler.cc
diff --git a/src/compiler/ffi-compiler.cc b/src/compiler/ffi-compiler.cc
new file mode 100644
index 0000000000000000000000000000000000000000..2148c52e687a21052f6aa2d7b47d9e4da4374886
--- /dev/null
+++ b/src/compiler/ffi-compiler.cc
@@ -0,0 +1,622 @@
+// 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/compiler/ffi-compiler.h"
+
+#include "src/isolate-inl.h"
+
+#include "src/code-factory.h"
+#include "src/compiler/access-builder.h"
+#include "src/compiler/common-operator.h"
+#include "src/compiler/graph-visualizer.h"
+#include "src/compiler/graph.h"
+#include "src/compiler/js-graph.h"
+#include "src/compiler/js-operator.h"
+#include "src/compiler/linkage.h"
+#include "src/compiler/pipeline.h"
+#include "src/factory.h"
+#include "src/profiler/cpu-profiler.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+namespace {
+
+// TODO(ofrobots): duplicated from wasm-compiler.cc
+static void MergeControlToEnd(JSGraph* jsgraph, Node* node) {
+ Graph* g = jsgraph->graph();
+ if (g->end()) {
+ NodeProperties::MergeControlToEnd(g, jsgraph->common(), node);
+ } else {
+ g->SetEnd(g->NewNode(jsgraph->common()->End(1), node));
+ }
+}
+
+} // namespace
+
+FFIGraphBuilder::FFIGraphBuilder(Zone* zone, JSGraph* jsgraph)
+ : zone_(zone),
+ jsgraph_(jsgraph),
+ control_(nullptr),
+ effect_(nullptr),
+ cur_buffer_(def_buffer_),
+ cur_bufsize_(kDefaultBufferSize) {
+ DCHECK_NOT_NULL(jsgraph_);
+}
+
+Node* FFIGraphBuilder::Start(unsigned params) {
+ Node* start = graph()->NewNode(jsgraph()->common()->Start(params));
+ graph()->SetStart(start);
+ return start;
+}
+
+Node* FFIGraphBuilder::BuildCCall(MachineSignature* sig, Node** args) {
+ const size_t params = sig->parameter_count();
+ const size_t extra = 2; // effect and control inputs.
+ const size_t count = 1 + params + extra;
+
+ // Reallocate the buffer to make space for extra inputs.
+ args = Realloc(args, 1 + params, count);
+
+ // Add effect and control inputs.
+ args[params + 1] = *effect_;
+ args[params + 2] = *control_;
+
+ CallDescriptor* desc =
+ Linkage::GetSimplifiedCDescriptor(jsgraph()->zone(), sig);
+
+ const Operator* op = jsgraph()->common()->Call(desc);
+ Node* call = graph()->NewNode(op, static_cast<int>(count), args);
+ *effect_ = call;
+ return call;
+}
+
+Node* FFIGraphBuilder::BuildChangeInt32ToTagged(Node* value) {
+ MachineOperatorBuilder* machine = jsgraph()->machine();
+ CommonOperatorBuilder* common = jsgraph()->common();
+
+ if (machine->Is64()) {
+ return BuildChangeInt32ToSmi(value);
+ }
+
+ Node* add = graph()->NewNode(machine->Int32AddWithOverflow(), value, value);
+
+ Node* ovf = graph()->NewNode(common->Projection(1), add);
+ Node* branch = graph()->NewNode(common->Branch(BranchHint::kFalse), ovf,
+ graph()->start());
+
+ Node* if_true = graph()->NewNode(common->IfTrue(), branch);
+ Node* vtrue = BuildAllocateHeapNumberWithValue(
+ graph()->NewNode(machine->ChangeInt32ToFloat64(), value), if_true);
+
+ Node* if_false = graph()->NewNode(common->IfFalse(), branch);
+ Node* vfalse = graph()->NewNode(common->Projection(0), add);
+
+ Node* merge = graph()->NewNode(common->Merge(2), if_true, if_false);
+ Node* phi = graph()->NewNode(common->Phi(MachineRepresentation::kTagged, 2),
+ vtrue, vfalse, merge);
+ return phi;
+}
+
+Node* FFIGraphBuilder::BuildChangeFloat64ToTagged(Node* value) {
+ MachineOperatorBuilder* machine = jsgraph()->machine();
+ CommonOperatorBuilder* common = jsgraph()->common();
+
+ Node* value32 = graph()->NewNode(machine->RoundFloat64ToInt32(), value);
+ Node* check_same = graph()->NewNode(
+ machine->Float64Equal(), value,
+ graph()->NewNode(machine->ChangeInt32ToFloat64(), value32));
+ Node* branch_same =
+ graph()->NewNode(common->Branch(), check_same, graph()->start());
+
+ Node* if_smi = graph()->NewNode(common->IfTrue(), branch_same);
+ Node* vsmi;
+ Node* if_box = graph()->NewNode(common->IfFalse(), branch_same);
+ Node* vbox;
+
+ // We only need to check for -0 if the {value} can potentially contain -0.
+ Node* check_zero = graph()->NewNode(machine->Word32Equal(), value32,
+ jsgraph()->Int32Constant(0));
+ Node* branch_zero =
+ graph()->NewNode(common->Branch(BranchHint::kFalse), check_zero, if_smi);
+
+ Node* if_zero = graph()->NewNode(common->IfTrue(), branch_zero);
+ Node* if_notzero = graph()->NewNode(common->IfFalse(), branch_zero);
+
+ // In case of 0, we need to check the high bits for the IEEE -0 pattern.
+ Node* check_negative = graph()->NewNode(
+ machine->Int32LessThan(),
+ graph()->NewNode(machine->Float64ExtractHighWord32(), value),
+ jsgraph()->Int32Constant(0));
+ Node* branch_negative = graph()->NewNode(common->Branch(BranchHint::kFalse),
+ check_negative, if_zero);
+
+ Node* if_negative = graph()->NewNode(common->IfTrue(), branch_negative);
+ Node* if_notnegative = graph()->NewNode(common->IfFalse(), branch_negative);
+
+ // We need to create a box for negative 0.
+ if_smi = graph()->NewNode(common->Merge(2), if_notzero, if_notnegative);
+ if_box = graph()->NewNode(common->Merge(2), if_box, if_negative);
+
+ // On 64-bit machines we can just wrap the 32-bit integer in a smi, for 32-bit
+ // machines we need to deal with potential overflow and fallback to boxing.
+ if (machine->Is64()) {
+ vsmi = BuildChangeInt32ToSmi(value32);
+ } else {
+ Node* smi_tag =
+ graph()->NewNode(machine->Int32AddWithOverflow(), value32, value32);
+
+ Node* check_ovf = graph()->NewNode(common->Projection(1), smi_tag);
+ Node* branch_ovf =
+ graph()->NewNode(common->Branch(BranchHint::kFalse), check_ovf, if_smi);
+
+ Node* if_ovf = graph()->NewNode(common->IfTrue(), branch_ovf);
+ if_box = graph()->NewNode(common->Merge(2), if_ovf, if_box);
+
+ if_smi = graph()->NewNode(common->IfFalse(), branch_ovf);
+ vsmi = graph()->NewNode(common->Projection(0), smi_tag);
+ }
+
+ // Allocate the box for the {value}.
+ vbox = BuildAllocateHeapNumberWithValue(value, if_box);
+
+ Node* control = graph()->NewNode(common->Merge(2), if_smi, if_box);
+ value = graph()->NewNode(common->Phi(MachineRepresentation::kTagged, 2), vsmi,
+ vbox, control);
+ return value;
+}
+
+Node* FFIGraphBuilder::ToJS(Node* node, Node* context, MachineType type) {
+ switch (type.representation()) {
+ case MachineRepresentation::kWord32:
+ return BuildChangeInt32ToTagged(node);
+ case MachineRepresentation::kWord64:
+ // TODO(titzer): i64->JS has no good solution right now. Using lower 32
+ // bits.
+ if (jsgraph()->machine()->Is64()) {
+ // On 32 bit platforms we do not have to do the truncation because the
+ // node we get in as a parameter only contains the low word anyways.
+ node = graph()->NewNode(jsgraph()->machine()->TruncateInt64ToInt32(),
+ node);
+ }
+ return BuildChangeInt32ToTagged(node);
+ case MachineRepresentation::kFloat32:
+ node = graph()->NewNode(jsgraph()->machine()->ChangeFloat32ToFloat64(),
+ node);
+ return BuildChangeFloat64ToTagged(node);
+ case MachineRepresentation::kFloat64:
+ return BuildChangeFloat64ToTagged(node);
+ default:
+ UNREACHABLE();
+ return nullptr;
+ }
+}
+
+Node* FFIGraphBuilder::BuildJavaScriptToNumber(Node* node, Node* context,
+ Node* effect, Node* control) {
+ Callable callable = CodeFactory::ToNumber(jsgraph()->isolate());
+ CallDescriptor* desc = Linkage::GetStubCallDescriptor(
+ jsgraph()->isolate(), jsgraph()->zone(), callable.descriptor(), 0,
+ CallDescriptor::kNoFlags, Operator::kNoProperties);
+ Node* stub_code = jsgraph()->HeapConstant(callable.code());
+
+ Node* result = graph()->NewNode(jsgraph()->common()->Call(desc), stub_code,
+ node, context, effect, control);
+
+ *control_ = result;
+ *effect_ = result;
+
+ return result;
+}
+
+static bool CanCover(Node* value, IrOpcode::Value opcode) {
Benedikt Meurer 2016/06/21 03:26:01 You don't need this helper (see below).
ofrobots 2016/06/23 01:02:51 Acknowledged.
+ if (value->opcode() != opcode) return false;
+ bool first = true;
+ for (Edge const edge : value->use_edges()) {
+ if (NodeProperties::IsControlEdge(edge)) continue;
+ if (NodeProperties::IsEffectEdge(edge)) continue;
+ DCHECK(NodeProperties::IsValueEdge(edge));
+ if (!first) return false;
+ first = false;
+ }
+ return true;
+}
+
+Node* FFIGraphBuilder::BuildChangeTaggedToInt32(Node* value) {
+ CommonOperatorBuilder* common = jsgraph()->common();
+
+ Node* check = BuildTestNotSmi(value);
+ Node* branch = graph()->NewNode(common->Branch(BranchHint::kFalse), check,
+ graph()->start());
+
+ Node* if_smi = graph()->NewNode(common->IfFalse(), branch);
+ Node* vfrom_smi = BuildChangeSmiToInt32(value);
+
+ // TODO(ofrobots): the not_smi path is too ugly and slow at the moment
+ Node* if_not_smi = graph()->NewNode(common->IfTrue(), branch);
+ Node* vfloat = BuildChangeTaggedToFloat64(value);
+ Node* vnot_smi =
+ graph()->NewNode(jsgraph()->machine()->TruncateFloat64ToWord32(), vfloat);
+
+ Node* merge = graph()->NewNode(common->Merge(2), if_not_smi, if_smi);
+ Node* phi = graph()->NewNode(common->Phi(MachineRepresentation::kWord32, 2),
+ vnot_smi, vfrom_smi, merge);
+ return phi;
+}
+
+Node* FFIGraphBuilder::BuildChangeTaggedToFloat64(Node* value) {
+ MachineOperatorBuilder* machine = jsgraph()->machine();
+ CommonOperatorBuilder* common = jsgraph()->common();
+
+ if (CanCover(value, IrOpcode::kJSToNumber)) {
Benedikt Meurer 2016/06/21 03:26:01 You don't need this magic. It will never trigger a
ofrobots 2016/06/23 01:02:51 Acknowledged.
+ // ChangeTaggedToFloat64(JSToNumber(x)) =>
+ // if IsSmi(x) then ChangeSmiToFloat64(x)
+ // else let y = JSToNumber(x) in
+ // if IsSmi(y) then ChangeSmiToFloat64(y)
+ // else BuildLoadHeapNumberValue(y)
+ Node* object = NodeProperties::GetValueInput(value, 0);
+ Node* context = NodeProperties::GetContextInput(value);
+ Node* frame_state = NodeProperties::GetFrameStateInput(value, 0);
+ Node* effect = NodeProperties::GetEffectInput(value);
+ Node* control = NodeProperties::GetControlInput(value);
+
+ const Operator* merge_op = common->Merge(2);
+ const Operator* ephi_op = common->EffectPhi(2);
+ const Operator* phi_op = common->Phi(MachineRepresentation::kFloat64, 2);
+
+ Node* check1 = BuildTestNotSmi(object);
+ Node* branch1 =
+ graph()->NewNode(common->Branch(BranchHint::kFalse), check1, control);
+
+ Node* if_true1 = graph()->NewNode(common->IfTrue(), branch1);
+ Node* vtrue1 = graph()->NewNode(value->op(), object, context, frame_state,
+ effect, if_true1);
+ Node* etrue1 = vtrue1;
+
+ Node* check2 = BuildTestNotSmi(vtrue1);
+ Node* branch2 = graph()->NewNode(common->Branch(), check2, if_true1);
+
+ Node* if_true2 = graph()->NewNode(common->IfTrue(), branch2);
+ Node* vtrue2 = BuildLoadHeapNumberValue(vtrue1, if_true2);
+
+ Node* if_false2 = graph()->NewNode(common->IfFalse(), branch2);
+ Node* vfalse2 = BuildChangeSmiToFloat64(vtrue1);
+
+ if_true1 = graph()->NewNode(merge_op, if_true2, if_false2);
+ vtrue1 = graph()->NewNode(phi_op, vtrue2, vfalse2, if_true1);
+
+ Node* if_false1 = graph()->NewNode(common->IfFalse(), branch1);
+ Node* vfalse1 = BuildChangeSmiToFloat64(object);
+ Node* efalse1 = effect;
+
+ Node* merge1 = graph()->NewNode(merge_op, if_true1, if_false1);
+ Node* ephi1 = graph()->NewNode(ephi_op, etrue1, efalse1, merge1);
+ Node* phi1 = graph()->NewNode(phi_op, vtrue1, vfalse1, merge1);
+
+ // Wire the new diamond into the graph, {JSToNumber} can still throw.
+ NodeProperties::ReplaceUses(value, phi1, ephi1, etrue1, etrue1);
+
+ // TODO(mstarzinger): This iteration cuts out the IfSuccess projection from
+ // the node and places it inside the diamond. Come up with a helper method!
+ for (Node* use : etrue1->uses()) {
+ if (use->opcode() == IrOpcode::kIfSuccess) {
+ use->ReplaceUses(merge1);
+ NodeProperties::ReplaceControlInput(branch2, use);
+ }
+ }
+ return phi1;
+ }
+
+ Node* check = BuildTestNotSmi(value);
+ Node* branch = graph()->NewNode(common->Branch(BranchHint::kFalse), check,
+ graph()->start());
+
+ Node* if_not_smi = graph()->NewNode(common->IfTrue(), branch);
+
+ Node* vnot_smi;
+ Node* check_undefined = graph()->NewNode(machine->WordEqual(), value,
+ jsgraph()->UndefinedConstant());
+ Node* branch_undefined = graph()->NewNode(common->Branch(BranchHint::kFalse),
+ check_undefined, if_not_smi);
+
+ Node* if_undefined = graph()->NewNode(common->IfTrue(), branch_undefined);
+ Node* vundefined =
+ jsgraph()->Float64Constant(std::numeric_limits<double>::quiet_NaN());
+
+ Node* if_not_undefined =
+ graph()->NewNode(common->IfFalse(), branch_undefined);
+ Node* vheap_number = BuildLoadHeapNumberValue(value, if_not_undefined);
+
+ if_not_smi =
+ graph()->NewNode(common->Merge(2), if_undefined, if_not_undefined);
+ vnot_smi = graph()->NewNode(common->Phi(MachineRepresentation::kFloat64, 2),
+ vundefined, vheap_number, if_not_smi);
+
+ Node* if_smi = graph()->NewNode(common->IfFalse(), branch);
+ Node* vfrom_smi = BuildChangeSmiToFloat64(value);
+
+ Node* merge = graph()->NewNode(common->Merge(2), if_not_smi, if_smi);
+ Node* phi = graph()->NewNode(common->Phi(MachineRepresentation::kFloat64, 2),
+ vnot_smi, vfrom_smi, merge);
+
+ return phi;
+}
+
+Node* FFIGraphBuilder::FromJS(Node* node, Node* context, MachineType type) {
+ // Do a JavaScript ToNumber.
+ Node* num = BuildJavaScriptToNumber(node, context, *effect_, *control_);
+
+ switch (type.representation()) {
+ case MachineRepresentation::kWord32: {
+ // num = BuildChangeTaggedToFloat64(num);
+ // num = graph()->NewNode(jsgraph()->machine()->TruncateFloat64ToWord32(),
+ // num);
+ num = BuildChangeTaggedToInt32(num);
+ break;
+ }
+ // TODO(ofrobots): handle other types.
+ default:
+ UNREACHABLE();
+ return nullptr;
+ }
+ return num;
+}
+
+Node* FFIGraphBuilder::BuildChangeInt32ToSmi(Node* value) {
+ if (jsgraph()->machine()->Is64()) {
+ value = graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), value);
+ }
+ return graph()->NewNode(jsgraph()->machine()->WordShl(), value,
+ BuildSmiShiftBitsConstant());
+}
+
+Node* FFIGraphBuilder::BuildChangeSmiToInt32(Node* value) {
+ value = graph()->NewNode(jsgraph()->machine()->WordSar(), value,
+ BuildSmiShiftBitsConstant());
+ if (jsgraph()->machine()->Is64()) {
+ value =
+ graph()->NewNode(jsgraph()->machine()->TruncateInt64ToInt32(), value);
+ }
+ return value;
+}
+
+Node* FFIGraphBuilder::BuildChangeSmiToFloat64(Node* value) {
+ return graph()->NewNode(jsgraph()->machine()->ChangeInt32ToFloat64(),
+ BuildChangeSmiToInt32(value));
+}
+
+Node* FFIGraphBuilder::BuildTestNotSmi(Node* value) {
+ STATIC_ASSERT(kSmiTag == 0);
+ STATIC_ASSERT(kSmiTagMask == 1);
+ return graph()->NewNode(jsgraph()->machine()->WordAnd(), value,
+ jsgraph()->IntPtrConstant(kSmiTagMask));
+}
+
+Node* FFIGraphBuilder::BuildSmiShiftBitsConstant() {
+ return jsgraph()->IntPtrConstant(kSmiShiftSize + kSmiTagSize);
+}
+
+Node* FFIGraphBuilder::BuildAllocateHeapNumberWithValue(Node* value,
+ Node* control) {
+ MachineOperatorBuilder* machine = jsgraph()->machine();
+ CommonOperatorBuilder* common = jsgraph()->common();
+ // The AllocateHeapNumberStub does not use the context, so we can safely pass
+ // in Smi zero here.
+ Callable callable = CodeFactory::AllocateHeapNumber(jsgraph()->isolate());
+ Node* target = jsgraph()->HeapConstant(callable.code());
+ Node* context = jsgraph()->NoContextConstant();
+ Node* effect =
+ graph()->NewNode(common->BeginRegion(RegionObservability::kNotObservable),
+ graph()->start());
+ if (!allocate_heap_number_operator_.is_set()) {
+ CallDescriptor* descriptor = Linkage::GetStubCallDescriptor(
+ jsgraph()->isolate(), jsgraph()->zone(), callable.descriptor(), 0,
+ CallDescriptor::kNoFlags, Operator::kNoThrow);
+ allocate_heap_number_operator_.set(common->Call(descriptor));
+ }
+ Node* heap_number = graph()->NewNode(allocate_heap_number_operator_.get(),
+ target, context, effect, control);
+ Node* store =
+ graph()->NewNode(machine->Store(StoreRepresentation(
+ MachineRepresentation::kFloat64, kNoWriteBarrier)),
+ heap_number, BuildHeapNumberValueIndexConstant(), value,
+ heap_number, control);
+ return graph()->NewNode(common->FinishRegion(), heap_number, store);
+}
+
+Node* FFIGraphBuilder::BuildLoadHeapNumberValue(Node* value, Node* control) {
+ return graph()->NewNode(jsgraph()->machine()->Load(MachineType::Float64()),
+ value, BuildHeapNumberValueIndexConstant(),
+ graph()->start(), control);
+}
+
+Node* FFIGraphBuilder::BuildHeapNumberValueIndexConstant() {
+ return jsgraph()->IntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag);
+}
+
+void FFIGraphBuilder::BuildJSToNativeWrapper(ffi::NativeFunction func) {
+ MachineSignature* sig = func.sig;
+ int param_count;
+ // if (jsgraph()->machine()->Is64()) {
+ param_count = static_cast<int>(sig->parameter_count());
+ // } else {
+ // param_count = Int64Lowering::GetParameterCountAfterLowering(sig);
+ // }
+ int count = param_count + 1; // the function is the first arg
+ Node** args = Buffer(count);
+
+ // Build the start and the JS parameter nodes.
+ Node* start = Start(param_count + 5); // FIXME: why 5?
+ *control_ = start;
+ *effect_ = start;
+
+ // Create the context parameter.
+ Node* context = graph()->NewNode(
+ jsgraph()->common()->Parameter(
+ Linkage::GetJSCallContextParamIndex(param_count + 1), "%context"),
+ graph()->start());
+
+ int pos = 0;
+ ApiFunction api_func(func.start);
ofrobots 2016/06/23 01:02:51 Any thoughts on the abuse of 'ApiFunction' here?
Benedikt Meurer 2016/06/23 03:34:06 I think it's OK for prototyping. Long-term you'll
+ ExternalReference ref(&api_func, ExternalReference::DIRECT_API_CALL,
+ jsgraph()->isolate());
+ Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref));
+ args[pos++] = function;
+
+ // Convert JS parameters to native numbers.
+ for (int i = 0; i < param_count; i++) {
+ Node* param =
+ graph()->NewNode(jsgraph()->common()->Parameter(i + 1), start);
+ Node* native_param = FromJS(param, context, sig->GetParam(i));
+ args[pos++] = native_param;
+ }
+
+ CHECK_EQ(pos, count);
+
+ // Call the Native code.
+ Node* call = BuildCCall(sig, args);
+
+ Node* retval = call;
+ Node* jsval = ToJS(retval, context, sig->GetReturn());
+ Node* ret =
+ graph()->NewNode(jsgraph()->common()->Return(), jsval, call, start);
+
+ MergeControlToEnd(jsgraph(), ret);
+}
+
+void FFIGraphBuilder::PrintDebugName(Node* node) {
+ PrintF("#%d:%s", node->id(), node->op()->mnemonic());
+}
+
+Graph* FFIGraphBuilder::graph() { return jsgraph()->graph(); }
+
+static void RecordFunctionCompilation(Logger::LogEventsAndTags tag,
+ CompilationInfo* info,
+ const char* message,
+ Vector<const char> func_name) {
+ Isolate* isolate = info->isolate();
+ if (isolate->logger()->is_logging_code_events() ||
+ isolate->cpu_profiler()->is_profiling()) {
+ ScopedVector<char> buffer(128);
+ SNPrintF(buffer, "%s:%.*s", message, func_name.length(), func_name.start());
+ Handle<String> name_str =
+ isolate->factory()->NewStringFromAsciiChecked(buffer.start());
+ Handle<String> script_str =
+ isolate->factory()->NewStringFromAsciiChecked("(FFI)");
+ Handle<Code> code = info->code();
+ Handle<SharedFunctionInfo> shared =
+ isolate->factory()->NewSharedFunctionInfo(name_str, code, false);
+ PROFILE(isolate, CodeCreateEvent(tag, AbstractCode::cast(*code), *shared,
+ *script_str, 0, 0));
+ }
+}
+
+// TODO(ofrobots): find a better home for this.
+static void Setup(Isolate* isolate, Handle<Context> context) {
+ if (!context->get(Context::NATIVE_FUNCTION_MAP_INDEX)->IsMap()) {
+ // TODO(ofrobots): move this to boostrapper.cc??
+ Handle<Map> prev_map = Handle<Map>(context->sloppy_function_map(), isolate);
+
+ InstanceType instance_type = prev_map->instance_type();
+ int internal_fields = JSObject::GetInternalFieldCount(*prev_map);
+ CHECK_EQ(0, internal_fields);
+ int pre_allocated =
+ prev_map->GetInObjectProperties() - prev_map->unused_property_fields();
+ int instance_size;
+ int in_object_properties;
+ JSFunction::CalculateInstanceSizeHelper(instance_type, internal_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);
+ }
+}
+
+Handle<JSFunction> CompileJSToNativeWrapper(Isolate* isolate,
+ Handle<String> name,
+ ffi::NativeFunction func) {
+ Handle<Context> context(isolate->context());
+ Setup(isolate, context);
+
+ //----------------------------------------------------------------------------
+ // Create the JSFunction object.
+ //----------------------------------------------------------------------------
+ Handle<SharedFunctionInfo> shared = isolate->factory()->NewSharedFunctionInfo(
+ name, MaybeHandle<Code>(), false);
+ int params = static_cast<int>(func.sig->parameter_count());
+ shared->set_length(params);
+ shared->set_internal_formal_parameter_count(params);
+ Handle<JSFunction> function = isolate->factory()->NewFunction(
+ isolate->native_function_map(), name, MaybeHandle<Code>());
+ // function->SetInternalField(0, *module_object);
+ function->set_shared(*shared);
+
+ //----------------------------------------------------------------------------
+ // Create the Graph
+ //----------------------------------------------------------------------------
+ Zone zone(isolate->allocator());
+ Graph graph(&zone);
+ CommonOperatorBuilder common(&zone);
+ MachineOperatorBuilder machine(&zone);
+ JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr, &machine);
+
+ // TODO(ofrobots): we only support 64-bit at the moment
+ CHECK(machine.Is64());
+
+ Node* control = nullptr;
+ Node* effect = nullptr;
+
+ FFIGraphBuilder builder(&zone, &jsgraph);
+ builder.set_control_ptr(&control);
+ builder.set_effect_ptr(&effect);
+ builder.BuildJSToNativeWrapper(func);
+
+ //----------------------------------------------------------------------------
+ // Run the compilation pipeline.
+ //----------------------------------------------------------------------------
+ {
+ if (FLAG_trace_turbo_graph) { // Simple textual RPO.
+ OFStream os(stdout);
+ os << "-- Graph after change lowering -- " << std::endl;
+ os << AsRPO(graph);
+ }
+
+ // Schedule and compile to machine code.
+ int params = static_cast<int>(func.sig->parameter_count());
+ CallDescriptor* incoming = Linkage::GetJSCallDescriptor(
+ &zone, false, params + 1, CallDescriptor::kNoFlags);
+ Code::Flags flags = Code::ComputeFlags(Code::JS_TO_NATIVE_FUNCTION);
+
+ int length = 0;
+ base::SmartArrayPointer<char> c_str =
+ name->ToCString(DISALLOW_NULLS, FAST_STRING_TRAVERSAL, &length);
+ ScopedVector<char> buffer(32 + length);
+ int chars = SNPrintF(buffer, "js-to-native#%s", c_str.get());
+ Vector<const char> func_name =
+ Vector<const char>::cast(buffer.SubVector(0, chars));
+
+ CompilationInfo info(func_name, isolate, &zone, flags);
+ Handle<Code> code =
+ Pipeline::GenerateCodeForTesting(&info, incoming, &graph);
+#ifdef ENABLE_DISASSEMBLER
+ if (FLAG_print_opt_code && !code.is_null()) {
+ OFStream os(stdout);
+ code->Disassemble(buffer.start(), os);
+ }
+#endif
+
+ RecordFunctionCompilation(Logger::FUNCTION_TAG, &info, "js-to-native",
+ func_name);
+ // Set the JSFunction's machine code.
+ function->set_code(*code);
+ }
+ return function;
+}
+
+} // namespace compiler
+} // namespace internal
+} // namespace v8
« no previous file with comments | « src/compiler/ffi-compiler.h ('k') | src/contexts.h » ('j') | src/objects.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698