Revert "[vm/ffi] FFI callbacks on X64."
This reverts commit be209f7846e8db8ad6512f3a0d7681b2d14bced1.
Reason for revert: failures on dartkb and windows bots
Original change's description:
> [vm/ffi] FFI callbacks on X64.
>
> For context on the design, see go/dart-ffi-callbacks
>
> Change-Id: I2482e3c932e73f9a4c00fa7e218ff85f9328fc51
> Cq-Include-Trybots: luci.dart.try:vm-kernel-linux-debug-simdbc64-try, vm-kernel-linux-release-simdbc64-try, vm-kernel-mac-debug-simdbc64-try, vm-kernel-mac-release-simdbc64-try, vm-kernel-reload-mac-debug-simdbc64-try, vm-kernel-reload-mac-release-simdbc64-try, vm-kernel-linux-debug-ia32-try, vm-dartkb-linux-debug-simarm64-try
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/100240
> Commit-Queue: Samir Jindel <sjindel@google.com>
> Reviewed-by: Daco Harkes <dacoharkes@google.com>
TBR=sjindel@google.com,ajcbik@google.com,dacoharkes@google.com
Change-Id: I4cb3d93675d68a51ac9e125ad1d572c47e8b5903
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Cq-Include-Trybots: luci.dart.try:vm-kernel-linux-debug-simdbc64-try, vm-kernel-linux-release-simdbc64-try, vm-kernel-mac-debug-simdbc64-try, vm-kernel-mac-release-simdbc64-try, vm-kernel-reload-mac-debug-simdbc64-try, vm-kernel-reload-mac-release-simdbc64-try, vm-kernel-linux-debug-ia32-try, vm-dartkb-linux-debug-simarm64-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/102983
Reviewed-by: Samir Jindel <sjindel@google.com>
Commit-Queue: Samir Jindel <sjindel@google.com>
diff --git a/pkg/vm/lib/transformations/ffi_use_sites.dart b/pkg/vm/lib/transformations/ffi_use_sites.dart
index d61ca95..4b40caf 100644
--- a/pkg/vm/lib/transformations/ffi_use_sites.dart
+++ b/pkg/vm/lib/transformations/ffi_use_sites.dart
@@ -275,10 +275,9 @@
}
bool _isStatic(Expression node) {
- if (node is StaticGet) {
- return node.target is Procedure;
- }
- return node is ConstantExpression;
+ if (node is! StaticGet) return false;
+
+ return (node as StaticGet).target is Procedure;
}
}
diff --git a/runtime/bin/ffi_test_functions.cc b/runtime/bin/ffi_test_functions.cc
index 8e937f0..f1c418c 100644
--- a/runtime/bin/ffi_test_functions.cc
+++ b/runtime/bin/ffi_test_functions.cc
@@ -7,19 +7,15 @@
#include <stddef.h>
#include <stdlib.h>
#include <sys/types.h>
-#include <csignal>
#include "platform/assert.h"
#include "platform/globals.h"
-#include "vm/os_thread.h"
#if defined(HOST_OS_WINDOWS)
#include <psapi.h>
#else
#include <unistd.h>
#endif
-#include <setjmp.h>
-#include <signal.h>
#include <iostream>
#include <limits>
@@ -27,9 +23,6 @@
namespace dart {
-////////////////////////////////////////////////////////////////////////////////
-// Tests for Dart -> native calls.
-
// Sums two ints and adds 42.
// Simple function to test trampolines.
// Also used for testing argument exception on passing null instead of a Dart
@@ -456,8 +449,7 @@
return retval;
}
-////////////////////////////////////////////////////////////////////////////////
-// Functions for stress-testing.
+// Functions for stress-testing GC by returning values that require boxing.
DART_EXPORT int64_t MinInt64() {
return 0x8000000000000000;
@@ -519,213 +511,4 @@
}
#endif
-////////////////////////////////////////////////////////////////////////////////
-// Tests for callbacks.
-
-#define CHECK(X) \
- if (!(X)) { \
- fprintf(stderr, "%s\n", "Check failed: " #X); \
- return 1; \
- }
-
-#define CHECK_EQ(X, Y) CHECK((X) == (Y))
-
-// Sanity test.
-DART_EXPORT int TestSimpleAddition(int (*add)(int, int)) {
- CHECK_EQ(add(10, 20), 30);
- return 0;
-}
-
-//// Following tests are copied from above, with the role of Dart and C++ code
-//// reversed.
-
-DART_EXPORT int TestIntComputation(
- int64_t (*fn)(int8_t, int16_t, int32_t, int64_t)) {
- CHECK_EQ(fn(125, 250, 500, 1000), 625);
- CHECK_EQ(0x7FFFFFFFFFFFFFFFLL, fn(0, 0, 0, 0x7FFFFFFFFFFFFFFFLL));
- CHECK_EQ(((int64_t)-0x8000000000000000LL),
- fn(0, 0, 0, -0x8000000000000000LL));
- return 0;
-}
-
-DART_EXPORT int TestUintComputation(
- uint64_t (*fn)(uint8_t, uint16_t, uint32_t, uint64_t)) {
- CHECK_EQ(0x7FFFFFFFFFFFFFFFLL, fn(0, 0, 0, 0x7FFFFFFFFFFFFFFFLL));
- CHECK_EQ(-0x8000000000000000LL, fn(0, 0, 0, -0x8000000000000000LL));
- CHECK_EQ(-1, (int64_t)fn(0, 0, 0, -1));
- return 0;
-}
-
-DART_EXPORT int TestSimpleMultiply(double (*fn)(double)) {
- CHECK_EQ(fn(2.0), 2.0 * 1.337);
- return 0;
-}
-
-DART_EXPORT int TestSimpleMultiplyFloat(float (*fn)(float)) {
- CHECK(std::abs(fn(2.0) - 2.0 * 1.337) < 0.001);
- return 0;
-}
-
-DART_EXPORT int TestManyInts(intptr_t (*fn)(intptr_t,
- intptr_t,
- intptr_t,
- intptr_t,
- intptr_t,
- intptr_t,
- intptr_t,
- intptr_t,
- intptr_t,
- intptr_t)) {
- CHECK_EQ(55, fn(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
- return 0;
-}
-
-DART_EXPORT int TestManyDoubles(double (*fn)(double,
- double,
- double,
- double,
- double,
- double,
- double,
- double,
- double,
- double)) {
- CHECK_EQ(55, fn(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
- return 0;
-}
-
-DART_EXPORT int TestManyArgs(double (*fn)(intptr_t a,
- float b,
- intptr_t c,
- double d,
- intptr_t e,
- float f,
- intptr_t g,
- double h,
- intptr_t i,
- float j,
- intptr_t k,
- double l,
- intptr_t m,
- float n,
- intptr_t o,
- double p,
- intptr_t q,
- float r,
- intptr_t s,
- double t)) {
- CHECK(210.0 == fn(1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9, 10.0, 11, 12.0, 13, 14.0,
- 15, 16.0, 17, 18.0, 19, 20.0));
- return 0;
-}
-
-DART_EXPORT int TestStore(int64_t* (*fn)(int64_t* a)) {
- int64_t p[2] = {42, 1000};
- int64_t* result = fn(p);
- CHECK_EQ(*result, 1337);
- CHECK_EQ(p[1], 1337);
- CHECK_EQ(result, p + 1);
- return 0;
-}
-
-DART_EXPORT int TestReturnNull(int32_t fn()) {
- CHECK_EQ(fn(), 0);
- return 0;
-}
-
-DART_EXPORT int TestNullPointers(int64_t* (*fn)(int64_t* ptr)) {
- CHECK_EQ(fn(nullptr), nullptr);
- int64_t p[2] = {0};
- CHECK_EQ(fn(p), p + 1);
- return 0;
-}
-
-struct CallbackTestData {
- int success;
- void (*callback)();
-};
-
-#if defined(TARGET_OS_LINUX) && !defined(PRODUCT)
-
-thread_local sigjmp_buf buf;
-void CallbackTestSignalHandler(int) {
- siglongjmp(buf, 1);
-}
-
-int ExpectAbort(void (*fn)()) {
- fprintf(stderr, "**** EXPECT STACKTRACE TO FOLLOW. THIS IS OK. ****\n");
-
- struct sigaction old_action;
- int result = __sigsetjmp(buf, /*savesigs=*/1);
- if (result == 0) {
- // Install signal handler.
- struct sigaction handler;
- handler.sa_handler = CallbackTestSignalHandler;
- sigemptyset(&handler.sa_mask);
- handler.sa_flags = 0;
-
- sigaction(SIGABRT, &handler, &old_action);
-
- fn();
- } else {
- // Caught the setjmp.
- sigaction(SIGABRT, &old_action, NULL);
- exit(0);
- }
- fprintf(stderr, "Expected abort!!!\n");
- exit(1);
-}
-
-void* TestCallbackOnThreadOutsideIsolate(void* parameter) {
- CallbackTestData* data = reinterpret_cast<CallbackTestData*>(parameter);
- data->success = ExpectAbort(data->callback);
- return NULL;
-}
-
-int TestCallbackOtherThreadHelper(void* (*tester)(void*), void (*fn)()) {
- CallbackTestData data = {1, fn};
-
- pthread_attr_t attr;
- int result = pthread_attr_init(&attr);
- CHECK_EQ(result, 0);
-
- pthread_t tid;
- result = pthread_create(&tid, &attr, tester, &data);
- CHECK_EQ(result, 0);
-
- result = pthread_attr_destroy(&attr);
- CHECK_EQ(result, 0);
-
- void* retval;
- result = pthread_join(tid, &retval);
-
- // Doesn't actually return because the other thread will exit when the test is
- // finished.
- UNREACHABLE();
-}
-
-// Run a callback on another thread and verify that it triggers SIGABRT.
-DART_EXPORT int TestCallbackWrongThread(void (*fn)()) {
- return TestCallbackOtherThreadHelper(&TestCallbackOnThreadOutsideIsolate, fn);
-}
-
-// Verify that we get SIGABRT when invoking a native callback outside an
-// isolate.
-DART_EXPORT int TestCallbackOutsideIsolate(void (*fn)()) {
- Dart_Isolate current = Dart_CurrentIsolate();
-
- Dart_ExitIsolate();
- CallbackTestData data = {1, fn};
- TestCallbackOnThreadOutsideIsolate(&data);
- Dart_EnterIsolate(current);
-
- return data.success;
-}
-
-DART_EXPORT int TestCallbackWrongIsolate(void (*fn)()) {
- return ExpectAbort(fn);
-}
-
-#endif // defined(TARGET_OS_LINUX) && !defined(PRODUCT)
-
} // namespace dart
diff --git a/runtime/lib/ffi.cc b/runtime/lib/ffi.cc
index 12620f4..34a5530 100644
--- a/runtime/lib/ffi.cc
+++ b/runtime/lib/ffi.cc
@@ -9,7 +9,6 @@
#include "vm/class_finalizer.h"
#include "vm/compiler/assembler/assembler.h"
#include "vm/compiler/ffi.h"
-#include "vm/compiler/jit/compiler.h"
#include "vm/exceptions.h"
#include "vm/log.h"
#include "vm/native_arguments.h"
@@ -547,68 +546,53 @@
return raw_closure;
}
-// Generates assembly to trampoline from native code into Dart.
-static uword CompileNativeCallback(const Function& c_signature,
- const Function& dart_target) {
+// Generates assembly to trampoline from C++ back into Dart.
+static void* GenerateFfiInverseTrampoline(const Function& signature,
+ void* dart_entry_point) {
#if defined(DART_PRECOMPILED_RUNTIME) || defined(DART_PRECOMPILER)
UNREACHABLE();
#elif !defined(TARGET_ARCH_X64)
// https://github.com/dart-lang/sdk/issues/35774
- // FFI is supported, but callbacks are not.
- Exceptions::ThrowUnsupportedError(
- "FFI callbacks are currently supported on 64-bit Intel only.");
+ UNREACHABLE();
+#elif !defined(TARGET_OS_LINUX) && !defined(TARGET_OS_MACOS) && \
+ !defined(TARGET_OS_WINDOWS)
+ // https://github.com/dart-lang/sdk/issues/35760 Arm32 && Android
+ // https://github.com/dart-lang/sdk/issues/35772 Arm64
+ // https://github.com/dart-lang/sdk/issues/35773 DBC
+ UNREACHABLE();
#else
- Thread* const thread = Thread::Current();
- const int32_t callback_id = thread->AllocateFfiCallbackId();
- // Create a new Function named 'FfiCallback' and stick it in the 'dart:ffi'
- // library. Note that these functions will never be invoked by Dart, so it
- // doesn't matter that they all have the same name.
- Zone* const Z = thread->zone();
- const String& name =
- String::ZoneHandle(Symbols::New(Thread::Current(), "FfiCallback"));
- const Library& lib = Library::Handle(Library::FfiLibrary());
- const Class& owner_class = Class::Handle(lib.toplevel_class());
- const Function& function =
- Function::Handle(Z, Function::New(name, RawFunction::kFfiTrampoline,
- /*is_static=*/true,
- /*is_const=*/false,
- /*is_abstract=*/false,
- /*is_external=*/false,
- /*is_native=*/false, owner_class,
- TokenPosition::kMinSource));
- function.set_is_debuggable(false);
-
- // Set callback-specific fields which the flow-graph builder needs to generate
- // the body.
- function.SetFfiCSignature(c_signature);
- function.SetFfiCallbackId(callback_id);
- function.SetFfiCallbackTarget(dart_target);
-
- // We compile the callback immediately because we need to return a pointer to
- // the entry-point. Native calls do not use patching like Dart calls, so we
- // cannot compile it lazily.
- const Object& result =
- Object::Handle(Z, Compiler::CompileOptimizedFunction(thread, function));
- if (result.IsError()) {
- Exceptions::PropagateError(Error::Cast(result));
- }
- ASSERT(result.IsCode());
- const Code& code = Code::Cast(result);
-
- thread->SetFfiCallbackCode(callback_id, code);
-
- return code.EntryPoint();
+ // TODO(dacoharkes): Implement this.
+ // https://github.com/dart-lang/sdk/issues/35761
+ // Look at StubCode::GenerateInvokeDartCodeStub.
+ UNREACHABLE();
#endif
}
+// TODO(dacoharkes): Implement this feature.
+// https://github.com/dart-lang/sdk/issues/35761
+// For now, it always returns Pointer with address 0.
DEFINE_NATIVE_ENTRY(Ffi_fromFunction, 1, 1) {
GET_NATIVE_TYPE_ARGUMENT(type_arg, arguments->NativeTypeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(Closure, closure, arguments->NativeArgAt(0));
- const Function& native_signature =
- Function::Handle(((Type&)type_arg).signature());
+ Function& c_signature = Function::Handle(((Type&)type_arg).signature());
+
Function& func = Function::Handle(closure.function());
+ Code& code = Code::Handle(func.EnsureHasCode());
+ void* entryPoint = reinterpret_cast<void*>(code.EntryPoint());
+
+ THR_Print("Ffi_fromFunction: %s\n", type_arg.ToCString());
+ THR_Print("Ffi_fromFunction: %s\n", c_signature.ToCString());
+ THR_Print("Ffi_fromFunction: %s\n", closure.ToCString());
+ THR_Print("Ffi_fromFunction: %s\n", func.ToCString());
+ THR_Print("Ffi_fromFunction: %s\n", code.ToCString());
+ THR_Print("Ffi_fromFunction: %p\n", entryPoint);
+ THR_Print("Ffi_fromFunction: %" Pd "\n", code.Size());
+
+ intptr_t address = reinterpret_cast<intptr_t>(
+ GenerateFfiInverseTrampoline(c_signature, entryPoint));
+
TypeArguments& type_args = TypeArguments::Handle(zone);
type_args = TypeArguments::New(1);
type_args.SetTypeAt(Pointer::kNativeTypeArgPos, type_arg);
@@ -624,19 +608,9 @@
ClassFinalizer::FinalizeType(Class::Handle(), native_function_type);
native_function_type ^= native_function_type.Canonicalize();
- // The FE verifies that the target of a 'fromFunction' is a static method, so
- // the value we see here must be a static tearoff. See ffi_use_sites.dart for
- // details.
- //
- // TODO(36748): Define hot-reload semantics of native callbacks. We may need
- // to look up the target by name.
- ASSERT(func.IsImplicitClosureFunction());
- func = func.parent_function();
- ASSERT(func.is_static());
+ address = 0; // https://github.com/dart-lang/sdk/issues/35761
- const uword address = CompileNativeCallback(native_signature, func);
-
- const Pointer& result = Pointer::Handle(Pointer::New(
+ Pointer& result = Pointer::Handle(Pointer::New(
native_function_type, Integer::Handle(zone, Integer::New(address))));
return result.raw();
@@ -708,7 +682,7 @@
} else if (loc.IsFpuRegister()) {
descr.SetFpuRegister(loc.fpu_reg(), arg_value);
} else {
- ASSERT(loc.IsStackSlot() || loc.IsDoubleStackSlot());
+ ASSERT(loc.IsStackSlot());
ASSERT(loc.stack_index() < num_stack_slots);
descr.SetStackSlotValue(loc.stack_index(), arg_value);
}
diff --git a/runtime/lib/ffi_patch.dart b/runtime/lib/ffi_patch.dart
index 6915d51..c8fde6c 100644
--- a/runtime/lib/ffi_patch.dart
+++ b/runtime/lib/ffi_patch.dart
@@ -53,21 +53,3 @@
@patch
void free() native "Ffi_free";
}
-
-// This method gets called when an exception bubbles up to the native -> Dart
-// boundary from an FFI native callback. Since native code does not have any
-// concept of exceptions, the exception cannot be propagated any further.
-// Instead, print a warning with the exception and return 0/0.0 from the
-// callback.
-//
-// TODO(36856): Iron out the story behind exceptions.
-@pragma("vm:entry-point")
-void _handleExposedException(dynamic exception, dynamic stackTrace) {
- print(
- "==================== UNHANDLED EXCEPTION FROM FFI CALLBACK ====================");
- print(
- """ ** Native callbacks should not throw exceptions because they cannot be
- propagated into native code. **""");
- print("EXCEPTION: $exception");
- print(stackTrace);
-}
diff --git a/runtime/vm/compiler/assembler/assembler_ia32.cc b/runtime/vm/compiler/assembler/assembler_ia32.cc
index dc08528..32656b9 100644
--- a/runtime/vm/compiler/assembler/assembler_ia32.cc
+++ b/runtime/vm/compiler/assembler/assembler_ia32.cc
@@ -2085,10 +2085,9 @@
}
void Assembler::TransitionGeneratedToNative(Register destination_address,
- Register new_exit_frame,
Register scratch) {
// Save exit frame information to enable stack walking.
- movl(Address(THR, Thread::top_exit_frame_info_offset()), new_exit_frame);
+ movl(Address(THR, Thread::top_exit_frame_info_offset()), FPREG);
// Mark that the thread is executing native code.
movl(VMTagAddress(), destination_address);
diff --git a/runtime/vm/compiler/assembler/assembler_ia32.h b/runtime/vm/compiler/assembler/assembler_ia32.h
index c09a0e5..f9e01e5 100644
--- a/runtime/vm/compiler/assembler/assembler_ia32.h
+++ b/runtime/vm/compiler/assembler/assembler_ia32.h
@@ -649,7 +649,6 @@
// Require a temporary register 'tmp'.
// Clobber all non-CPU registers (e.g. XMM registers and the "FPU stack").
void TransitionGeneratedToNative(Register destination_address,
- Register new_exit_frame,
Register scratch);
void TransitionNativeToGenerated(Register scratch);
diff --git a/runtime/vm/compiler/assembler/assembler_x64.cc b/runtime/vm/compiler/assembler/assembler_x64.cc
index f9e725b..073a179 100644
--- a/runtime/vm/compiler/assembler/assembler_x64.cc
+++ b/runtime/vm/compiler/assembler/assembler_x64.cc
@@ -164,10 +164,9 @@
EmitUint8(0xC0 + (dst & 0x07));
}
-void Assembler::TransitionGeneratedToNative(Register destination_address,
- Register new_exit_frame) {
+void Assembler::TransitionGeneratedToNative(Register destination_address) {
// Save exit frame information to enable stack walking.
- movq(Address(THR, Thread::top_exit_frame_info_offset()), new_exit_frame);
+ movq(Address(THR, Thread::top_exit_frame_info_offset()), FPREG);
movq(Assembler::VMTagAddress(), destination_address);
movq(Address(THR, compiler::target::Thread::execution_state_offset()),
@@ -1518,18 +1517,6 @@
}
}
-void Assembler::EmitEntryFrameVerification() {
-#if defined(DEBUG)
- Label ok;
- leaq(RAX, Address(RBP, target::frame_layout.exit_link_slot_from_entry_fp *
- target::kWordSize));
- cmpq(RAX, RSP);
- j(EQUAL, &ok);
- Stop("target::frame_layout.exit_link_slot_from_entry_fp mismatch");
- Bind(&ok);
-#endif
-}
-
void Assembler::PushRegisters(intptr_t cpu_register_set,
intptr_t xmm_register_set) {
const intptr_t xmm_regs_count = RegisterSet::RegisterCount(xmm_register_set);
diff --git a/runtime/vm/compiler/assembler/assembler_x64.h b/runtime/vm/compiler/assembler/assembler_x64.h
index 4df9250..1fe5400 100644
--- a/runtime/vm/compiler/assembler/assembler_x64.h
+++ b/runtime/vm/compiler/assembler/assembler_x64.h
@@ -306,8 +306,7 @@
void setcc(Condition condition, ByteRegister dst);
- void TransitionGeneratedToNative(Register destination_address,
- Register new_exit_frame);
+ void TransitionGeneratedToNative(Register destination_address);
void TransitionNativeToGenerated();
// Register-register, register-address and address-register instructions.
@@ -778,13 +777,6 @@
void LeaveFrame();
void ReserveAlignedFrameSpace(intptr_t frame_space);
- // In debug mode, generates code to verify that:
- // FP + kExitLinkSlotFromFp == SP
- //
- // Triggers breakpoint otherwise.
- // Clobbers RAX.
- void EmitEntryFrameVerification();
-
// Create a frame for calling into runtime that preserves all volatile
// registers. Frame's RSP is guaranteed to be correctly aligned and
// frame_space bytes are reserved under it.
diff --git a/runtime/vm/compiler/backend/constant_propagator.cc b/runtime/vm/compiler/backend/constant_propagator.cc
index 44a3055..931ffa3 100644
--- a/runtime/vm/compiler/backend/constant_propagator.cc
+++ b/runtime/vm/compiler/backend/constant_propagator.cc
@@ -142,10 +142,6 @@
}
}
-void ConstantPropagator::VisitNativeEntry(NativeEntryInstr* block) {
- VisitFunctionEntry(block);
-}
-
void ConstantPropagator::VisitOsrEntry(OsrEntryInstr* block) {
for (auto def : *block->initial_definitions()) {
def->Accept(this);
@@ -196,10 +192,6 @@
// Nothing to do.
}
-void ConstantPropagator::VisitNativeReturn(NativeReturnInstr* instr) {
- // Nothing to do.
-}
-
void ConstantPropagator::VisitThrow(ThrowInstr* instr) {
// Nothing to do.
}
@@ -373,10 +365,6 @@
SetValue(instr, non_constant_);
}
-void ConstantPropagator::VisitNativeParameter(NativeParameterInstr* instr) {
- SetValue(instr, non_constant_);
-}
-
void ConstantPropagator::VisitPushArgument(PushArgumentInstr* instr) {
if (SetValue(instr, instr->value()->definition()->constant_value())) {
// The worklist implementation breaks down around push arguments,
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc
index 1a8e9bb..00f1bdf 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc
@@ -1365,7 +1365,7 @@
: ic_data.arguments_descriptor());
ASSERT(ArgumentsDescriptor(arguments_descriptor).TypeArgsLen() ==
args_info.type_args_len);
- if (is_optimizing() && !ForcedOptimization()) {
+ if (is_optimizing()) {
EmitOptimizedStaticCall(function, arguments_descriptor,
args_info.count_with_type_args, deopt_id, token_pos,
locs, entry_kind);
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.h b/runtime/vm/compiler/backend/flow_graph_compiler.h
index cd43179..8795377 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.h
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.h
@@ -409,11 +409,6 @@
return block_order_;
}
- // If 'ForcedOptimization()' returns 'true', we are compiling in optimized
- // mode for a function which cannot deoptimize. Certain optimizations, e.g.
- // speculative optimizations and call patching are disabled.
- bool ForcedOptimization() const { return function().ForceOptimize(); }
-
const FlowGraph& flow_graph() const { return flow_graph_; }
BlockEntryInstr* current_block() const { return current_block_; }
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index 86bf257..5c840ec 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -27,7 +27,6 @@
#include "vm/regexp_assembler_ir.h"
#include "vm/resolver.h"
#include "vm/scopes.h"
-#include "vm/stack_frame.h"
#include "vm/stub_code.h"
#include "vm/symbols.h"
#include "vm/type_testing_stubs.h"
@@ -3826,9 +3825,7 @@
__ nop();
}
#endif
- if (tag() == Instruction::kFunctionEntry) {
- __ Bind(compiler->GetJumpLabel(this));
- }
+ __ Bind(compiler->GetJumpLabel(this));
// In the AOT compiler we want to reduce code size, so generate no
// fall-through code in [FlowGraphCompiler::CompileGraph()].
@@ -3884,21 +3881,6 @@
}
}
-LocationSummary* NativeEntryInstr::MakeLocationSummary(Zone* zone,
- bool optimizing) const {
- UNREACHABLE();
-}
-
-#if !defined(TARGET_ARCH_X64)
-void NativeEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNREACHABLE();
-}
-
-void NativeReturnInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNREACHABLE();
-}
-#endif
-
LocationSummary* OsrEntryInstr::MakeLocationSummary(Zone* zone,
bool optimizing) const {
UNREACHABLE();
@@ -4004,43 +3986,6 @@
UNREACHABLE();
}
-void NativeParameterInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-#if !defined(TARGET_ARCH_DBC)
- // The native entry frame has size -kExitLinkSlotFromFp. In order to access
- // the top of stack from above the entry frame, we add a constant to account
- // for the the two frame pointers and return address of the entry frame.
- constexpr intptr_t kEntryFramePadding = 3;
- FrameRebase rebase(/*old_base=*/SPREG, /*new_base=*/FPREG,
- -kExitLinkSlotFromEntryFp + kEntryFramePadding);
- const Location dst = locs()->out(0);
- const Location src = rebase.Rebase(loc_);
- NoTemporaryAllocator no_temp;
- compiler->EmitMove(dst, src, &no_temp);
-#else
- UNREACHABLE();
-#endif
-}
-
-LocationSummary* NativeParameterInstr::MakeLocationSummary(Zone* zone,
- bool opt) const {
-#if !defined(TARGET_ARCH_DBC)
- ASSERT(opt);
- Location input = Location::Any();
- if (representation() == kUnboxedInt64 && compiler::target::kWordSize < 8) {
- input = Location::Pair(Location::RequiresRegister(),
- Location::RequiresFpuRegister());
- } else {
- input = RegisterKindForResult() == Location::kRegister
- ? Location::RequiresRegister()
- : Location::RequiresFpuRegister();
- }
- return LocationSummary::Make(zone, /*num_inputs=*/0, input,
- LocationSummary::kNoCall);
-#else
- UNREACHABLE();
-#endif
-}
-
bool ParallelMoveInstr::IsRedundant() const {
for (intptr_t i = 0; i < moves_.length(); i++) {
if (!moves_[i]->IsRedundant()) {
@@ -5429,16 +5374,6 @@
}
}
-LocationSummary* NativeReturnInstr::MakeLocationSummary(Zone* zone,
- bool opt) const {
- const intptr_t kNumInputs = 1;
- const intptr_t kNumTemps = 0;
- LocationSummary* locs = new (zone)
- LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
- locs->set_in(0, result_location_);
- return locs;
-}
-
#undef Z
#else
@@ -5461,11 +5396,6 @@
return summary;
}
-LocationSummary* NativeReturnInstr::MakeLocationSummary(Zone* zone,
- bool opt) const {
- UNREACHABLE();
-}
-
#endif // !defined(TARGET_ARCH_DBC)
Representation FfiCallInstr::representation() const {
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index 3d1f7f4..3e91b50 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -336,21 +336,18 @@
M(JoinEntry, kNoGC) \
M(TargetEntry, kNoGC) \
M(FunctionEntry, kNoGC) \
- M(NativeEntry, kNoGC) \
M(OsrEntry, kNoGC) \
M(IndirectEntry, kNoGC) \
M(CatchBlockEntry, kNoGC) \
M(Phi, kNoGC) \
M(Redefinition, kNoGC) \
M(Parameter, kNoGC) \
- M(NativeParameter, kNoGC) \
M(LoadIndexedUnsafe, kNoGC) \
M(StoreIndexedUnsafe, kNoGC) \
M(TailCall, kNoGC) \
M(ParallelMove, kNoGC) \
M(PushArgument, kNoGC) \
M(Return, kNoGC) \
- M(NativeReturn, kNoGC) \
M(Throw, kNoGC) \
M(ReThrow, kNoGC) \
M(Stop, _) \
@@ -919,28 +916,6 @@
virtual bool UseSharedSlowPathStub(bool is_optimizing) const { return false; }
- // 'RegisterKindForResult()' returns the register kind necessary to hold the
- // result.
- //
- // This is not virtual because instructions should override representation()
- // instead.
- Location::Kind RegisterKindForResult() const {
- const Representation rep = representation();
-#if !defined(TARGET_ARCH_DBC)
- if ((rep == kUnboxedFloat) || (rep == kUnboxedDouble) ||
- (rep == kUnboxedFloat32x4) || (rep == kUnboxedInt32x4) ||
- (rep == kUnboxedFloat64x2)) {
- return Location::kFpuRegister;
- }
-#else
- // DBC supports only unboxed doubles and does not have distinguished FPU
- // registers.
- ASSERT((rep != kUnboxedFloat32x4) && (rep != kUnboxedInt32x4) &&
- (rep != kUnboxedFloat64x2));
-#endif
- return Location::kRegister;
- }
-
protected:
// GetDeoptId and/or CopyDeoptIdFrom.
friend class CallSiteInliner;
@@ -1639,33 +1614,6 @@
DISALLOW_COPY_AND_ASSIGN(FunctionEntryInstr);
};
-// Represents entry into a function from native code.
-//
-// Native entries are not allowed to have regular parameters. They should use
-// NativeParameter instead (which doesn't count as an initial definition).
-class NativeEntryInstr : public FunctionEntryInstr {
- public:
- NativeEntryInstr(const ZoneGrowableArray<Location>* argument_locations,
- GraphEntryInstr* graph_entry,
- intptr_t block_id,
- intptr_t try_index,
- intptr_t deopt_id,
- intptr_t callback_id)
- : FunctionEntryInstr(graph_entry, block_id, try_index, deopt_id),
- callback_id_(callback_id),
- argument_locations_(argument_locations) {}
-
- DECLARE_INSTRUCTION(NativeEntry)
-
- PRINT_TO_SUPPORT
-
- private:
- void SaveArgument(FlowGraphCompiler* compiler, Location loc) const;
-
- const intptr_t callback_id_;
- const ZoneGrowableArray<Location>* const argument_locations_;
-};
-
// Represents an OSR entrypoint to a function.
//
// The OSR entry has it's own initial definitions.
@@ -2245,57 +2193,6 @@
DISALLOW_COPY_AND_ASSIGN(ParameterInstr);
};
-// Native parameters are not treated as initial definitions because they cannot
-// be inlined and are only usable in optimized code. The location must be a
-// stack location relative to the position of the stack (SPREG) after
-// register-based arguments have been saved on entry to a native call. See
-// NativeEntryInstr::EmitNativeCode for more details.
-//
-// TOOD(33549): Unify with ParameterInstr.
-class NativeParameterInstr : public Definition {
- public:
- NativeParameterInstr(Location loc, Representation representation)
- : loc_(loc), representation_(representation) {
- if (loc.IsPairLocation()) {
- for (intptr_t i : {0, 1}) {
- ASSERT(loc_.Component(i).HasStackIndex() &&
- loc_.Component(i).base_reg() == SPREG);
- }
- } else {
- ASSERT(loc_.HasStackIndex() && loc_.base_reg() == SPREG);
- }
- }
-
- DECLARE_INSTRUCTION(NativeParameter)
-
- virtual Representation representation() const { return representation_; }
-
- intptr_t InputCount() const { return 0; }
- Value* InputAt(intptr_t i) const {
- UNREACHABLE();
- return NULL;
- }
-
- virtual bool ComputeCanDeoptimize() const { return false; }
-
- virtual bool HasUnknownSideEffects() const { return false; }
-
- // TODO(sjindel): We can make this more precise.
- virtual CompileType ComputeType() const { return CompileType::Dynamic(); }
-
- virtual bool MayThrow() const { return false; }
-
- PRINT_OPERANDS_TO_SUPPORT
-
- private:
- virtual void RawSetInputAt(intptr_t i, Value* value) { UNREACHABLE(); }
-
- const Location loc_;
- const Representation representation_;
-
- DISALLOW_COPY_AND_ASSIGN(NativeParameterInstr);
-};
-
// Stores a tagged pointer to a slot accessible from a fixed register. It has
// the form:
//
@@ -2359,11 +2256,8 @@
// the frame. This is asserted via `inliner.cc::CalleeGraphValidator`.
class LoadIndexedUnsafeInstr : public TemplateDefinition<1, NoThrow> {
public:
- LoadIndexedUnsafeInstr(Value* index,
- intptr_t offset,
- CompileType result_type,
- Representation representation = kTagged)
- : offset_(offset), representation_(representation) {
+ LoadIndexedUnsafeInstr(Value* index, intptr_t offset, CompileType result_type)
+ : offset_(offset) {
UpdateType(result_type);
SetInputAt(0, index);
}
@@ -2374,6 +2268,7 @@
ASSERT(index == 0);
return kTagged;
}
+ virtual Representation representation() const { return kTagged; }
virtual bool ComputeCanDeoptimize() const { return false; }
virtual bool HasUnknownSideEffects() const { return false; }
@@ -2389,7 +2284,6 @@
private:
const intptr_t offset_;
- const Representation representation_;
DISALLOW_COPY_AND_ASSIGN(LoadIndexedUnsafeInstr);
};
@@ -2499,40 +2393,6 @@
DISALLOW_COPY_AND_ASSIGN(ReturnInstr);
};
-// Represents a return from a Dart function into native code.
-class NativeReturnInstr : public ReturnInstr {
- public:
- NativeReturnInstr(TokenPosition token_pos,
- Value* value,
- Representation rep,
- Location result_location,
- intptr_t deopt_id)
- : ReturnInstr(token_pos, value, deopt_id),
- result_representation_(rep),
- result_location_(result_location) {}
-
- DECLARE_INSTRUCTION(NativeReturn)
-
- PRINT_OPERANDS_TO_SUPPORT
-
- virtual Representation RequiredInputRepresentation(intptr_t idx) const {
- ASSERT(idx == 0);
- return result_representation_;
- }
-
- virtual bool CanBecomeDeoptimizationTarget() const {
- // Unlike ReturnInstr, NativeReturnInstr cannot be inlined (because it's
- // returning into native code).
- return false;
- }
-
- private:
- const Representation result_representation_;
- const Location result_location_;
-
- DISALLOW_COPY_AND_ASSIGN(NativeReturnInstr);
-};
-
class ThrowInstr : public TemplateInstruction<0, Throws> {
public:
explicit ThrowInstr(TokenPosition token_pos, intptr_t deopt_id)
diff --git a/runtime/vm/compiler/backend/il_ia32.cc b/runtime/vm/compiler/backend/il_ia32.cc
index 8e0e512..349a09c 100644
--- a/runtime/vm/compiler/backend/il_ia32.cc
+++ b/runtime/vm/compiler/backend/il_ia32.cc
@@ -886,7 +886,7 @@
__ popl(tmp);
__ movl(Address(FPREG, kSavedCallerPcSlotFromFp * kWordSize), tmp);
- __ TransitionGeneratedToNative(branch, FPREG, tmp);
+ __ TransitionGeneratedToNative(branch, tmp);
__ call(branch);
// The x86 calling convention requires floating point values to be returned on
diff --git a/runtime/vm/compiler/backend/il_printer.cc b/runtime/vm/compiler/backend/il_printer.cc
index a2f841d..fe7508f 100644
--- a/runtime/vm/compiler/backend/il_printer.cc
+++ b/runtime/vm/compiler/backend/il_printer.cc
@@ -524,10 +524,12 @@
void FfiCallInstr::PrintOperandsTo(BufferFormatter* f) const {
f->Print(" pointer=");
InputAt(TargetAddressIndex())->PrintTo(f);
+ f->Print(" signature=%s",
+ Type::Handle(signature_.SignatureType()).ToCString());
for (intptr_t i = 0, n = InputCount(); i < n - 1; ++i) {
f->Print(", ");
InputAt(i)->PrintTo(f);
- f->Print(" (@%s)", arg_locations_[i].ToCString());
+ f->Print(" (at %s) ", arg_locations_[i].ToCString());
}
}
@@ -1061,24 +1063,6 @@
BlockEntryWithInitialDefs::PrintInitialDefinitionsTo(f);
}
-void NativeEntryInstr::PrintTo(BufferFormatter* f) const {
- f->Print("B%" Pd "[native function entry]:%" Pd, block_id(), GetDeoptId());
- if (HasParallelMove()) {
- f->Print("\n");
- parallel_move()->PrintTo(f);
- }
- BlockEntryWithInitialDefs::PrintInitialDefinitionsTo(f);
-}
-
-void NativeReturnInstr::PrintOperandsTo(BufferFormatter* f) const {
- value()->PrintTo(f);
-}
-
-void NativeParameterInstr::PrintOperandsTo(BufferFormatter* f) const {
- f->Print("%s as %s", loc_.ToCString(),
- RepresentationToCString(representation_));
-}
-
void CatchBlockEntryInstr::PrintTo(BufferFormatter* f) const {
f->Print("B%" Pd "[target catch try_idx %" Pd " catch_try_idx %" Pd "]",
block_id(), try_index(), catch_try_index());
diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc
index 70073b1..ce0b196 100644
--- a/runtime/vm/compiler/backend/il_x64.cc
+++ b/runtime/vm/compiler/backend/il_x64.cc
@@ -139,43 +139,6 @@
__ set_constant_pool_allowed(true);
}
-void NativeReturnInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- __ LeaveDartFrame();
-
- // Pop dummy return address.
- __ popq(TMP);
-
- // Anything besides the return register.
- const Register vm_tag_reg = RBX, old_exit_frame_reg = RCX;
-
- __ popq(old_exit_frame_reg);
-
- // Restore top_resource.
- __ popq(TMP);
- __ movq(Address(THR, compiler::target::Thread::top_resource_offset()), TMP);
-
- __ popq(vm_tag_reg);
-
- // TransitionGeneratedToNative will reset the exit frame info to
- // old_exit_frame_reg *before* entering the safepoint.
- __ TransitionGeneratedToNative(vm_tag_reg, old_exit_frame_reg);
-
- // Restore C++ ABI callee-saved registers.
- __ PopRegisters(CallingConventions::kCalleeSaveCpuRegisters,
- CallingConventions::kCalleeSaveXmmRegisters);
-
- // Leave the entry frame.
- __ LeaveFrame();
-
- // Leave the dummy frame holding the pushed arguments.
- __ LeaveFrame();
-
- __ ret();
-
- // For following blocks.
- __ set_constant_pool_allowed(true);
-}
-
static Condition NegateCondition(Condition condition) {
switch (condition) {
case EQUAL:
@@ -958,7 +921,7 @@
__ movq(Address(FPREG, kSavedCallerPcSlotFromFp * kWordSize), TMP);
// Update information in the thread object and enter a safepoint.
- __ TransitionGeneratedToNative(target_address, FPREG);
+ __ TransitionGeneratedToNative(target_address);
__ CallCFunction(target_address);
@@ -980,130 +943,6 @@
__ popq(TMP);
}
-void NativeEntryInstr::SaveArgument(FlowGraphCompiler* compiler,
- Location loc) const {
- ASSERT(!loc.IsPairLocation());
-
- if (loc.HasStackIndex()) return;
-
- if (loc.IsRegister()) {
- __ pushq(loc.reg());
- } else if (loc.IsFpuRegister()) {
- __ movq(TMP, loc.fpu_reg());
- __ pushq(TMP);
- } else {
- UNREACHABLE();
- }
-}
-
-void NativeEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- if (FLAG_precompiled_mode) {
- UNREACHABLE();
- }
-
- __ Bind(compiler->GetJumpLabel(this));
-
- // Create a dummy frame holding the pushed arguments. This simplifies
- // NativeReturnInstr::EmitNativeCode.
- __ EnterFrame(0);
-
- // Save the argument registers, in reverse order.
- for (intptr_t i = argument_locations_->length(); i-- > 0;) {
- SaveArgument(compiler, argument_locations_->At(i));
- }
-
- // Enter the entry frame.
- __ EnterFrame(0);
-
- // Save a space for the code object.
- __ PushImmediate(Immediate(0));
-
- // InvokoeDartCodeStub saves the arguments descriptor here. We don't have one,
- // but we need to follow the same frame layout for the stack walker.
- __ PushImmediate(Immediate(0));
-
- // Save ABI callee-saved registers.
- __ PushRegisters(CallingConventions::kCalleeSaveCpuRegisters,
- CallingConventions::kCalleeSaveXmmRegisters);
-
- // Load the thread object.
- // TODO(35765): Fix linking issue on AOT.
- // TOOD(35934): Exclude native callbacks from snapshots.
- //
- // Create another frame to align the frame before continuing in "native" code.
- {
- __ EnterFrame(0);
- __ ReserveAlignedFrameSpace(0);
-
- __ movq(
- RAX,
- Immediate(reinterpret_cast<int64_t>(DLRT_GetThreadForNativeCallback)));
- __ call(RAX);
- __ movq(THR, RAX);
-
- __ LeaveFrame();
- }
-
- // Save the current VMTag on the stack.
- __ movq(RAX, Assembler::VMTagAddress());
- __ pushq(RAX);
-
- // Save top resource.
- __ pushq(Address(THR, compiler::target::Thread::top_resource_offset()));
- __ movq(Address(THR, compiler::target::Thread::top_resource_offset()),
- Immediate(0));
-
- // Save top exit frame info. Stack walker expects it to be here.
- __ pushq(
- Address(THR, compiler::target::Thread::top_exit_frame_info_offset()));
-
- // In debug mode, verify that we've pushed the top exit frame info at the
- // correct offset from FP.
- __ EmitEntryFrameVerification();
-
- // TransitionNativeToGenerated will reset top exit frame info to 0 *after*
- // leaving the safepoint.
- __ TransitionNativeToGenerated();
-
- // Now that the safepoint has ended, we can touch Dart objects without
- // handles.
- // Otherwise we'll clobber the argument sent from the caller.
- COMPILE_ASSERT(RAX != CallingConventions::kArg1Reg);
- __ movq(CallingConventions::kArg1Reg, Immediate(callback_id_));
- __ movq(RAX, Address(THR, compiler::target::Thread::
- verify_callback_isolate_entry_point_offset()));
- __ call(RAX);
-
- // Load the code object.
- __ movq(RAX, Address(THR, compiler::target::Thread::callback_code_offset()));
- __ movq(RAX, FieldAddress(
- RAX, compiler::target::GrowableObjectArray::data_offset()));
- __ movq(CODE_REG,
- FieldAddress(RAX, compiler::target::Array::data_offset() +
- callback_id_ * compiler::target::kWordSize));
-
- // Put the code object in the reserved slot.
- __ movq(Address(FPREG, kPcMarkerSlotFromFp * compiler::target::kWordSize),
- CODE_REG);
-
- if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
- __ movq(PP, Address(THR,
- compiler::target::Thread::global_object_pool_offset()));
- } else {
- __ xorq(PP, PP); // GC-safe value into PP.
- }
-
- // Push a dummy return address which suggests that we are inside of
- // InvokeDartCodeStub. This is how the stack walker detects an entry frame.
- __ movq(
- RAX,
- Address(THR, compiler::target::Thread::invoke_dart_code_stub_offset()));
- __ pushq(FieldAddress(RAX, compiler::target::Code::entry_point_offset()));
-
- // Continue with Dart frame setup.
- FunctionEntryInstr::EmitNativeCode(compiler);
-}
-
static bool CanBeImmediateIndex(Value* index, intptr_t cid) {
if (!index->definition()->IsConstant()) return false;
const Object& constant = index->definition()->AsConstant()->value();
@@ -1826,10 +1665,10 @@
Label ok, fail_label;
- Label* deopt = NULL;
- if (compiler->is_optimizing()) {
- deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptGuardField);
- }
+ Label* deopt =
+ compiler->is_optimizing()
+ ? compiler->AddDeoptStub(deopt_id(), ICData::kDeoptGuardField)
+ : NULL;
Label* fail = (deopt != NULL) ? deopt : &fail_label;
diff --git a/runtime/vm/compiler/backend/linearscan.cc b/runtime/vm/compiler/backend/linearscan.cc
index b5fea9c..4f5473c 100644
--- a/runtime/vm/compiler/backend/linearscan.cc
+++ b/runtime/vm/compiler/backend/linearscan.cc
@@ -824,6 +824,25 @@
}
}
+static Location::Kind RegisterKindForResult(Instruction* instr) {
+ const Representation rep = instr->representation();
+#if !defined(TARGET_ARCH_DBC)
+ if ((rep == kUnboxedFloat) || (rep == kUnboxedDouble) ||
+ (rep == kUnboxedFloat32x4) || (rep == kUnboxedInt32x4) ||
+ (rep == kUnboxedFloat64x2)) {
+ return Location::kFpuRegister;
+ } else {
+ return Location::kRegister;
+ }
+#else
+ // DBC supports only unboxed doubles and does not have distinguished FPU
+ // registers.
+ ASSERT((rep != kUnboxedFloat32x4) && (rep != kUnboxedInt32x4) &&
+ (rep != kUnboxedFloat64x2));
+ return Location::kRegister;
+#endif
+}
+
//
// When describing shape of live ranges in comments below we are going to use
// the following notation:
@@ -972,11 +991,11 @@
// All phi resolution moves are connected. Phi's live range is
// complete.
AssignSafepoints(phi, range);
- CompleteRange(range, phi->RegisterKindForResult());
+ CompleteRange(range, RegisterKindForResult(phi));
if (is_pair_phi) {
LiveRange* second_range = GetLiveRange(ToSecondPairVreg(vreg));
AssignSafepoints(phi, second_range);
- CompleteRange(second_range, phi->RegisterKindForResult());
+ CompleteRange(second_range, RegisterKindForResult(phi));
}
move_idx += is_pair_phi ? 2 : 1;
@@ -1284,7 +1303,7 @@
}
AssignSafepoints(def, range);
- CompleteRange(range, def->RegisterKindForResult());
+ CompleteRange(range, RegisterKindForResult(def));
}
// Create and update live ranges corresponding to instruction's inputs,
diff --git a/runtime/vm/compiler/ffi.cc b/runtime/vm/compiler/ffi.cc
index 665382a..823e8ef 100644
--- a/runtime/vm/compiler/ffi.cc
+++ b/runtime/vm/compiler/ffi.cc
@@ -9,8 +9,6 @@
#include "platform/globals.h"
#include "vm/compiler/backend/locations.h"
#include "vm/compiler/runtime_api.h"
-#include "vm/growable_array.h"
-#include "vm/stack_frame.h"
namespace dart {
@@ -184,7 +182,7 @@
class Location,
class Register,
class FpuRegister>
-class ArgumentAllocator : public ValueObject {
+class ArgumentFrameState : public ValueObject {
public:
Location AllocateArgument(Representation rep) {
switch (rep) {
@@ -209,13 +207,9 @@
}
// Argument must be spilled.
- if (rep == kUnboxedInt64 && compiler::target::kWordSize == 4) {
+ if ((rep == kUnboxedInt64 || rep == kUnboxedDouble) &&
+ compiler::target::kWordSize == 4) {
return AllocateAlignedStackSlots(rep);
- } else if (rep == kUnboxedDouble) {
- // By convention, we always use DoubleStackSlot for doubles, even on
- // 64-bit systems.
- ASSERT(!CallingConventions::kAlignArguments);
- return AllocateDoubleStackSlot();
} else {
return AllocateStackSlot();
}
@@ -227,13 +221,6 @@
CallingConventions::kStackPointerRegister);
}
- Location AllocateDoubleStackSlot() {
- const Location result = Location::DoubleStackSlot(
- stack_height_in_slots, CallingConventions::kStackPointerRegister);
- stack_height_in_slots += 8 / compiler::target::kWordSize;
- return result;
- }
-
// Allocates a pair of stack slots where the first stack slot is aligned to an
// 8-byte boundary, if necessary.
Location AllocateAlignedStackSlots(Representation rep) {
@@ -300,68 +287,6 @@
intptr_t stack_height_in_slots = 0;
};
-ZoneGrowableArray<Location>*
-CallbackArgumentTranslator::TranslateArgumentLocations(
- const ZoneGrowableArray<Location>& arg_locs) {
- auto& pushed_locs = *(new ZoneGrowableArray<Location>(arg_locs.length()));
-
- CallbackArgumentTranslator translator;
- for (intptr_t i = 0, n = arg_locs.length(); i < n; i++) {
- translator.AllocateArgument(arg_locs[i]);
- }
- for (intptr_t i = 0, n = arg_locs.length(); i < n; ++i) {
- pushed_locs.Add(translator.TranslateArgument(arg_locs[i]));
- }
-
- return &pushed_locs;
-}
-
-void CallbackArgumentTranslator::AllocateArgument(Location arg) {
- if (arg.IsPairLocation()) {
- AllocateArgument(arg.Component(0));
- AllocateArgument(arg.Component(1));
- return;
- }
- if (arg.HasStackIndex()) return;
- ASSERT(arg.IsRegister() || arg.IsFpuRegister());
- if (arg.IsRegister()) {
- argument_slots_required_++;
- } else {
- argument_slots_required_ += 8 / compiler::target::kWordSize;
- }
-}
-
-Location CallbackArgumentTranslator::TranslateArgument(Location arg) {
- if (arg.IsPairLocation()) {
- const Location low = TranslateArgument(arg.Component(0));
- const Location high = TranslateArgument(arg.Component(1));
- return Location::Pair(low, high);
- }
-
- if (arg.HasStackIndex()) {
- // Add extra slots after the saved arguments for the return address and
- // frame pointer of the dummy arguments frame, which will be between the
- // saved argument registers and stack arguments. Also add slots for the
- // shadow space if present (factored into
- // kCallbackSlotsBeforeSavedArguments).
- FrameRebase rebase(
- /*old_base=*/SPREG, /*new_base=*/SPREG,
- /*stack_delta=*/argument_slots_required_ +
- kCallbackSlotsBeforeSavedArguments);
- return rebase.Rebase(arg);
- }
-
- if (arg.IsRegister()) {
- return Location::StackSlot(argument_slots_used_++, SPREG);
- }
-
- ASSERT(arg.IsFpuRegister());
- const Location result =
- Location::DoubleStackSlot(argument_slots_used_, SPREG);
- argument_slots_used_ += 8 / compiler::target::kWordSize;
- return result;
-}
-
// Takes a list of argument representations, and converts it to a list of
// argument locations based on calling convention.
template <class CallingConventions,
@@ -374,7 +299,7 @@
auto result = new ZoneGrowableArray<Location>(num_arguments);
// Loop through all arguments and assign a register or a stack location.
- ArgumentAllocator<CallingConventions, Location, Register, FpuRegister>
+ ArgumentFrameState<CallingConventions, Location, Register, FpuRegister>
frame_state;
for (intptr_t i = 0; i < num_arguments; i++) {
Representation rep = arg_reps[i];
diff --git a/runtime/vm/compiler/ffi.h b/runtime/vm/compiler/ffi.h
index 846775a..cd8e96f 100644
--- a/runtime/vm/compiler/ffi.h
+++ b/runtime/vm/compiler/ffi.h
@@ -108,31 +108,6 @@
#endif // defined(TARGET_ARCH_DBC)
-// This classes translates the ABI location of arguments into the locations they
-// will inhabit after entry-frame setup in the invocation of a native callback.
-//
-// Native -> Dart callbacks must push all the arguments before executing any
-// Dart code because the reading the Thread from TLS requires calling a native
-// stub, and the argument registers are volatile on all ABIs we support.
-//
-// To avoid complicating initial definitions, all callback arguments are read
-// off the stack from their pushed locations, so this class updates the argument
-// positions to account for this.
-//
-// See 'NativeEntryInstr::EmitNativeCode' for details.
-class CallbackArgumentTranslator : public ValueObject {
- public:
- static ZoneGrowableArray<Location>* TranslateArgumentLocations(
- const ZoneGrowableArray<Location>& arg_locs);
-
- private:
- void AllocateArgument(Location arg);
- Location TranslateArgument(Location arg);
-
- intptr_t argument_slots_used_ = 0;
- intptr_t argument_slots_required_ = 0;
-};
-
} // namespace ffi
} // namespace compiler
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index 8e9a84b..6049959 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -16,7 +16,6 @@
#include "vm/compiler/jit/compiler.h"
#include "vm/kernel_loader.h"
#include "vm/longjump.h"
-#include "vm/native_entry.h"
#include "vm/object_store.h"
#include "vm/report.h"
#include "vm/resolver.h"
@@ -2441,31 +2440,6 @@
return Fragment(extend);
}
-Fragment FlowGraphBuilder::FfiExceptionalReturnValue(
- const AbstractType& result_type,
- Representation representation) {
- ASSERT(optimizing_);
- Object& result = Object::ZoneHandle(Z, Object::null());
- if (representation == kUnboxedFloat || representation == kUnboxedDouble) {
- result = Double::New(0.0, Heap::kOld);
- } else {
- result = Integer::New(0, Heap::kOld);
- }
- Fragment code;
- code += Constant(result);
- code += UnboxTruncate(representation);
- return code;
-}
-
-#if !defined(TARGET_ARCH_DBC)
-Fragment FlowGraphBuilder::NativeReturn(Representation result) {
- auto* instr = new (Z)
- NativeReturnInstr(TokenPosition::kNoSource, Pop(), result,
- compiler::ffi::ResultLocation(result), DeoptId::kNone);
- return Fragment(instr);
-}
-#endif
-
Fragment FlowGraphBuilder::FfiPointerFromAddress(const Type& result_type) {
Fragment test;
TargetEntryInstr* null_entry;
@@ -2524,69 +2498,8 @@
return Fragment(instr);
}
-Fragment FlowGraphBuilder::FfiConvertArgumentToDart(
- const AbstractType& ffi_type,
- const Representation native_representation) {
- Fragment body;
- if (compiler::ffi::NativeTypeIsPointer(ffi_type)) {
- body += Box(kUnboxedFfiIntPtr);
- body += FfiPointerFromAddress(Type::Cast(ffi_type));
- } else if (compiler::ffi::NativeTypeIsVoid(ffi_type)) {
- body += Drop();
- body += NullConstant();
- } else {
- const Representation from_rep = native_representation;
- const Representation to_rep = compiler::ffi::TypeRepresentation(ffi_type);
- if (from_rep != to_rep) {
- body += BitCast(from_rep, to_rep);
- } else {
- body += FfiUnboxedExtend(from_rep, ffi_type);
- }
- body += Box(to_rep);
- }
- return body;
-}
-
-Fragment FlowGraphBuilder::FfiConvertArgumentToNative(
- const Function& function,
- const AbstractType& ffi_type,
- const Representation native_representation) {
- Fragment body;
- // Check for 'null'. Only ffi.Pointers are allowed to be null.
- if (!compiler::ffi::NativeTypeIsPointer(ffi_type)) {
- body += LoadLocal(MakeTemporary());
- body <<=
- new (Z) CheckNullInstr(Pop(), String::ZoneHandle(Z, function.name()),
- GetNextDeoptId(), TokenPosition::kNoSource);
- }
-
- if (compiler::ffi::NativeTypeIsPointer(ffi_type)) {
- body += LoadAddressFromFfiPointer();
- body += UnboxTruncate(kUnboxedFfiIntPtr);
- } else {
- Representation from_rep = compiler::ffi::TypeRepresentation(ffi_type);
- body += UnboxTruncate(from_rep);
-
- Representation to_rep = native_representation;
- if (from_rep != to_rep) {
- body += BitCast(from_rep, to_rep);
- } else {
- body += FfiUnboxedExtend(from_rep, ffi_type);
- }
- }
- return body;
-}
-
FlowGraph* FlowGraphBuilder::BuildGraphOfFfiTrampoline(
const Function& function) {
- if (function.FfiCallbackTarget() != Function::null()) {
- return BuildGraphOfFfiCallback(function);
- } else {
- return BuildGraphOfFfiNative(function);
- }
-}
-
-FlowGraph* FlowGraphBuilder::BuildGraphOfFfiNative(const Function& function) {
graph_entry_ =
new (Z) GraphEntryInstr(*parsed_function_, Compiler::kNoOSRDeoptId);
@@ -2619,7 +2532,29 @@
for (intptr_t pos = 1; pos < function.num_fixed_parameters(); pos++) {
body += LoadLocal(parsed_function_->ParameterVariable(pos));
ffi_type = signature.ParameterTypeAt(pos);
- body += FfiConvertArgumentToNative(function, ffi_type, arg_reps[pos - 1]);
+
+ // Check for 'null'. Only ffi.Pointers are allowed to be null.
+ if (!compiler::ffi::NativeTypeIsPointer(ffi_type)) {
+ body += LoadLocal(parsed_function_->ParameterVariable(pos));
+ body <<=
+ new (Z) CheckNullInstr(Pop(), String::ZoneHandle(Z, function.name()),
+ GetNextDeoptId(), TokenPosition::kNoSource);
+ }
+
+ if (compiler::ffi::NativeTypeIsPointer(ffi_type)) {
+ body += LoadAddressFromFfiPointer();
+ body += UnboxTruncate(kUnboxedFfiIntPtr);
+ } else {
+ Representation from_rep = compiler::ffi::TypeRepresentation(ffi_type);
+ body += UnboxTruncate(from_rep);
+
+ Representation to_rep = arg_reps[pos - 1];
+ if (from_rep != to_rep) {
+ body += BitCast(from_rep, to_rep);
+ } else {
+ body += FfiUnboxedExtend(from_rep, ffi_type);
+ }
+ }
}
// Push the function pointer, which is stored (boxed) in the first slot of the
@@ -2634,109 +2569,34 @@
body += FfiCall(signature, arg_reps, arg_locs, arg_host_locs);
ffi_type = signature.result_type();
+ if (compiler::ffi::NativeTypeIsPointer(ffi_type)) {
+ body += Box(kUnboxedFfiIntPtr);
+ body += FfiPointerFromAddress(Type::Cast(ffi_type));
+ } else if (compiler::ffi::NativeTypeIsVoid(ffi_type)) {
+ body += Drop();
+ body += NullConstant();
+ } else {
#if !defined(TARGET_ARCH_DBC)
- const Representation from_rep =
- compiler::ffi::ResultRepresentation(signature);
+ Representation from_rep = compiler::ffi::ResultRepresentation(signature);
#else
- const Representation from_rep =
- compiler::ffi::ResultHostRepresentation(signature);
+ Representation from_rep =
+ compiler::ffi::ResultHostRepresentation(signature);
#endif // !defined(TARGET_ARCH_DBC)
- body += FfiConvertArgumentToDart(ffi_type, from_rep);
+ Representation to_rep = compiler::ffi::TypeRepresentation(ffi_type);
+ if (from_rep != to_rep) {
+ body += BitCast(from_rep, to_rep);
+ } else {
+ body += FfiUnboxedExtend(from_rep, ffi_type);
+ }
+ body += Box(to_rep);
+ }
+
body += Return(TokenPosition::kNoSource);
return new (Z) FlowGraph(*parsed_function_, graph_entry_, last_used_block_id_,
prologue_info);
}
-FlowGraph* FlowGraphBuilder::BuildGraphOfFfiCallback(const Function& function) {
-#if !defined(TARGET_ARCH_DBC)
- const Function& signature = Function::ZoneHandle(Z, function.FfiCSignature());
- const auto& arg_reps = *compiler::ffi::ArgumentRepresentations(signature);
- const auto& arg_locs = *compiler::ffi::ArgumentLocations(arg_reps);
- const auto& callback_locs =
- *compiler::ffi::CallbackArgumentTranslator::TranslateArgumentLocations(
- arg_locs);
-
- graph_entry_ =
- new (Z) GraphEntryInstr(*parsed_function_, Compiler::kNoOSRDeoptId);
-
- auto* const native_entry = new (Z) NativeEntryInstr(
- &arg_locs, graph_entry_, AllocateBlockId(), CurrentTryIndex(),
- GetNextDeoptId(), function.FfiCallbackId());
-
- graph_entry_->set_normal_entry(native_entry);
-
- Fragment function_body(native_entry);
- function_body += CheckStackOverflowInPrologue(function.token_pos());
-
- // Wrap the entire method in a big try/catch. This is important to ensure that
- // the VM does not crash if the callback throws an exception.
- const intptr_t try_handler_index = AllocateTryIndex();
- Fragment body = TryCatch(try_handler_index);
- ++try_depth_;
-
- // Box and push the arguments.
- AbstractType& ffi_type = AbstractType::Handle(Z);
- for (intptr_t i = 0, n = callback_locs.length(); i < n; ++i) {
- ffi_type = signature.ParameterTypeAt(i + 1);
- auto* parameter =
- new (Z) NativeParameterInstr(callback_locs[i], arg_reps[i]);
- Push(parameter);
- body <<= parameter;
- body += FfiConvertArgumentToDart(ffi_type, arg_reps[i]);
- body += PushArgument();
- }
-
- // Call the target.
- //
- // TODO(36748): Determine the hot-reload semantics of callbacks and update the
- // rebind-rule accordingly.
- body += StaticCall(TokenPosition::kNoSource,
- Function::ZoneHandle(Z, function.FfiCallbackTarget()),
- callback_locs.length(), Array::empty_array(),
- ICData::kNoRebind);
-
- ffi_type = signature.result_type();
- const Representation result_rep =
- compiler::ffi::ResultRepresentation(signature);
- body += FfiConvertArgumentToNative(function, ffi_type, result_rep);
- body += NativeReturn(result_rep);
-
- --try_depth_;
- function_body += body;
-
- ++catch_depth_;
- Fragment catch_body =
- CatchBlockEntry(Array::empty_array(), try_handler_index,
- /*needs_stacktrace=*/true, /*is_synthesized=*/true);
-
- catch_body += LoadLocal(CurrentException());
- catch_body += PushArgument();
- catch_body += LoadLocal(CurrentStackTrace());
- catch_body += PushArgument();
-
- // Find '_handleExposedException(e, st)' from ffi_patch.dart and call it.
- const Library& ffi_lib =
- Library::Handle(Z, Library::LookupLibrary(thread_, Symbols::DartFfi()));
- const Function& handler = Function::ZoneHandle(
- Z, ffi_lib.LookupFunctionAllowPrivate(Symbols::HandleExposedException()));
- ASSERT(!handler.IsNull());
- catch_body += StaticCall(TokenPosition::kNoSource, handler, /*num_args=*/2,
- /*arg_names=*/Array::empty_array(), ICData::kStatic);
- catch_body += Drop();
-
- catch_body += FfiExceptionalReturnValue(ffi_type, result_rep);
- catch_body += NativeReturn(result_rep);
- --catch_depth_;
-
- PrologueInfo prologue_info(-1, -1);
- return new (Z) FlowGraph(*parsed_function_, graph_entry_, last_used_block_id_,
- prologue_info);
-#else
- UNREACHABLE();
-#endif
-}
-
void FlowGraphBuilder::SetCurrentTryCatchBlock(TryCatchBlock* try_catch_block) {
try_catch_block_ = try_catch_block;
SetCurrentTryIndex(try_catch_block == nullptr ? kInvalidTryIndex
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.h b/runtime/vm/compiler/frontend/kernel_to_il.h
index 9ccc1a94..1e34e13 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.h
+++ b/runtime/vm/compiler/frontend/kernel_to_il.h
@@ -101,8 +101,6 @@
FlowGraph* BuildGraphOfNoSuchMethodDispatcher(const Function& function);
FlowGraph* BuildGraphOfInvokeFieldDispatcher(const Function& function);
FlowGraph* BuildGraphOfFfiTrampoline(const Function& function);
- FlowGraph* BuildGraphOfFfiCallback(const Function& function);
- FlowGraph* BuildGraphOfFfiNative(const Function& function);
Fragment NativeFunctionBody(const Function& function,
LocalVariable* first_parameter);
@@ -238,26 +236,6 @@
// the pointer.
Fragment FfiPointerFromAddress(const Type& result_type);
- // Pushes an (unboxed) bogus value returned when a native -> Dart callback
- // throws an exception.
- Fragment FfiExceptionalReturnValue(const AbstractType& result_type,
- const Representation target);
-
- // Pops a Dart object and push the unboxed native version, according to the
- // semantics of FFI argument translation.
- Fragment FfiConvertArgumentToNative(
- const Function& function,
- const AbstractType& ffi_type,
- const Representation native_representation);
-
- // Reverse of 'FfiConvertArgumentToNative'.
- Fragment FfiConvertArgumentToDart(const AbstractType& ffi_type,
- const Representation native_representation);
-
- // Return from a native -> Dart callback. Can only be used in conjunction with
- // NativeEntry and NativeParameter are used.
- Fragment NativeReturn(Representation result);
-
// Bit-wise cast between representations.
// Pops the input and pushes the converted result.
// Currently only works with equal sizes and floating point <-> integer.
diff --git a/runtime/vm/compiler/frontend/scope_builder.cc b/runtime/vm/compiler/frontend/scope_builder.cc
index a0f984d..dde3667 100644
--- a/runtime/vm/compiler/frontend/scope_builder.cc
+++ b/runtime/vm/compiler/frontend/scope_builder.cc
@@ -390,17 +390,6 @@
: Object::dynamic_type().raw()));
scope_->InsertParameterAt(i, variable);
}
- // Callbacks need try/catch variables.
- if (function.IsFfiTrampoline() &&
- function.FfiCallbackTarget() != Function::null()) {
- ++depth_.try_;
- AddTryVariables();
- --depth_.try_;
- ++depth_.catch_;
- AddCatchVariables();
- FinalizeCatchVariables();
- --depth_.catch_;
- }
break;
case RawFunction::kSignatureFunction:
case RawFunction::kIrregexpFunction:
diff --git a/runtime/vm/compiler/runtime_api.cc b/runtime/vm/compiler/runtime_api.cc
index 5637049..8f927b8 100644
--- a/runtime/vm/compiler/runtime_api.cc
+++ b/runtime/vm/compiler/runtime_api.cc
@@ -500,7 +500,6 @@
V(Thread, top_resource_offset) \
V(Thread, vm_tag_offset) \
V(Thread, safepoint_state_offset) \
- V(Thread, callback_code_offset) \
V(TimelineStream, enabled_offset) \
V(TwoByteString, data_offset) \
V(Type, arguments_offset) \
@@ -583,10 +582,6 @@
word Thread::array_write_barrier_entry_point_offset() {
return dart::Thread::array_write_barrier_entry_point_offset();
}
-
-word Thread::verify_callback_isolate_entry_point_offset() {
- return dart::Thread::verify_callback_entry_offset();
-}
#endif // !defined(TARGET_ARCH_DBC)
#if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_ARM64) || \
diff --git a/runtime/vm/compiler/runtime_api.h b/runtime/vm/compiler/runtime_api.h
index a873fbd..d910575 100644
--- a/runtime/vm/compiler/runtime_api.h
+++ b/runtime/vm/compiler/runtime_api.h
@@ -572,7 +572,6 @@
static word write_barrier_wrappers_thread_offset(intptr_t regno);
static word array_write_barrier_entry_point_offset();
static word write_barrier_entry_point_offset();
- static word verify_callback_isolate_entry_point_offset();
static word vm_tag_offset();
static uword vm_tag_compiled_id();
@@ -584,8 +583,6 @@
static uword native_execution_state();
static uword generated_execution_state();
- static word callback_code_offset();
-
#if !defined(TARGET_ARCH_DBC)
static word write_barrier_code_offset();
static word array_write_barrier_code_offset();
diff --git a/runtime/vm/compiler/stub_code_compiler_arm.cc b/runtime/vm/compiler/stub_code_compiler_arm.cc
index 0988331..e82fa9f 100644
--- a/runtime/vm/compiler/stub_code_compiler_arm.cc
+++ b/runtime/vm/compiler/stub_code_compiler_arm.cc
@@ -290,10 +290,6 @@
__ Ret();
}
-void StubCodeCompiler::GenerateVerifyCallbackStub(Assembler* assembler) {
- __ Breakpoint();
-}
-
void StubCodeCompiler::GenerateNullErrorSharedWithoutFPURegsStub(
Assembler* assembler) {
GenerateSharedStub(
diff --git a/runtime/vm/compiler/stub_code_compiler_arm64.cc b/runtime/vm/compiler/stub_code_compiler_arm64.cc
index 1ef512c..9bee589 100644
--- a/runtime/vm/compiler/stub_code_compiler_arm64.cc
+++ b/runtime/vm/compiler/stub_code_compiler_arm64.cc
@@ -235,10 +235,6 @@
__ Ret();
}
-void StubCodeCompiler::GenerateVerifyCallbackStub(Assembler* assembler) {
- __ Breakpoint();
-}
-
// R1: The extracted method.
// R4: The type_arguments_field_offset (or 0)
void StubCodeCompiler::GenerateBuildMethodExtractorStub(
diff --git a/runtime/vm/compiler/stub_code_compiler_ia32.cc b/runtime/vm/compiler/stub_code_compiler_ia32.cc
index 68dbdcd..806c130 100644
--- a/runtime/vm/compiler/stub_code_compiler_ia32.cc
+++ b/runtime/vm/compiler/stub_code_compiler_ia32.cc
@@ -154,10 +154,6 @@
__ ret();
}
-void StubCodeCompiler::GenerateVerifyCallbackStub(Assembler* assembler) {
- __ Breakpoint();
-}
-
void StubCodeCompiler::GenerateNullErrorSharedWithoutFPURegsStub(
Assembler* assembler) {
__ Breakpoint();
diff --git a/runtime/vm/compiler/stub_code_compiler_x64.cc b/runtime/vm/compiler/stub_code_compiler_x64.cc
index 32fb433..4313cd4 100644
--- a/runtime/vm/compiler/stub_code_compiler_x64.cc
+++ b/runtime/vm/compiler/stub_code_compiler_x64.cc
@@ -204,13 +204,8 @@
all_registers.AddAllGeneralRegisters();
__ PushRegisters(all_registers.cpu_registers(),
all_registers.fpu_registers());
-
- __ EnterFrame(0);
- __ ReserveAlignedFrameSpace(0);
__ movq(RAX, Address(THR, kEnterSafepointRuntimeEntry.OffsetFromThread()));
__ CallCFunction(RAX);
- __ LeaveFrame();
-
__ PopRegisters(all_registers.cpu_registers(), all_registers.fpu_registers());
__ ret();
}
@@ -220,31 +215,12 @@
all_registers.AddAllGeneralRegisters();
__ PushRegisters(all_registers.cpu_registers(),
all_registers.fpu_registers());
-
- __ EnterFrame(0);
- __ ReserveAlignedFrameSpace(0);
__ movq(RAX, Address(THR, kExitSafepointRuntimeEntry.OffsetFromThread()));
__ CallCFunction(RAX);
- __ LeaveFrame();
-
__ PopRegisters(all_registers.cpu_registers(), all_registers.fpu_registers());
__ ret();
}
-void StubCodeCompiler::GenerateVerifyCallbackStub(Assembler* assembler) {
- // SP points to return address, which needs to be the second argument to
- // VerifyCallbackIsolate.
- __ movq(CallingConventions::kArg2Reg, Address(SPREG, 0));
-
- __ EnterFrame(0);
- __ ReserveAlignedFrameSpace(0);
- __ movq(RAX,
- Address(THR, kVerifyCallbackIsolateRuntimeEntry.OffsetFromThread()));
- __ CallCFunction(RAX);
- __ LeaveFrame();
- __ ret();
-}
-
// RBX: The extracted method.
// RDX: The type_arguments_field_offset (or 0)
void StubCodeCompiler::GenerateBuildMethodExtractorStub(
@@ -1110,8 +1086,19 @@
__ pushq(RAX);
// The constant target::frame_layout.exit_link_slot_from_entry_fp must be kept
- // in sync with the code above.
- __ EmitEntryFrameVerification();
+ // in sync with the code below.
+#if defined(DEBUG)
+ {
+ Label ok;
+ __ leaq(RAX,
+ Address(RBP, target::frame_layout.exit_link_slot_from_entry_fp *
+ target::kWordSize));
+ __ cmpq(RAX, RSP);
+ __ j(EQUAL, &ok);
+ __ Stop("target::frame_layout.exit_link_slot_from_entry_fp mismatch");
+ __ Bind(&ok);
+ }
+#endif
__ movq(Address(THR, target::Thread::top_exit_frame_info_offset()),
Immediate(0));
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index 79361ba..73a41f0 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -995,12 +995,6 @@
Exceptions::ThrowByType(Exceptions::kRange, args);
}
-void Exceptions::ThrowUnsupportedError(const char* msg) {
- const Array& args = Array::Handle(Array::New(1));
- args.SetAt(0, String::Handle(String::New(msg)));
- Exceptions::ThrowByType(Exceptions::kUnsupported, args);
-}
-
void Exceptions::ThrowRangeErrorMsg(const char* msg) {
const Array& args = Array::Handle(Array::New(1));
args.SetAt(0, String::Handle(String::New(msg)));
diff --git a/runtime/vm/exceptions.h b/runtime/vm/exceptions.h
index 46b4d68..894f374 100644
--- a/runtime/vm/exceptions.h
+++ b/runtime/vm/exceptions.h
@@ -84,7 +84,6 @@
intptr_t expected_from,
intptr_t expected_to);
DART_NORETURN static void ThrowRangeErrorMsg(const char* msg);
- DART_NORETURN static void ThrowUnsupportedError(const char* msg);
DART_NORETURN static void ThrowCompileTimeError(const LanguageError& error);
// Returns a RawInstance if the exception is successfully created,
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 4f490d3..c427228 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -6065,34 +6065,6 @@
return FfiTrampolineData::Cast(obj).c_signature();
}
-int32_t Function::FfiCallbackId() const {
- ASSERT(IsFfiTrampoline());
- const Object& obj = Object::Handle(raw_ptr()->data_);
- ASSERT(!obj.IsNull());
- return FfiTrampolineData::Cast(obj).callback_id();
-}
-
-void Function::SetFfiCallbackId(int32_t value) const {
- ASSERT(IsFfiTrampoline());
- const Object& obj = Object::Handle(raw_ptr()->data_);
- ASSERT(!obj.IsNull());
- FfiTrampolineData::Cast(obj).set_callback_id(value);
-}
-
-RawFunction* Function::FfiCallbackTarget() const {
- ASSERT(IsFfiTrampoline());
- const Object& obj = Object::Handle(raw_ptr()->data_);
- ASSERT(!obj.IsNull());
- return FfiTrampolineData::Cast(obj).callback_target();
-}
-
-void Function::SetFfiCallbackTarget(const Function& target) const {
- ASSERT(IsFfiTrampoline());
- const Object& obj = Object::Handle(raw_ptr()->data_);
- ASSERT(!obj.IsNull());
- FfiTrampolineData::Cast(obj).set_callback_target(target);
-}
-
RawType* Function::SignatureType() const {
Type& type = Type::Handle(ExistingSignatureType());
if (type.IsNull()) {
@@ -8246,22 +8218,12 @@
StorePointer(&raw_ptr()->c_signature_, value.raw());
}
-void FfiTrampolineData::set_callback_target(const Function& value) const {
- StorePointer(&raw_ptr()->callback_target_, value.raw());
-}
-
-void FfiTrampolineData::set_callback_id(int32_t callback_id) const {
- StoreNonPointer(&raw_ptr()->callback_id_, callback_id);
-}
-
RawFfiTrampolineData* FfiTrampolineData::New() {
ASSERT(Object::ffi_trampoline_data_class() != Class::null());
RawObject* raw =
Object::Allocate(FfiTrampolineData::kClassId,
FfiTrampolineData::InstanceSize(), Heap::kOld);
- RawFfiTrampolineData* data = reinterpret_cast<RawFfiTrampolineData*>(raw);
- data->ptr()->callback_id_ = -1;
- return data;
+ return reinterpret_cast<RawFfiTrampolineData*>(raw);
}
const char* FfiTrampolineData::ToCString() const {
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index dfc1e9b..540a7ac 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -2005,20 +2005,6 @@
// Can only be used on FFI trampolines.
RawFunction* FfiCSignature() const;
- // Can only be called on FFI trampolines.
- // -1 for Dart -> native calls.
- int32_t FfiCallbackId() const;
-
- // Can only be called on FFI trampolines.
- void SetFfiCallbackId(int32_t value) const;
-
- // Can only be called on FFI trampolines.
- // Null for Dart -> native calls.
- RawFunction* FfiCallbackTarget() const;
-
- // Can only be called on FFI trampolines.
- void SetFfiCallbackTarget(const Function& target) const;
-
// Return a new function with instantiated result and parameter types.
RawFunction* InstantiateSignatureFrom(
const TypeArguments& instantiator_type_arguments,
@@ -3149,12 +3135,6 @@
RawFunction* c_signature() const { return raw_ptr()->c_signature_; }
void set_c_signature(const Function& value) const;
- RawFunction* callback_target() const { return raw_ptr()->callback_target_; }
- void set_callback_target(const Function& value) const;
-
- int32_t callback_id() const { return raw_ptr()->callback_id_; }
- void set_callback_id(int32_t value) const;
-
static RawFfiTrampolineData* New();
FINAL_HEAP_OBJECT_IMPLEMENTATION(FfiTrampolineData, Object);
@@ -5025,7 +5005,7 @@
return ContainsInstructionAt(raw(), addr);
}
- static bool ContainsInstructionAt(const RawCode* code, uword addr) {
+ static bool ContainsInstructionAt(RawCode* code, uword addr) {
return Instructions::ContainsPc(code->ptr()->instructions_, addr);
}
@@ -8292,14 +8272,6 @@
static RawGrowableObjectArray* New(const Array& array,
Heap::Space space = Heap::kNew);
- static RawSmi* NoSafepointLength(const RawGrowableObjectArray* array) {
- return array->ptr()->length_;
- }
-
- static RawArray* NoSafepointData(const RawGrowableObjectArray* array) {
- return array->ptr()->data_;
- }
-
private:
RawArray* DataArray() const { return data()->ptr(); }
RawObject** ObjectAddr(intptr_t index) const {
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 3494b45..75e7a92 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -1013,19 +1013,7 @@
VISIT_FROM(RawObject*, signature_type_);
RawType* signature_type_;
RawFunction* c_signature_;
-
- // Target Dart method for callbacks, otherwise null.
- RawFunction* callback_target_;
-
- VISIT_TO(RawObject*, callback_target_);
-
- // Callback id for callbacks, otherwise 0.
- //
- // The callbacks ids are used so that native callbacks can lookup their own
- // code objects, since native code doesn't pass code objects into function
- // calls. The callback id is also used to for verifying that callbacks are
- // called on the correct isolate. See DLRT_VerifyCallbackIsolate for details.
- uint32_t callback_id_;
+ VISIT_TO(RawObject*, c_signature_);
};
class RawField : public RawObject {
diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc
index b4b4563..1a7ba2e 100644
--- a/runtime/vm/runtime_entry.cc
+++ b/runtime/vm/runtime_entry.cc
@@ -26,7 +26,6 @@
#include "vm/service_isolate.h"
#include "vm/stack_frame.h"
#include "vm/symbols.h"
-#include "vm/thread.h"
#include "vm/thread_registry.h"
#include "vm/type_testing_stubs.h"
@@ -2766,29 +2765,4 @@
}
DEFINE_RAW_LEAF_RUNTIME_ENTRY(ExitSafepoint, 0, false, &DFLRT_ExitSafepoint);
-// Not registered as a runtime entry because we can't use Thread to look it up.
-extern "C" Thread* DLRT_GetThreadForNativeCallback() {
- Thread* const thread = Thread::Current();
- if (thread == nullptr) {
- FATAL("Cannot invoke native callback outside an isolate.");
- }
- if (thread->no_callback_scope_depth() != 0) {
- FATAL("Cannot invoke native callback when API callbacks are prohibited.");
- }
- if (!thread->IsMutatorThread()) {
- FATAL("Native callbacks must be invoked on the mutator thread.");
- }
- return thread;
-}
-
-extern "C" void DLRT_VerifyCallbackIsolate(int32_t callback_id,
- uword return_address) {
- Thread::Current()->VerifyCallbackIsolate(callback_id, return_address);
-}
-DEFINE_RAW_LEAF_RUNTIME_ENTRY(
- VerifyCallbackIsolate,
- 1,
- false /* is_float */,
- reinterpret_cast<RuntimeFunction>(&DLRT_VerifyCallbackIsolate));
-
} // namespace dart
diff --git a/runtime/vm/runtime_entry.h b/runtime/vm/runtime_entry.h
index f072c14..85e9d7f2 100644
--- a/runtime/vm/runtime_entry.h
+++ b/runtime/vm/runtime_entry.h
@@ -145,9 +145,6 @@
RUNTIME_ENTRY_LIST(DECLARE_RUNTIME_ENTRY)
LEAF_RUNTIME_ENTRY_LIST(DECLARE_LEAF_RUNTIME_ENTRY)
-// Expected to be called inside a safepoint.
-extern "C" Thread* DLRT_GetThreadForNativeCallback();
-
const char* DeoptReasonToCString(ICData::DeoptReasonId deopt_reason);
void DeoptimizeAt(const Code& optimized_code, StackFrame* frame);
diff --git a/runtime/vm/runtime_entry_list.h b/runtime/vm/runtime_entry_list.h
index b0c241e..dd4159d 100644
--- a/runtime/vm/runtime_entry_list.h
+++ b/runtime/vm/runtime_entry_list.h
@@ -84,8 +84,7 @@
V(RawBool*, CaseInsensitiveCompareUTF16, RawString*, RawSmi*, RawSmi*, \
RawSmi*) \
V(void, EnterSafepoint) \
- V(void, ExitSafepoint) \
- V(void, VerifyCallbackIsolate, int32_t, uword)
+ V(void, ExitSafepoint)
} // namespace dart
diff --git a/runtime/vm/stack_frame.h b/runtime/vm/stack_frame.h
index 3b59005..bf67520 100644
--- a/runtime/vm/stack_frame.h
+++ b/runtime/vm/stack_frame.h
@@ -471,13 +471,6 @@
return fp + LocalVarIndex(0, index) * kWordSize;
}
-#if !defined(TARGET_ARCH_X64)
-// For FFI native -> Dart callbacks, the number of stack slots between arguments
-// passed on stack and arguments saved in callback prologue. This placeholder
-// here is for unsupported architectures.
-constexpr intptr_t kCallbackSlotsBeforeSavedArguments = -1;
-#endif
-
} // namespace dart
#endif // RUNTIME_VM_STACK_FRAME_H_
diff --git a/runtime/vm/stack_frame_x64.h b/runtime/vm/stack_frame_x64.h
index 7659b51..00d0059 100644
--- a/runtime/vm/stack_frame_x64.h
+++ b/runtime/vm/stack_frame_x64.h
@@ -5,8 +5,6 @@
#ifndef RUNTIME_VM_STACK_FRAME_X64_H_
#define RUNTIME_VM_STACK_FRAME_X64_H_
-#include "vm/constants_x64.h"
-
namespace dart {
/* X64 Dart Frame Layout
@@ -54,13 +52,6 @@
static const int kExitLinkSlotFromEntryFp = -10;
#endif // defined(_WIN64)
-// For FFI native -> Dart callbacks, the number of stack slots between arguments
-// passed on stack and arguments saved in callback prologue. 2 = return adddress
-// (1) + saved frame pointer (1). Also add slots for the shadow space, if
-// present.
-constexpr intptr_t kCallbackSlotsBeforeSavedArguments =
- 2 + CallingConventions::kShadowSpaceBytes;
-
} // namespace dart
#endif // RUNTIME_VM_STACK_FRAME_X64_H_
diff --git a/runtime/vm/stub_code_list.h b/runtime/vm/stub_code_list.h
index 248c455..7f93f5b8 100644
--- a/runtime/vm/stub_code_list.h
+++ b/runtime/vm/stub_code_list.h
@@ -77,8 +77,7 @@
V(OneArgCheckInlineCacheWithExactnessCheck) \
V(OneArgOptimizedCheckInlineCacheWithExactnessCheck) \
V(EnterSafepoint) \
- V(ExitSafepoint) \
- V(VerifyCallback)
+ V(ExitSafepoint)
#else
#define VM_STUB_CODE_LIST(V) \
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index f265e3e..845d780 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -179,7 +179,6 @@
V(GetterPrefix, "get:") \
V(GreaterEqualOperator, ">=") \
V(GrowRegExpStack, "_growRegExpStack") \
- V(HandleExposedException, "_handleExposedException") \
V(HaveSameRuntimeType, "_haveSameRuntimeType") \
V(Hide, "hide") \
V(ICData, "ICData") \
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index 71a9b2d..6b48726 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -6,7 +6,6 @@
#include "vm/dart_api_state.h"
#include "vm/growable_array.h"
-#include "vm/heap/safepoint.h"
#include "vm/isolate.h"
#include "vm/json_stream.h"
#include "vm/lockers.h"
@@ -77,7 +76,6 @@
resume_pc_(0),
execution_state_(kThreadInNative),
safepoint_state_(0),
- ffi_callback_code_(GrowableObjectArray::null()),
task_kind_(kUnknownTask),
dart_stream_(NULL),
thread_lock_(),
@@ -670,7 +668,6 @@
visitor->VisitPointer(reinterpret_cast<RawObject**>(&active_stacktrace_));
visitor->VisitPointer(reinterpret_cast<RawObject**>(&sticky_error_));
visitor->VisitPointer(reinterpret_cast<RawObject**>(&async_stack_trace_));
- visitor->VisitPointer(reinterpret_cast<RawObject**>(&ffi_callback_code_));
#if !defined(DART_PRECOMPILED_RUNTIME)
if (interpreter() != NULL) {
@@ -939,45 +936,4 @@
}
}
-const intptr_t kInitialCallbackIdsReserved = 1024;
-int32_t Thread::AllocateFfiCallbackId() {
- Zone* Z = isolate()->current_zone();
- if (ffi_callback_code_ == GrowableObjectArray::null()) {
- ffi_callback_code_ = GrowableObjectArray::New(kInitialCallbackIdsReserved);
- }
- const auto& array = GrowableObjectArray::Handle(Z, ffi_callback_code_);
- array.Add(Code::Handle(Z, Code::null()));
- return array.Length() - 1;
-}
-
-void Thread::SetFfiCallbackCode(int32_t callback_id, const Code& code) {
- Zone* Z = isolate()->current_zone();
- const auto& array = GrowableObjectArray::Handle(Z, ffi_callback_code_);
- array.SetAt(callback_id, code);
-}
-
-void Thread::VerifyCallbackIsolate(int32_t callback_id, uword entry) {
- NoSafepointScope _;
-
- const RawGrowableObjectArray* const array = ffi_callback_code_;
- if (array == GrowableObjectArray::null()) {
- FATAL("Cannot invoke callback on incorrect isolate.");
- }
-
- const RawSmi* const length_smi =
- GrowableObjectArray::NoSafepointLength(array);
- const intptr_t length = Smi::Value(length_smi);
-
- if (callback_id < 0 || callback_id >= length) {
- FATAL("Cannot invoke callback on incorrect isolate.");
- }
-
- RawObject** const code_array =
- Array::DataOf(GrowableObjectArray::NoSafepointData(array));
- const RawCode* const code = Code::RawCast(code_array[callback_id]);
- if (!Code::ContainsInstructionAt(code, entry)) {
- FATAL("Cannot invoke callback on incorrect isolate.");
- }
-}
-
} // namespace dart
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index 44bb9e6..c9d81bb 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -168,8 +168,8 @@
V(uword, monomorphic_miss_entry_, StubCode::MonomorphicMiss().EntryPoint(), \
0) \
V(uword, optimize_entry_, StubCode::OptimizeFunction().EntryPoint(), 0) \
- V(uword, deoptimize_entry_, StubCode::Deoptimize().EntryPoint(), 0) \
- V(uword, verify_callback_entry_, StubCode::VerifyCallback().EntryPoint(), 0)
+ V(uword, deoptimize_entry_, StubCode::Deoptimize().EntryPoint(), 0)
+
#endif
#define CACHED_ADDRESSES_LIST(V) \
@@ -315,10 +315,6 @@
return OFFSET_OF(Thread, safepoint_state_);
}
- static intptr_t callback_code_offset() {
- return OFFSET_OF(Thread, ffi_callback_code_);
- }
-
TaskKind task_kind() const { return task_kind_; }
// Retrieves and clears the stack overflow flags. These are set by
@@ -772,13 +768,6 @@
}
}
- int32_t AllocateFfiCallbackId();
- void SetFfiCallbackCode(int32_t callback_id, const Code& code);
-
- // Ensure that 'entry' points within the code of the callback identified by
- // 'callback_id'. Aborts otherwise.
- void VerifyCallbackIsolate(int32_t callback_id, uword entry);
-
Thread* next() const { return next_; }
// Visit all object pointers.
@@ -872,7 +861,6 @@
uword resume_pc_;
uword execution_state_;
uword safepoint_state_;
- RawGrowableObjectArray* ffi_callback_code_;
// ---- End accessed from generated code. ----
diff --git a/tests/ffi/ffi.status b/tests/ffi/ffi.status
index 024505c..2b170cf 100644
--- a/tests/ffi/ffi.status
+++ b/tests/ffi/ffi.status
@@ -25,9 +25,6 @@
[ $arch == x64 || $arch == arm64 || $arch == simdbc64 ]
enable_structs_test: SkipByDesign # Tests that structs don't work on 32-bit systems.
-[ $arch != x64 ]
-function_callbacks_test: Skip # Issue 35761
-
[ $runtime == dart_precompiled ]
*: Skip # AOT is not yet supported: dartbug.com/35765
diff --git a/tests/ffi/function_callbacks_test.dart b/tests/ffi/function_callbacks_test.dart
index bef1599..0ad50a9 100644
--- a/tests/ffi/function_callbacks_test.dart
+++ b/tests/ffi/function_callbacks_test.dart
@@ -8,192 +8,71 @@
library FfiTest;
-import 'dart:io';
-import 'dart:ffi';
-import 'dart:isolate';
+import 'dart:ffi' as ffi;
+
import 'dylib_utils.dart';
import "package:expect/expect.dart";
-typedef NativeCallbackTest = Int32 Function(Pointer);
-typedef NativeCallbackTestFn = int Function(Pointer);
+import 'coordinate.dart';
-final DynamicLibrary testLibrary = dlopenPlatformSpecific("ffi_test_functions");
+typedef NativeCoordinateOp = Coordinate Function(Coordinate);
-class Test {
- final String name;
- final Pointer callback;
- final bool skip;
+typedef CoordinateTrice = Coordinate Function(
+ ffi.Pointer<ffi.NativeFunction<NativeCoordinateOp>>, Coordinate);
- Test(this.name, this.callback, {bool skipIf: false}) : skip = skipIf {}
-
- void run() {
- if (skip) return;
-
- final NativeCallbackTestFn tester = testLibrary
- .lookupFunction<NativeCallbackTest, NativeCallbackTestFn>("Test$name");
- final int testCode = tester(callback);
- if (testCode != 0) {
- Expect.fail("Test $name failed.");
- }
- }
+void main() {
+ testFunctionWithFunctionPointer();
+ testNativeFunctionWithFunctionPointer();
}
-typedef SimpleAdditionType = Int32 Function(Int32, Int32);
-int simpleAddition(int x, int y) => x + y;
+ffi.DynamicLibrary ffiTestFunctions =
+ dlopenPlatformSpecific("ffi_test_functions");
-typedef IntComputationType = Int64 Function(Int8, Int16, Int32, Int64);
-int intComputation(int a, int b, int c, int d) => d - c + b - a;
+/// pass a pointer to a c function as an argument to a c function
+void testFunctionWithFunctionPointer() {
+ ffi.Pointer<ffi.NativeFunction<NativeCoordinateOp>>
+ transposeCoordinatePointer =
+ ffiTestFunctions.lookup("TransposeCoordinate");
-typedef UintComputationType = Uint64 Function(Uint8, Uint16, Uint32, Uint64);
-int uintComputation(int a, int b, int c, int d) => d - c + b - a;
+ ffi.Pointer<ffi.NativeFunction<CoordinateTrice>> p2 =
+ ffiTestFunctions.lookup("CoordinateUnOpTrice");
+ CoordinateTrice coordinateUnOpTrice = p2.asFunction();
-typedef SimpleMultiplyType = Double Function(Double);
-double simpleMultiply(double x) => x * 1.337;
+ Coordinate c1 = Coordinate(10.0, 20.0, null);
+ c1.next = c1;
-typedef SimpleMultiplyFloatType = Float Function(Float);
-double simpleMultiplyFloat(double x) => x * 1.337;
+ Coordinate result = coordinateUnOpTrice(transposeCoordinatePointer, c1);
-typedef ManyIntsType = IntPtr Function(IntPtr, IntPtr, IntPtr, IntPtr, IntPtr,
- IntPtr, IntPtr, IntPtr, IntPtr, IntPtr);
-int manyInts(
- int a, int b, int c, int d, int e, int f, int g, int h, int i, int j) {
- return a + b + c + d + e + f + g + h + i + j;
+ print(result.runtimeType);
+ print(result.x);
+ print(result.y);
+
+ c1.free();
}
-typedef ManyDoublesType = Double Function(Double, Double, Double, Double,
- Double, Double, Double, Double, Double, Double);
-double manyDoubles(double a, double b, double c, double d, double e, double f,
- double g, double h, double i, double j) {
- return a + b + c + d + e + f + g + h + i + j;
+typedef BinaryOp = int Function(int, int);
+
+typedef NativeIntptrBinOp = ffi.IntPtr Function(ffi.IntPtr, ffi.IntPtr);
+
+typedef NativeIntptrBinOpLookup
+ = ffi.Pointer<ffi.NativeFunction<NativeIntptrBinOp>> Function();
+
+void testNativeFunctionWithFunctionPointer() {
+ ffi.Pointer<ffi.NativeFunction<NativeIntptrBinOpLookup>> p1 =
+ ffiTestFunctions.lookup("IntptrAdditionClosure");
+ NativeIntptrBinOpLookup intptrAdditionClosure = p1.asFunction();
+
+ ffi.Pointer<ffi.NativeFunction<NativeIntptrBinOp>> intptrAdditionPointer =
+ intptrAdditionClosure();
+ BinaryOp intptrAddition = intptrAdditionPointer.asFunction();
+ Expect.equals(37, intptrAddition(10, 27));
}
-typedef ManyArgsType = Double Function(
- IntPtr,
- Float,
- IntPtr,
- Double,
- IntPtr,
- Float,
- IntPtr,
- Double,
- IntPtr,
- Float,
- IntPtr,
- Double,
- IntPtr,
- Float,
- IntPtr,
- Double,
- IntPtr,
- Float,
- IntPtr,
- Double);
-double manyArgs(
- int _1,
- double _2,
- int _3,
- double _4,
- int _5,
- double _6,
- int _7,
- double _8,
- int _9,
- double _10,
- int _11,
- double _12,
- int _13,
- double _14,
- int _15,
- double _16,
- int _17,
- double _18,
- int _19,
- double _20) {
- return _1 +
- _2 +
- _3 +
- _4 +
- _5 +
- _6 +
- _7 +
- _8 +
- _9 +
- _10 +
- _11 +
- _12 +
- _13 +
- _14 +
- _15 +
- _16 +
- _17 +
- _18 +
- _19 +
- _20;
-}
+int myPlus(int a, int b) => a + b;
-typedef StoreType = Pointer<Int64> Function(Pointer<Int64>);
-Pointer<Int64> store(Pointer<Int64> ptr) => ptr.elementAt(1)..store(1337);
+typedef NativeApplyTo42And74Type = ffi.IntPtr Function(
+ ffi.Pointer<ffi.NativeFunction<NativeIntptrBinOp>>);
-typedef NullPointersType = Pointer<Int64> Function(Pointer<Int64>);
-Pointer<Int64> nullPointers(Pointer<Int64> ptr) => ptr?.elementAt(1);
-
-typedef ReturnNullType = Int32 Function();
-int returnNull() {
- print('Expect "unhandled exception" error message to follow.');
- return null;
-}
-
-typedef ReturnVoid = Void Function();
-void returnVoid() {}
-
-final List<Test> testcases = [
- Test("SimpleAddition", fromFunction<SimpleAdditionType>(simpleAddition)),
- Test("IntComputation", fromFunction<IntComputationType>(intComputation)),
- Test("UintComputation", fromFunction<UintComputationType>(uintComputation)),
- Test("SimpleMultiply", fromFunction<SimpleMultiplyType>(simpleMultiply)),
- Test("SimpleMultiplyFloat",
- fromFunction<SimpleMultiplyFloatType>(simpleMultiplyFloat)),
- Test("ManyInts", fromFunction<ManyIntsType>(manyInts)),
- Test("ManyDoubles", fromFunction<ManyDoublesType>(manyDoubles)),
- Test("ManyArgs", fromFunction<ManyArgsType>(manyArgs)),
- Test("Store", fromFunction<StoreType>(store)),
- Test("NullPointers", fromFunction<NullPointersType>(nullPointers)),
- Test("ReturnNull", fromFunction<ReturnNullType>(returnNull)),
-];
-
-testCallbackWrongThread() =>
- Test("CallbackWrongThread", fromFunction<ReturnVoid>(returnVoid)).run();
-
-testCallbackOutsideIsolate() =>
- Test("CallbackOutsideIsolate", fromFunction<ReturnVoid>(returnVoid)).run();
-
-isolateHelper(int callbackPointer) {
- final Pointer<Void> ptr = fromAddress(callbackPointer);
- final NativeCallbackTestFn tester =
- testLibrary.lookupFunction<NativeCallbackTest, NativeCallbackTestFn>(
- "TestCallbackWrongIsolate");
- Expect.equals(0, tester(ptr));
-}
-
-testCallbackWrongIsolate() async {
- final int callbackPointer = fromFunction<ReturnVoid>(returnVoid).address;
- final ReceivePort exitPort = ReceivePort();
- await Isolate.spawn(isolateHelper, callbackPointer,
- errorsAreFatal: true, onExit: exitPort.sendPort);
- await exitPort.first;
-}
-
-void main() async {
- testcases.forEach((t) => t.run());
-
- // These tests terminate the process after successful completion, so we have
- // to run them separately.
- //
- // Since they use signal handlers they only run on Linux.
- if (Platform.isLinux && !const bool.fromEnvironment("dart.vm.product")) {
- testCallbackWrongThread(); //# 01: ok
- testCallbackOutsideIsolate(); //# 02: ok
- await testCallbackWrongIsolate(); //# 03: ok
- }
-}
+typedef ApplyTo42And74Type = int Function(
+ ffi.Pointer<ffi.NativeFunction<NativeIntptrBinOp>>);