diff --git a/pkg/front_end/lib/src/api_unstable/vm.dart b/pkg/front_end/lib/src/api_unstable/vm.dart index 47691d791f9..38dc0425983 100644 --- a/pkg/front_end/lib/src/api_unstable/vm.dart +++ b/pkg/front_end/lib/src/api_unstable/vm.dart @@ -40,19 +40,23 @@ export '../fasta/fasta_codes.dart' show LocatedMessage, messageBytecodeLimitExceededTooManyArguments, + messageFfiExceptionalReturnNull, + messageFfiExpectedConstant, noLength, + templateFfiDartTypeMismatch, + templateFfiExpectedExceptionalReturn, + templateFfiExpectedNoExceptionalReturn, + templateFfiExtendsOrImplementsSealedClass, templateFfiFieldAnnotation, + templateFfiFieldInitializer, templateFfiFieldNoAnnotation, templateFfiNotStatic, + templateFfiStructGeneric, templateFfiTypeInvalid, templateFfiTypeMismatch, templateFfiTypeUnsized, - templateFfiFieldInitializer, - templateIllegalRecursiveType, - templateFfiDartTypeMismatch, - templateFfiExtendsOrImplementsSealedClass, - templateFfiStructGeneric, - templateFfiWrongStructInheritance; + templateFfiWrongStructInheritance, + templateIllegalRecursiveType; export '../fasta/hybrid_file_system.dart' show HybridFileSystem; diff --git a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart index c6845a81fd1..9e76db91098 100644 --- a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart +++ b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart @@ -3754,6 +3754,81 @@ Message _withArgumentsFfiDartTypeMismatch(DartType _type, DartType _type2) { arguments: {'type': _type, 'type2': _type2}); } +// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. +const Code codeFfiExceptionalReturnNull = messageFfiExceptionalReturnNull; + +// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. +const MessageCode messageFfiExceptionalReturnNull = const MessageCode( + "FfiExceptionalReturnNull", + message: r"""Exceptional return value must not be null."""); + +// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. +const Code codeFfiExpectedConstant = messageFfiExpectedConstant; + +// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. +const MessageCode messageFfiExpectedConstant = const MessageCode( + "FfiExpectedConstant", + message: r"""Exceptional return value must be a constant."""); + +// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. +const Template< + Message Function( + DartType + _type)> templateFfiExpectedExceptionalReturn = const Template< + Message Function(DartType _type)>( + messageTemplate: + r"""Expected an exceptional return value for a native callback returning '#type'.""", + withArguments: _withArgumentsFfiExpectedExceptionalReturn); + +// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. +const Code codeFfiExpectedExceptionalReturn = + const Code( + "FfiExpectedExceptionalReturn", + templateFfiExpectedExceptionalReturn, +); + +// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. +Message _withArgumentsFfiExpectedExceptionalReturn(DartType _type) { + TypeLabeler labeler = new TypeLabeler(); + List typeParts = labeler.labelType(_type); + String type = typeParts.join(); + return new Message(codeFfiExpectedExceptionalReturn, + message: + """Expected an exceptional return value for a native callback returning '${type}'.""" + + labeler.originMessages, + arguments: {'type': _type}); +} + +// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. +const Template< + Message Function( + DartType + _type)> templateFfiExpectedNoExceptionalReturn = const Template< + Message Function(DartType _type)>( + messageTemplate: + r"""Exceptional return value cannot be provided for a native callback returning '#type'.""", + withArguments: _withArgumentsFfiExpectedNoExceptionalReturn); + +// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. +const Code + codeFfiExpectedNoExceptionalReturn = + const Code( + "FfiExpectedNoExceptionalReturn", + templateFfiExpectedNoExceptionalReturn, +); + +// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. +Message _withArgumentsFfiExpectedNoExceptionalReturn(DartType _type) { + TypeLabeler labeler = new TypeLabeler(); + List typeParts = labeler.labelType(_type); + String type = typeParts.join(); + return new Message(codeFfiExpectedNoExceptionalReturn, + message: + """Exceptional return value cannot be provided for a native callback returning '${type}'.""" + + labeler.originMessages, + arguments: {'type': _type}); +} + // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. const Template templateFfiExtendsOrImplementsSealedClass = @@ -3784,7 +3859,7 @@ const Template< Message Function(String name)> templateFfiFieldAnnotation = const Template< Message Function(String name)>( messageTemplate: - r"""Field '#name' requires exactly one annotation to declare its C++ type, which cannot be Void. dart:ffi Structs cannot have regular Dart fields.""", + r"""Field '#name' requires exactly one annotation to declare its native type, which cannot be Void. dart:ffi Structs cannot have regular Dart fields.""", withArguments: _withArgumentsFfiFieldAnnotation); // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. @@ -3800,7 +3875,7 @@ Message _withArgumentsFfiFieldAnnotation(String name) { name = demangleMixinApplicationName(name); return new Message(codeFfiFieldAnnotation, message: - """Field '${name}' requires exactly one annotation to declare its C++ type, which cannot be Void. dart:ffi Structs cannot have regular Dart fields.""", + """Field '${name}' requires exactly one annotation to declare its native type, which cannot be Void. dart:ffi Structs cannot have regular Dart fields.""", arguments: {'name': name}); } @@ -3836,7 +3911,7 @@ const Template< name)> templateFfiFieldNoAnnotation = const Template< Message Function(String name)>( messageTemplate: - r"""Field '#name' requires no annotation to declare its C++ type, it is a Pointer which is represented by the same type in Dart and C++.""", + r"""Field '#name' requires no annotation to declare its native type, it is a Pointer which is represented by the same type in Dart and native code.""", withArguments: _withArgumentsFfiFieldNoAnnotation); // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. @@ -3852,7 +3927,7 @@ Message _withArgumentsFfiFieldNoAnnotation(String name) { name = demangleMixinApplicationName(name); return new Message(codeFfiFieldNoAnnotation, message: - """Field '${name}' requires no annotation to declare its C++ type, it is a Pointer which is represented by the same type in Dart and C++.""", + """Field '${name}' requires no annotation to declare its native type, it is a Pointer which is represented by the same type in Dart and native code.""", arguments: {'name': name}); } @@ -3861,7 +3936,7 @@ const Template< Message Function(String name)> templateFfiNotStatic = const Template< Message Function(String name)>( messageTemplate: - r"""#name expects a static function as parameter. dart:ffi only supports calling static Dart functions from c.""", + r"""#name expects a static function as parameter. dart:ffi only supports calling static Dart functions from native code.""", withArguments: _withArgumentsFfiNotStatic); // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. @@ -3877,7 +3952,7 @@ Message _withArgumentsFfiNotStatic(String name) { name = demangleMixinApplicationName(name); return new Message(codeFfiNotStatic, message: - """${name} expects a static function as parameter. dart:ffi only supports calling static Dart functions from c.""", + """${name} expects a static function as parameter. dart:ffi only supports calling static Dart functions from native code.""", arguments: {'name': name}); } diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status index 64aa92413a0..5c99198de55 100644 --- a/pkg/front_end/messages.status +++ b/pkg/front_end/messages.status @@ -265,6 +265,10 @@ FfiDartTypeMismatch/analyzerCode: Fail FfiExtendsOrImplementsSealedClass/analyzerCode: Fail FfiStructGeneric/analyzerCode: Fail FfiWrongStructInheritance/analyzerCode: Fail +FfiExpectedExceptionalReturn/analyzerCode: Fail +FfiExpectedNoExceptionalReturn/analyzerCode: Fail +FfiExpectedConstant/analyzerCode: Fail +FfiExceptionalReturnNull/analyzerCode: Fail FieldInitializedOutsideDeclaringClass/part_wrapped_script1: Fail FieldInitializedOutsideDeclaringClass/script1: Fail FieldInitializerOutsideConstructor/part_wrapped_script1: Fail diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml index f2492ae3a13..056dbc84f47 100644 --- a/pkg/front_end/messages.yaml +++ b/pkg/front_end/messages.yaml @@ -3493,17 +3493,17 @@ FfiTypeUnsized: FfiFieldAnnotation: # Used by dart:ffi - template: "Field '#name' requires exactly one annotation to declare its C++ type, which cannot be Void. dart:ffi Structs cannot have regular Dart fields." + template: "Field '#name' requires exactly one annotation to declare its native type, which cannot be Void. dart:ffi Structs cannot have regular Dart fields." external: test/ffi_test.dart FfiFieldNoAnnotation: # Used by dart:ffi - template: "Field '#name' requires no annotation to declare its C++ type, it is a Pointer which is represented by the same type in Dart and C++." + template: "Field '#name' requires no annotation to declare its native type, it is a Pointer which is represented by the same type in Dart and native code." external: test/ffi_test.dart FfiNotStatic: # Used by dart:ffi - template: "#name expects a static function as parameter. dart:ffi only supports calling static Dart functions from c." + template: "#name expects a static function as parameter. dart:ffi only supports calling static Dart functions from native code." external: test/ffi_test.dart FfiFieldInitializer: @@ -3531,6 +3531,26 @@ FfiDartTypeMismatch: template: "Expected '#type' to be a subtype of '#type2'." external: test/ffi_test.dart +FfiExpectedExceptionalReturn: + # Used by dart:ffi + template: "Expected an exceptional return value for a native callback returning '#type'." + external: test/ffi_test.dart + +FfiExpectedNoExceptionalReturn: + # Used by dart:ffi + template: "Exceptional return value cannot be provided for a native callback returning '#type'." + external: test/ffi_test.dart + +FfiExpectedConstant: + # Used by dart:ffi + template: "Exceptional return value must be a constant." + external: test/ffi_test.dart + +FfiExceptionalReturnNull: + # Used by dart:ffi + template: "Exceptional return value must not be null." + external: test/ffi_test.dart + SpreadTypeMismatch: template: "Unexpected type '#type' of a spread. Expected 'dynamic' or an Iterable." script: diff --git a/pkg/front_end/test/spell_checking_list_common.txt b/pkg/front_end/test/spell_checking_list_common.txt index db24d0f9a6d..64c7a3ca908 100644 --- a/pkg/front_end/test/spell_checking_list_common.txt +++ b/pkg/front_end/test/spell_checking_list_common.txt @@ -942,6 +942,7 @@ examples exceeded except exception +exceptional exceptions exclamation exclude diff --git a/pkg/vm/lib/transformations/ffi.dart b/pkg/vm/lib/transformations/ffi.dart index 667a2e9b261..6b473242c0e 100644 --- a/pkg/vm/lib/transformations/ffi.dart +++ b/pkg/vm/lib/transformations/ffi.dart @@ -186,6 +186,8 @@ class FfiTransformer extends Transformer { final Constructor structFromPointer; final Procedure libraryLookupMethod; final Procedure abiMethod; + final Procedure pointerFromFunctionProcedure; + final Procedure nativeCallbackFunctionProcedure; /// Classes corresponding to [NativeType], indexed by [NativeType]. final List nativeTypesClasses; @@ -220,6 +222,10 @@ class FfiTransformer extends Transformer { libraryLookupMethod = index.getMember('dart:ffi', 'DynamicLibrary', 'lookup'), abiMethod = index.getTopLevelMember('dart:ffi', '_abi'), + pointerFromFunctionProcedure = + index.getTopLevelMember('dart:ffi', '_pointerFromFunction'), + nativeCallbackFunctionProcedure = + index.getTopLevelMember('dart:ffi', '_nativeCallbackFunction'), nativeTypesClasses = nativeTypeClassNames .map((name) => index.getClass('dart:ffi', name)) .toList(); diff --git a/pkg/vm/lib/transformations/ffi_use_sites.dart b/pkg/vm/lib/transformations/ffi_use_sites.dart index 062f3ed9d69..d7cc4b5209b 100644 --- a/pkg/vm/lib/transformations/ffi_use_sites.dart +++ b/pkg/vm/lib/transformations/ffi_use_sites.dart @@ -6,12 +6,16 @@ library vm.transformations.ffi_use_sites; import 'package:front_end/src/api_unstable/vm.dart' show + messageFfiExceptionalReturnNull, + messageFfiExpectedConstant, + templateFfiDartTypeMismatch, + templateFfiExpectedExceptionalReturn, + templateFfiExpectedNoExceptionalReturn, + templateFfiExtendsOrImplementsSealedClass, + templateFfiNotStatic, templateFfiTypeInvalid, templateFfiTypeMismatch, - templateFfiDartTypeMismatch, - templateFfiTypeUnsized, - templateFfiNotStatic, - templateFfiExtendsOrImplementsSealedClass; + templateFfiTypeUnsized; import 'package:kernel/ast.dart'; import 'package:kernel/class_hierarchy.dart' show ClassHierarchy; @@ -55,7 +59,12 @@ class _FfiUseSiteTransformer extends FfiTransformer { final Map replacedGetters; final Map replacedSetters; - bool isFfiLibrary; + Library currentLibrary; + bool get isFfiLibrary => currentLibrary == ffiLibrary; + + // Used to create private top-level fields with unique names for each + // callback. + int callbackCount = 0; _FfiUseSiteTransformer( LibraryIndex index, @@ -68,7 +77,8 @@ class _FfiUseSiteTransformer extends FfiTransformer { @override TreeNode visitLibrary(Library node) { - isFfiLibrary = node == ffiLibrary; + currentLibrary = node; + callbackCount = 0; return super.visitLibrary(node); } @@ -78,6 +88,11 @@ class _FfiUseSiteTransformer extends FfiTransformer { try { _ensureNotExtendsOrImplementsSealedClass(node); return super.visitClass(node); + } on _FfiStaticTypeError { + // It's OK to swallow the exception because the diagnostics issued will + // cause compilation to fail. By continuing, we can report more + // diagnostics before compilation ends. + return super.visitClass(node); } finally { env.thisType = null; } @@ -115,31 +130,89 @@ class _FfiUseSiteTransformer extends FfiTransformer { Member target = node.target; try { if (target == fromFunctionMethod) { - DartType nativeType = + final DartType nativeType = InterfaceType(nativeFunctionClass, [node.arguments.types[0]]); - Expression func = node.arguments.positional[0]; - DartType dartType = func.getStaticType(env); + final Expression func = node.arguments.positional[0]; + final DartType dartType = func.getStaticType(env); + + _ensureIsStaticFunction(func); - _ensureIsStatic(func); // TODO(36730): Allow passing/returning structs by value. _ensureNativeTypeValid(nativeType, node); _ensureNativeTypeToDartType(nativeType, dartType, node); // Check `exceptionalReturn`'s type. final FunctionType funcType = dartType; - final Expression exceptionalReturn = node.arguments.positional[1]; - final DartType returnType = exceptionalReturn.getStaticType(env); + final NativeType expectedReturn = getType( + ((node.arguments.types[0] as FunctionType).returnType + as InterfaceType) + .classNode); - if (!env.isSubtypeOf(returnType, funcType.returnType)) { - diagnosticReporter.report( - templateFfiDartTypeMismatch.withArguments( - returnType, funcType.returnType), - exceptionalReturn.fileOffset, - 1, - exceptionalReturn.location.file); + if (expectedReturn == NativeType.kVoid || + expectedReturn == NativeType.kPointer) { + if (node.arguments.positional.length > 1) { + diagnosticReporter.report( + templateFfiExpectedNoExceptionalReturn + .withArguments(funcType.returnType), + node.fileOffset, + 1, + node.location.file); + return node; + } + node.arguments.positional.add(NullLiteral()..parent = node); + } else { + // The exceptional return value is not optional for other return + // types. + if (node.arguments.positional.length < 2) { + diagnosticReporter.report( + templateFfiExpectedExceptionalReturn + .withArguments(funcType.returnType), + node.fileOffset, + 1, + node.location.file); + return node; + } + + final Expression exceptionalReturn = node.arguments.positional[1]; + + // The exceptional return value must be a constant so that it be + // referenced by precompiled trampoline's object pool. + if (exceptionalReturn is! BasicLiteral && + !(exceptionalReturn is ConstantExpression && + exceptionalReturn.constant is PrimitiveConstant)) { + diagnosticReporter.report(messageFfiExpectedConstant, + node.fileOffset, 1, node.location.file); + return node; + } + + // Moreover it may not be null. + if (exceptionalReturn is NullLiteral || + (exceptionalReturn is ConstantExpression && + exceptionalReturn.constant is NullConstant)) { + diagnosticReporter.report(messageFfiExceptionalReturnNull, + node.fileOffset, 1, node.location.file); + return node; + } + + final DartType returnType = exceptionalReturn.getStaticType(env); + + if (!env.isSubtypeOf(returnType, funcType.returnType)) { + diagnosticReporter.report( + templateFfiDartTypeMismatch.withArguments( + returnType, funcType.returnType), + exceptionalReturn.fileOffset, + 1, + exceptionalReturn.location.file); + return node; + } } + return _replaceFromFunction(node); } - } on _FfiStaticTypeError {} + } on _FfiStaticTypeError { + // It's OK to swallow the exception because the diagnostics issued will + // cause compilation to fail. By continuing, we can report more + // diagnostics before compilation ends. + } return node; } @@ -151,10 +224,10 @@ class _FfiUseSiteTransformer extends FfiTransformer { // 'lookupFunction' are constants, so by inlining the call to 'asFunction' at // the call-site, we ensure that there are no generic calls to 'asFunction'. // - // We will not detect dynamic invocations of 'asFunction' -- these are handled - // by the stub in 'dynamic_library_patch.dart'. Dynamic invocations of - // 'lookupFunction' (and 'asFunction') are not legal and throw a runtime - // exception. + // We will not detect dynamic invocations of 'asFunction' and + // 'lookupFunction': these are handled by the stubs in 'ffi_patch.dart' and + // 'dynamic_library_patch.dart'. Dynamic invocations of 'lookupFunction' (and + // 'asFunction') are not legal and throw a runtime exception. Expression _replaceLookupFunction(MethodInvocation node) { // The generated code looks like: // @@ -176,6 +249,39 @@ class _FfiUseSiteTransformer extends FfiTransformer { Arguments([lookupResult], types: [dartSignature, nativeSignature])); } + // We need to rewrite calls to 'fromFunction' into two calls, representing the + // compile-time and run-time aspects of creating the closure: + // + // final dynamic _#ffiCallback0 = Pointer.fromFunction(f, e) => + // _pointerFromFunction>( + // _nativeCallbackFunction(f, e)); + // + // ... _#ffiCallback0 ... + // + // We must implement this as a Kernel rewrite because must be a + // compile-time constant to any invocation of '_nativeCallbackFunction'. + // + // Creating this closure requires a runtime call, so we save the result in a + // synthetic top-level field to avoid recomputing it. + Expression _replaceFromFunction(StaticInvocation node) { + final nativeFunctionType = + InterfaceType(nativeFunctionClass, node.arguments.types); + final Field field = Field( + Name("_#ffiCallback${callbackCount++}", currentLibrary), + type: InterfaceType(pointerClass, [nativeFunctionType]), + initializer: StaticInvocation( + pointerFromFunctionProcedure, + Arguments([ + StaticInvocation(nativeCallbackFunctionProcedure, node.arguments) + ], types: [ + nativeFunctionType + ])), + isStatic: true, + isFinal: true); + currentLibrary.addMember(field); + return StaticGet(field); + } + @override visitMethodInvocation(MethodInvocation node) { super.visitMethodInvocation(node); @@ -233,7 +339,11 @@ class _FfiUseSiteTransformer extends FfiTransformer { _ensureNativeTypeSized(nativeType, node, target.name); _ensureNativeTypeToDartType(nativeType, dartType, node); } - } on _FfiStaticTypeError {} + } on _FfiStaticTypeError { + // It's OK to swallow the exception because the diagnostics issued will + // cause compilation to fail. By continuing, we can report more + // diagnostics before compilation ends. + } return node; } @@ -322,22 +432,17 @@ class _FfiUseSiteTransformer extends FfiTransformer { return false; } - void _ensureIsStatic(Expression node) { - if (!_isStatic(node)) { - diagnosticReporter.report( - templateFfiNotStatic.withArguments(fromFunctionMethod.name.name), - node.fileOffset, - 1, - node.location.file); - throw _FfiStaticTypeError(); + void _ensureIsStaticFunction(Expression node) { + if ((node is StaticGet && node.target is Procedure) || + (node is ConstantExpression && node.constant is TearOffConstant)) { + return; } - } - - bool _isStatic(Expression node) { - if (node is StaticGet) { - return node.target is Procedure; - } - return node is ConstantExpression; + diagnosticReporter.report( + templateFfiNotStatic.withArguments(fromFunctionMethod.name.name), + node.fileOffset, + 1, + node.location.file); + throw _FfiStaticTypeError(); } Class _extendsOrImplementsSealedClass(Class klass) { @@ -368,6 +473,7 @@ class _FfiUseSiteTransformer extends FfiTransformer { klass.fileOffset, 1, klass.location.file); + throw _FfiStaticTypeError(); } } } diff --git a/runtime/bin/ffi_test/ffi_test_functions.cc b/runtime/bin/ffi_test/ffi_test_functions.cc index 98d60c1ce38..85145b1eed0 100644 --- a/runtime/bin/ffi_test/ffi_test_functions.cc +++ b/runtime/bin/ffi_test/ffi_test_functions.cc @@ -759,7 +759,7 @@ DART_EXPORT int TestThrowExceptionDouble(double (*fn)()) { } DART_EXPORT int TestThrowExceptionPointer(void* (*fn)()) { - CHECK_EQ(fn(), reinterpret_cast(42)); + CHECK_EQ(fn(), nullptr); return 0; } diff --git a/runtime/lib/ffi.cc b/runtime/lib/ffi.cc index 347cd0557e0..f103f2e7449 100644 --- a/runtime/lib/ffi.cc +++ b/runtime/lib/ffi.cc @@ -429,88 +429,6 @@ DEFINE_NATIVE_ENTRY(Ffi_sizeOf, 1, 0) { return Integer::New(SizeOf(type_arg)); } -#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_PRECOMPILER) && \ - !defined(TARGET_ARCH_DBC) -// Generates assembly to trampoline from native code into Dart. -static uword CompileNativeCallback(const Function& c_signature, - const Function& dart_target, - const Instance& exceptional_return) { - Thread* const thread = Thread::Current(); - - uword entry_point = 0; - const int32_t callback_id = thread->AllocateFfiCallbackId(&entry_point); - ASSERT(NativeCallbackTrampolines::Enabled() == (entry_point != 0)); - - // 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::Handle(Symbols::New(thread, "FfiCallback")); - const Library& lib = Library::Handle(Z, Library::FfiLibrary()); - const Class& owner_class = Class::Handle(Z, 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 require that the exceptional return value for functions returning 'Void' - // must be 'null', since native code should not look at the result. - if (compiler::ffi::NativeTypeIsVoid( - AbstractType::Handle(c_signature.result_type())) && - !exceptional_return.IsNull()) { - Exceptions::ThrowUnsupportedError( - "Only 'null' may be used as the exceptional return value for a " - "callback returning void."); - } - - // We need to load the exceptional return value as a constant in the generated - // function. This means we need to ensure that it's in old space and has no - // (transitively) mutable fields. This is done by checking (asserting) that - // it's a built-in FFI class, whose fields are all immutable, or a - // user-defined Pointer class, which has no fields. - // - // TODO(36730): We'll need to extend this when we support passing/returning - // structs by value. - ASSERT(exceptional_return.IsNull() || exceptional_return.IsNumber() || - exceptional_return.IsPointer()); - if (!exceptional_return.IsSmi() && exceptional_return.IsNew()) { - function.SetFfiCallbackExceptionalReturn( - Instance::Handle(exceptional_return.CopyShallowToOldSpace(thread))); - } else { - function.SetFfiCallbackExceptionalReturn(exceptional_return); - } - - // 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); - - if (entry_point != 0) { - return entry_point; - } else { - return code.EntryPoint(); - } -} -#endif // Static invocations to this method are translated directly in streaming FGB // and bytecode FGB. However, we can still reach this entrypoint in the bytecode @@ -545,80 +463,6 @@ DEFINE_NATIVE_ENTRY(Ffi_asFunctionInternal, 2, 1) { #endif } -DEFINE_NATIVE_ENTRY(Ffi_fromFunction, 1, 2) { -#if defined(DART_PRECOMPILED_RUNTIME) || defined(DART_PRECOMPILER) || \ - defined(TARGET_ARCH_DBC) - // https://github.com/dart-lang/sdk/issues/37295 - // FFI is supported, but callbacks are not. - Exceptions::ThrowUnsupportedError( - "FFI callbacks are not yet supported in AOT or on DBC."); -#else - GET_NATIVE_TYPE_ARGUMENT(type_arg, arguments->NativeTypeArgAt(0)); - GET_NON_NULL_NATIVE_ARGUMENT(Closure, closure, arguments->NativeArgAt(0)); - GET_NON_NULL_NATIVE_ARGUMENT(Instance, exceptional_return, - arguments->NativeArgAt(1)); - - if (!type_arg.IsInstantiated() || !type_arg.IsFunctionType()) { - // TODO(35902): Remove this when dynamic invocations of fromFunction are - // prohibited. - Exceptions::ThrowUnsupportedError( - "Type argument to fromFunction must an instantiated function type."); - } - - const Function& native_signature = - Function::Handle(Type::Cast(type_arg).signature()); - Function& func = Function::Handle(closure.function()); - TypeArguments& type_args = TypeArguments::Handle(zone); - type_args = TypeArguments::New(1); - type_args.SetTypeAt(Pointer::kNativeTypeArgPos, type_arg); - type_args = type_args.Canonicalize(); - - Class& native_function_class = - Class::Handle(isolate->class_table()->At(kFfiNativeFunctionCid)); - const auto& error = - Error::Handle(native_function_class.EnsureIsFinalized(Thread::Current())); - if (!error.IsNull()) { - Exceptions::PropagateError(error); - } - - Type& native_function_type = Type::Handle( - Type::New(native_function_class, type_args, TokenPosition::kNoSource)); - native_function_type ^= - 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()); - - const AbstractType& return_type = - AbstractType::Handle(native_signature.result_type()); - if (compiler::ffi::NativeTypeIsVoid(return_type)) { - if (!exceptional_return.IsNull()) { - const String& error = String::Handle( - String::NewFormatted("Exceptional return argument to 'fromFunction' " - "must be null for functions returning void.")); - Exceptions::ThrowArgumentError(error); - } - } else if (!compiler::ffi::NativeTypeIsPointer(return_type) && - exceptional_return.IsNull()) { - const String& error = String::Handle(String::NewFormatted( - "Exceptional return argument to 'fromFunction' must not be null.")); - Exceptions::ThrowArgumentError(error); - } - - return Pointer::New( - native_function_type, - CompileNativeCallback(native_signature, func, exceptional_return)); -#endif -} - DEFINE_NATIVE_ENTRY(Ffi_asExternalTypedData, 0, 2) { GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0)); GET_NON_NULL_NATIVE_ARGUMENT(Integer, count, arguments->NativeArgAt(1)); @@ -692,8 +536,8 @@ DEFINE_NATIVE_ENTRY(Ffi_asExternalTypedData, 0, 2) { const auto& typed_data_class = Class::Handle(zone, isolate->class_table()->At(cid)); - const auto& error = Error::Handle( - zone, typed_data_class.EnsureIsFinalized(Thread::Current())); + const auto& error = + Error::Handle(zone, typed_data_class.EnsureIsFinalized(thread)); if (!error.IsNull()) { Exceptions::PropagateError(error); } @@ -703,6 +547,91 @@ DEFINE_NATIVE_ENTRY(Ffi_asExternalTypedData, 0, 2) { Heap::kNew); } +DEFINE_NATIVE_ENTRY(Ffi_nativeCallbackFunction, 1, 2) { +#if defined(TARGET_ARCH_DBC) + Exceptions::ThrowUnsupportedError( + "FFI callbacks are not yet supported on DBC."); +#elif defined(DART_PRECOMPILED_RUNTIME) || defined(DART_PRECOMPILER) + // Calls to this function are removed by the flow-graph builder in AOT. + // See StreamingFlowGraphBuilder::BuildFfiNativeCallbackFunction(). + UNREACHABLE(); +#else + GET_NATIVE_TYPE_ARGUMENT(type_arg, arguments->NativeTypeArgAt(0)); + GET_NON_NULL_NATIVE_ARGUMENT(Closure, closure, arguments->NativeArgAt(0)); + GET_NON_NULL_NATIVE_ARGUMENT(Instance, exceptional_return, + arguments->NativeArgAt(1)); + + ASSERT(type_arg.IsInstantiated() && type_arg.IsFunctionType()); + const Function& native_signature = + Function::Handle(zone, Type::Cast(type_arg).signature()); + Function& func = Function::Handle(zone, closure.function()); + + // 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()); + + // We are returning an object which is not an Instance here. This is only OK + // because we know that the result will be passed directly to + // _pointerFromFunction and will not leak out into user code. + arguments->SetReturn( + Function::Handle(zone, compiler::ffi::NativeCallbackFunction( + native_signature, func, exceptional_return))); + + // Because we have already set the return value. + return Object::sentinel().raw(); +#endif +} + +DEFINE_NATIVE_ENTRY(Ffi_pointerFromFunction, 1, 1) { + GET_NATIVE_TYPE_ARGUMENT(type_arg, arguments->NativeTypeArgAt(0)); + const Function& function = + Function::CheckedHandle(zone, arguments->NativeArg0()); + + Code& code = Code::Handle(zone); + +#if defined(DART_PRECOMPILED_RUNTIME) + code = function.CurrentCode(); + + // Blobs snapshots don't support BSS-relative relocations required by native + // callbacks (yet). Issue an error if the code has an unpatched relocation. + if (!code.VerifyBSSRelocations()) { + Exceptions::ThrowUnsupportedError( + "FFI callbacks are not yet supported in blobs snapshots. Please use " + "ELF or Assembly snapshots instead."); + } +#else + // 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( + zone, Compiler::CompileOptimizedFunction(thread, function)); + if (result.IsError()) { + Exceptions::PropagateError(Error::Cast(result)); + } + ASSERT(result.IsCode()); + code ^= result.raw(); +#endif + + ASSERT(!code.IsNull()); + thread->SetFfiCallbackCode(function.FfiCallbackId(), code); + + uword entry_point = code.EntryPoint(); +#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(TARGET_ARCH_DBC) + if (NativeCallbackTrampolines::Enabled()) { + entry_point = isolate->native_callback_trampolines()->TrampolineForId( + function.FfiCallbackId()); + } +#endif + + return Pointer::New(type_arg, entry_point); +} + #if defined(TARGET_ARCH_DBC) void FfiMarshalledArguments::SetFunctionAddress(uint64_t value) const { diff --git a/runtime/lib/ffi_patch.dart b/runtime/lib/ffi_patch.dart index c16cd728014..089f0c997d8 100644 --- a/runtime/lib/ffi_patch.dart +++ b/runtime/lib/ffi_patch.dart @@ -23,6 +23,25 @@ DS _asFunctionInternal( dynamic _asExternalTypedData(Pointer ptr, int count) native "Ffi_asExternalTypedData"; +// Returns a Function object for a native callback. +// +// Calls to [Pointer.fromFunction] are re-written by the FE into calls to this +// method + _pointerFromFunction. All three arguments must be constants. +// +// In AOT we evaluate calls to this function during precompilation and replace +// them with Constant instruction referencing the callback trampoline, to ensure +// that it will be precompiled. +// +// In all JIT modes we call a native runtime entry. We *cannot* use the IL +// implementation, since that would pull the callback trampoline into JIT +// snapshots. The callback trampolines can only be serialized into AOT snapshots +// because they embed the addresses of runtime routines in JIT mode. +Object _nativeCallbackFunction(Function target, + Object exceptionalReturn) native "Ffi_nativeCallbackFunction"; + +Pointer _pointerFromFunction(Object function) + native "Ffi_pointerFromFunction"; + @patch @pragma("vm:entry-point") class Pointer { @@ -32,10 +51,18 @@ class Pointer { @patch factory Pointer.fromAddress(int ptr) => _fromAddress(ptr); + // All static calls to this method are replaced by the FE into + // _nativeCallbackFunction + _pointerFromFunction. + // + // We still need to throw an error on a dynamic invocations, invocations + // through tearoffs or reflective calls. @patch static Pointer> fromFunction( @DartRepresentationOf("T") Function f, - Object exceptionalReturn) native "Ffi_fromFunction"; + [Object exceptionalReturn]) { + throw UnsupportedError( + "Pointer.fromFunction cannot be called dynamically."); + } // TODO(sjindel): When NNBD is available, we should change `value` to be // non-null. diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h index abf2199ca13..c947c02ca64 100644 --- a/runtime/vm/bootstrap_natives.h +++ b/runtime/vm/bootstrap_natives.h @@ -381,7 +381,8 @@ namespace dart { V(Ffi_cast, 1) \ V(Ffi_sizeOf, 0) \ V(Ffi_asFunctionInternal, 1) \ - V(Ffi_fromFunction, 2) \ + V(Ffi_nativeCallbackFunction, 2) \ + V(Ffi_pointerFromFunction, 1) \ V(Ffi_dl_open, 1) \ V(Ffi_dl_lookup, 2) \ V(Ffi_dl_getHandle, 1) \ diff --git a/runtime/vm/bss_relocs.cc b/runtime/vm/bss_relocs.cc new file mode 100644 index 00000000000..7e01696657c --- /dev/null +++ b/runtime/vm/bss_relocs.cc @@ -0,0 +1,17 @@ +// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +#include +#include +#include + +namespace dart { + +void BSS::Initialize(Thread* current, uword* bss_start) { + bss_start[BSS::RelocationIndex( + BSS::Relocation::DRT_GetThreadForNativeCallback)] = + reinterpret_cast(DLRT_GetThreadForNativeCallback); +} + +} // namespace dart diff --git a/runtime/vm/bss_relocs.h b/runtime/vm/bss_relocs.h new file mode 100644 index 00000000000..aa3c1f7fb28 --- /dev/null +++ b/runtime/vm/bss_relocs.h @@ -0,0 +1,29 @@ +// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +#ifndef RUNTIME_VM_BSS_RELOCS_H_ +#define RUNTIME_VM_BSS_RELOCS_H_ + +#include + +namespace dart { +class Thread; + +class BSS : public AllStatic { + public: + enum class Relocation : intptr_t { + DRT_GetThreadForNativeCallback = 0, + NumRelocations = 1 + }; + + static intptr_t RelocationIndex(Relocation reloc) { + return static_cast(reloc); + } + + static void Initialize(Thread* current, uword* bss); +}; + +} // namespace dart + +#endif // RUNTIME_VM_BSS_RELOCS_H_ diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc index 5826e6ca70e..70459fd150c 100644 --- a/runtime/vm/clustered_snapshot.cc +++ b/runtime/vm/clustered_snapshot.cc @@ -6,6 +6,7 @@ #include "platform/assert.h" #include "vm/bootstrap.h" +#include "vm/bss_relocs.h" #include "vm/class_id.h" #include "vm/code_observers.h" #include "vm/compiler/backend/code_statistics.h" @@ -799,9 +800,12 @@ class FfiTrampolineDataSerializationCluster : public SerializationCluster { AutoTraceObject(data); WriteFromTo(data); - // TODO(37295): FFI callbacks shouldn't be written to a snapshot. They - // should only be referenced by the callback registry in Thread. - ASSERT(data->ptr()->callback_id_ == 0); + if (s->kind() == Snapshot::kFullAOT) { + s->WriteUnsigned(data->ptr()->callback_id_); + } else { + // FFI callbacks can only be written to AOT snapshots. + ASSERT(data->ptr()->callback_target_ == Object::null()); + } } } @@ -833,7 +837,8 @@ class FfiTrampolineDataDeserializationCluster : public DeserializationCluster { Deserializer::InitializeHeader(data, kFfiTrampolineDataCid, FfiTrampolineData::InstanceSize()); ReadFromTo(data); - data->ptr()->callback_id_ = 0; + data->ptr()->callback_id_ = + d->kind() == Snapshot::kFullAOT ? d->ReadUnsigned() : 0; } } }; @@ -5816,6 +5821,17 @@ RawApiError* FullSnapshotReader::ReadIsolateSnapshot() { } } } + + // Initialize symbols in the BSS, if present. + ASSERT(Snapshot::IncludesCode(kind_)); + Image image(instructions_image_); + if (image.bss_offset() != 0) { + // The const cast is safe because we're translating from the start of the + // instructions (read-only) to the start of the BSS (read-write). + uword* const bss_start = const_cast(reinterpret_cast( + instructions_image_ + image.bss_offset())); + BSS::Initialize(thread_, bss_start); + } #endif // defined(DART_PRECOMPILED_RUNTIME) return ApiError::null(); diff --git a/runtime/vm/code_descriptors.cc b/runtime/vm/code_descriptors.cc index 4d8f1b9e295..0d4bd00b5f6 100644 --- a/runtime/vm/code_descriptors.cc +++ b/runtime/vm/code_descriptors.cc @@ -15,10 +15,13 @@ void DescriptorList::AddDescriptor(RawPcDescriptors::Kind kind, TokenPosition token_pos, intptr_t try_index) { ASSERT((kind == RawPcDescriptors::kRuntimeCall) || + (kind == RawPcDescriptors::kBSSRelocation) || (kind == RawPcDescriptors::kOther) || (deopt_id != DeoptId::kNone)); - // When precompiling, we only use pc descriptors for exceptions. - if (!FLAG_precompiled_mode || try_index != -1) { + // When precompiling, we only use pc descriptors for exceptions and + // relocations. + if (!FLAG_precompiled_mode || try_index != -1 || + kind == RawPcDescriptors::kBSSRelocation) { int32_t merged_kind_try = RawPcDescriptors::MergedKindTry::Encode(kind, try_index); diff --git a/runtime/vm/compiler/assembler/assembler.cc b/runtime/vm/compiler/assembler/assembler.cc index f6c6175ebf9..6b5427d04ad 100644 --- a/runtime/vm/compiler/assembler/assembler.cc +++ b/runtime/vm/compiler/assembler/assembler.cc @@ -30,6 +30,31 @@ DEFINE_FLAG(bool, use_far_branches, false, "Enable far branches for ARM."); namespace compiler { +AssemblerBase::~AssemblerBase() {} + +intptr_t AssemblerBase::InsertAlignedRelocation(BSS::Relocation reloc) { + // We cannot put a relocation at the very start (it's not a valid + // instruction)! + ASSERT(CodeSize() != 0); + + // Align to a target word boundary. + const intptr_t offset = + Utils::RoundUp(CodeSize(), compiler::target::kWordSize); + + while (CodeSize() < offset) { + Breakpoint(); + } + ASSERT(CodeSize() == offset); + + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + buffer_.Emit(BSS::RelocationIndex(reloc) * + compiler::target::kWordSize); + + ASSERT(CodeSize() == (offset + compiler::target::kWordSize)); + + return offset; +} + static uword NewContents(intptr_t capacity) { Zone* zone = Thread::Current()->zone(); uword result = zone->AllocUnsafe(capacity); diff --git a/runtime/vm/compiler/assembler/assembler.h b/runtime/vm/compiler/assembler/assembler.h index cf4d6e652b2..645728aba31 100644 --- a/runtime/vm/compiler/assembler/assembler.h +++ b/runtime/vm/compiler/assembler/assembler.h @@ -305,7 +305,7 @@ class AssemblerBase : public StackResource { prologue_offset_(-1), has_single_entry_point_(true), object_pool_builder_(object_pool_builder) {} - virtual ~AssemblerBase() {} + virtual ~AssemblerBase(); intptr_t CodeSize() const { return buffer_.Size(); } @@ -320,6 +320,10 @@ class AssemblerBase : public StackResource { void Comment(const char* format, ...) PRINTF_ATTRIBUTE(2, 3); static bool EmittingComments(); + virtual void Breakpoint() = 0; + + intptr_t InsertAlignedRelocation(BSS::Relocation reloc); + void Unimplemented(const char* message); void Untested(const char* message); void Unreachable(const char* message); diff --git a/runtime/vm/compiler/assembler/assembler_arm.h b/runtime/vm/compiler/assembler/assembler_arm.h index df8ff93cdf8..904890d1825 100644 --- a/runtime/vm/compiler/assembler/assembler_arm.h +++ b/runtime/vm/compiler/assembler/assembler_arm.h @@ -392,7 +392,7 @@ class Assembler : public AssemblerBase { #endif // TESTING || DEBUG // Debugging and bringup support. - void Breakpoint() { bkpt(0); } + void Breakpoint() override { bkpt(0); } void Stop(const char* message) override; static void InitializeMemoryWithBreakpoints(uword data, intptr_t length); diff --git a/runtime/vm/compiler/assembler/assembler_arm64.h b/runtime/vm/compiler/assembler/assembler_arm64.h index eb8c59e079c..972b1dcae9b 100644 --- a/runtime/vm/compiler/assembler/assembler_arm64.h +++ b/runtime/vm/compiler/assembler/assembler_arm64.h @@ -485,7 +485,7 @@ class Assembler : public AssemblerBase { void set_use_far_branches(bool b) { use_far_branches_ = b; } // Debugging and bringup support. - void Breakpoint() { brk(0); } + void Breakpoint() override { brk(0); } void Stop(const char* message) override; static void InitializeMemoryWithBreakpoints(uword data, intptr_t length); diff --git a/runtime/vm/compiler/assembler/assembler_dbc.h b/runtime/vm/compiler/assembler/assembler_dbc.h index df2a83c1874..0737026cc69 100644 --- a/runtime/vm/compiler/assembler/assembler_dbc.h +++ b/runtime/vm/compiler/assembler/assembler_dbc.h @@ -43,6 +43,7 @@ class Assembler : public AssemblerBase { void MonomorphicCheckedEntryAOT() {} // Debugging and bringup support. + void Breakpoint() override { Stop("Breakpoint!"); } void Stop(const char* message) override; static void InitializeMemoryWithBreakpoints(uword data, intptr_t length); diff --git a/runtime/vm/compiler/assembler/assembler_ia32.h b/runtime/vm/compiler/assembler/assembler_ia32.h index cfc14a2915c..490c0648cb2 100644 --- a/runtime/vm/compiler/assembler/assembler_ia32.h +++ b/runtime/vm/compiler/assembler/assembler_ia32.h @@ -837,7 +837,7 @@ class Assembler : public AssemblerBase { Register temp); // Debugging and bringup support. - void Breakpoint() { int3(); } + void Breakpoint() override { int3(); } void Stop(const char* message) override; static void InitializeMemoryWithBreakpoints(uword data, intptr_t length); diff --git a/runtime/vm/compiler/assembler/assembler_x64.h b/runtime/vm/compiler/assembler/assembler_x64.h index 3f9992ed411..c8f07094f61 100644 --- a/runtime/vm/compiler/assembler/assembler_x64.h +++ b/runtime/vm/compiler/assembler/assembler_x64.h @@ -938,7 +938,7 @@ class Assembler : public AssemblerBase { void GenerateUnRelocatedPcRelativeCall(intptr_t offset_into_target = 0); // Debugging and bringup support. - void Breakpoint() { int3(); } + void Breakpoint() override { int3(); } void Stop(const char* message) override; static void InitializeMemoryWithBreakpoints(uword data, intptr_t length); diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc index f6f3902e986..27600c2a8ab 100644 --- a/runtime/vm/compiler/backend/flow_graph_compiler.cc +++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc @@ -242,6 +242,13 @@ bool FlowGraphCompiler::CanOSRFunction() const { return isolate()->use_osr() && CanOptimizeFunction() && !is_optimizing(); } +void FlowGraphCompiler::InsertBSSRelocation(BSS::Relocation reloc) { + const intptr_t offset = assembler()->InsertAlignedRelocation(reloc); + AddDescriptor(RawPcDescriptors::kBSSRelocation, /*pc_offset=*/offset, + /*deopt_id=*/DeoptId::kNone, TokenPosition::kNoSource, + /*try_index=*/-1); +} + bool FlowGraphCompiler::ForceSlowPathForStackOverflow() const { #if !defined(PRODUCT) if ((FLAG_stacktrace_every > 0) || (FLAG_deoptimize_every > 0) || @@ -1400,7 +1407,9 @@ void FlowGraphCompiler::GenerateStaticCall(intptr_t deopt_id, : ic_data.arguments_descriptor()); ASSERT(ArgumentsDescriptor(arguments_descriptor).TypeArgsLen() == args_info.type_args_len); - if (is_optimizing() && !ForcedOptimization()) { + // Force-optimized functions lack the deopt info which allows patching of + // optimized static calls. + if (is_optimizing() && (!ForcedOptimization() || FLAG_precompiled_mode)) { 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 b8d3114954e..4c26d2b0f13 100644 --- a/runtime/vm/compiler/backend/flow_graph_compiler.h +++ b/runtime/vm/compiler/backend/flow_graph_compiler.h @@ -428,6 +428,8 @@ class FlowGraphCompiler : public ValueObject { bool CanOSRFunction() const; bool is_optimizing() const { return is_optimizing_; } + void InsertBSSRelocation(BSS::Relocation reloc); + // The function was fully intrinsified, so the body is unreachable. // // We still need to compile the body in unoptimized mode because the diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc index aa05061602d..6ed9d5bef61 100644 --- a/runtime/vm/compiler/backend/il_arm.cc +++ b/runtime/vm/compiler/backend/il_arm.cc @@ -1137,10 +1137,6 @@ void NativeEntryInstr::SaveArgument(FlowGraphCompiler* compiler, } void NativeEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { - if (FLAG_precompiled_mode) { - UNREACHABLE(); - } - // Constant pool cannot be used until we enter the actual Dart frame. __ set_constant_pool_allowed(false); @@ -1165,8 +1161,41 @@ void NativeEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { // Load the thread object. If we were called by a trampoline, the thread is // already loaded. - // - // TODO(35765): Fix linking issue on AOT. + if (FLAG_precompiled_mode) { + compiler::Label skip_reloc; + __ b(&skip_reloc); + compiler->InsertBSSRelocation( + BSS::Relocation::DRT_GetThreadForNativeCallback); + __ Bind(&skip_reloc); + + // For historical reasons, the PC on ARM points 8 bytes (two instructions) + // past the current instruction. + __ sub( + R0, PC, + compiler::Operand(Instr::kPCReadOffset + compiler::target::kWordSize)); + + // R0 holds the address of the relocation. + __ ldr(R1, compiler::Address(R0)); + + // R1 holds the relocation itself: R0 - bss_start. + // R0 = R0 + (bss_start - R0) = bss_start + __ add(R0, R0, compiler::Operand(R1)); + + // R0 holds the start of the BSS section. + // Load the "get-thread" routine: *bss_start. + __ ldr(R1, compiler::Address(R0)); + } else if (!NativeCallbackTrampolines::Enabled()) { + // In JIT mode, we can just paste the address of the runtime entry into the + // generated code directly. This is not a problem since we don't save + // callbacks into JIT snapshots. + ASSERT(kWordSize == compiler::target::kWordSize); + __ LoadImmediate( + R1, static_cast( + reinterpret_cast(DLRT_GetThreadForNativeCallback))); + } + + // Load the thread object. If we were called by a trampoline, the thread is + // already loaded. if (!NativeCallbackTrampolines::Enabled()) { // Create another frame to align the frame before continuing in "native" // code. @@ -1174,8 +1203,6 @@ void NativeEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { __ ReserveAlignedFrameSpace(0); __ LoadImmediate(R0, callback_id_); - __ LoadImmediate( - R1, reinterpret_cast(DLRT_GetThreadForNativeCallback)); __ blx(R1); __ mov(THR, compiler::Operand(R0)); @@ -6953,7 +6980,8 @@ LocationSummary* BitCastInstr::MakeLocationSummary(Zone* zone, bool opt) const { break; case kUnboxedFloat: case kUnboxedDouble: - summary->set_in(0, Location::RequiresFpuRegister()); + // Choose an FPU register with corresponding D and S registers. + summary->set_in(0, Location::FpuRegisterLocation(Q0)); break; default: UNREACHABLE(); @@ -6969,7 +6997,8 @@ LocationSummary* BitCastInstr::MakeLocationSummary(Zone* zone, bool opt) const { break; case kUnboxedFloat: case kUnboxedDouble: - summary->set_out(0, Location::RequiresFpuRegister()); + // Choose an FPU register with corresponding D and S registers. + summary->set_out(0, Location::FpuRegisterLocation(Q0)); break; default: UNREACHABLE(); diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc index f6bfdacad73..3f7f28fd33b 100644 --- a/runtime/vm/compiler/backend/il_arm64.cc +++ b/runtime/vm/compiler/backend/il_arm64.cc @@ -1020,10 +1020,6 @@ void NativeEntryInstr::SaveArgument(FlowGraphCompiler* compiler, } void NativeEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { - if (FLAG_precompiled_mode) { - UNREACHABLE(); - } - // Constant pool cannot be used until we enter the actual Dart frame. __ set_constant_pool_allowed(false); @@ -1052,8 +1048,33 @@ void NativeEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { // Load the thread object. If we were called by a trampoline, the thread is // already loaded. - // - // TODO(35765): Fix linking issue on AOT. + if (FLAG_precompiled_mode) { + compiler::Label skip_reloc; + __ b(&skip_reloc); + compiler->InsertBSSRelocation( + BSS::Relocation::DRT_GetThreadForNativeCallback); + __ Bind(&skip_reloc); + + __ adr(R0, compiler::Immediate(-compiler::target::kWordSize)); + + // R0 holds the address of the relocation. + __ ldr(R1, compiler::Address(R0)); + + // R1 holds the relocation itself: R0 - bss_start. + // R0 = R0 + (bss_start - R0) = bss_start + __ add(R0, R0, compiler::Operand(R1)); + + // R0 holds the start of the BSS section. + // Load the "get-thread" routine: *bss_start. + __ ldr(R1, compiler::Address(R0)); + } else if (!NativeCallbackTrampolines::Enabled()) { + // In JIT mode, we can just paste the address of the runtime entry into the + // generated code directly. This is not a problem since we don't save + // callbacks into JIT snapshots. + __ LoadImmediate( + R1, reinterpret_cast(DLRT_GetThreadForNativeCallback)); + } + if (!NativeCallbackTrampolines::Enabled()) { // Create another frame to align the frame before continuing in "native" // code. @@ -1061,8 +1082,6 @@ void NativeEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { __ ReserveAlignedFrameSpace(0); __ LoadImmediate(R0, callback_id_); - __ LoadImmediate( - R1, reinterpret_cast(DLRT_GetThreadForNativeCallback)); __ blr(R1); __ mov(THR, R0); diff --git a/runtime/vm/compiler/backend/il_ia32.cc b/runtime/vm/compiler/backend/il_ia32.cc index be334114edf..ff3df265178 100644 --- a/runtime/vm/compiler/backend/il_ia32.cc +++ b/runtime/vm/compiler/backend/il_ia32.cc @@ -1036,15 +1036,16 @@ void NativeEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { __ pushl(EDI); // Load the thread object. - // Linking in AOT is not relevant here since we don't support AOT for IA32. + // // Create another frame to align the frame before continuing in "native" code. // If we were called by a trampoline, it has already loaded the thread. + ASSERT(!FLAG_precompiled_mode); // No relocation for AOT linking. if (!NativeCallbackTrampolines::Enabled()) { __ EnterFrame(0); __ ReserveAlignedFrameSpace(compiler::target::kWordSize); __ movl(compiler::Address(SPREG, 0), compiler::Immediate(callback_id_)); - __ movl(EAX, compiler::Immediate(reinterpret_cast( + __ movl(EAX, compiler::Immediate(reinterpret_cast( DLRT_GetThreadForNativeCallback))); __ call(EAX); __ movl(THR, EAX); diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc index c221ba2040e..10face26e55 100644 --- a/runtime/vm/compiler/backend/il_x64.cc +++ b/runtime/vm/compiler/backend/il_x64.cc @@ -1024,10 +1024,6 @@ void NativeEntryInstr::SaveArgument(FlowGraphCompiler* compiler, } void NativeEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { - if (FLAG_precompiled_mode) { - UNREACHABLE(); - } - __ Bind(compiler->GetJumpLabel(this)); // Create a dummy frame holding the pushed arguments. This simplifies @@ -1055,9 +1051,38 @@ void NativeEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { __ PushRegisters(CallingConventions::kCalleeSaveCpuRegisters, CallingConventions::kCalleeSaveXmmRegisters); - // Load the thread object. - // TODO(35765): Fix linking issue on AOT. - // + // Load the address of DLRT_GetThreadForNativeCallback without using Thread. + if (FLAG_precompiled_mode) { + compiler::Label skip_reloc; + __ jmp(&skip_reloc); + compiler->InsertBSSRelocation( + BSS::Relocation::DRT_GetThreadForNativeCallback); + const intptr_t reloc_end = __ CodeSize(); + __ Bind(&skip_reloc); + + const intptr_t kLeaqLength = 7; + __ leaq(RAX, compiler::Address::AddressRIPRelative( + -kLeaqLength - compiler::target::kWordSize)); + ASSERT((__ CodeSize() - reloc_end) == kLeaqLength); + + // RAX holds the address of the relocation. + __ movq(RCX, compiler::Address(RAX, 0)); + + // RCX holds the relocation itself: RAX - bss_start. + // RAX = RAX + (bss_start - RAX) = bss_start + __ addq(RAX, RCX); + + // RAX holds the start of the BSS section. + // Load the "get-thread" routine: *bss_start. + __ movq(RAX, compiler::Address(RAX, 0)); + } else if (!NativeCallbackTrampolines::Enabled()) { + // In JIT mode, we can just paste the address of the runtime entry into the + // generated code directly. This is not a problem since we don't save + // callbacks into JIT snapshots. + __ movq(RAX, compiler::Immediate(reinterpret_cast( + DLRT_GetThreadForNativeCallback))); + } + // Create another frame to align the frame before continuing in "native" code. // If we were called by a trampoline, it has already loaded the thread. if (!NativeCallbackTrampolines::Enabled()) { @@ -1066,8 +1091,6 @@ void NativeEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { COMPILE_ASSERT(RAX != CallingConventions::kArg1Reg); __ movq(CallingConventions::kArg1Reg, compiler::Immediate(callback_id_)); - __ movq(RAX, compiler::Immediate(reinterpret_cast( - DLRT_GetThreadForNativeCallback))); __ CallCFunction(RAX); __ movq(THR, RAX); diff --git a/runtime/vm/compiler/ffi.cc b/runtime/vm/compiler/ffi.cc index 5313922c2e7..3b3ce8c480d 100644 --- a/runtime/vm/compiler/ffi.cc +++ b/runtime/vm/compiler/ffi.cc @@ -210,6 +210,58 @@ Representation ResultRepresentationBase(const Function& signature) { #if !defined(TARGET_ARCH_DBC) +RawFunction* NativeCallbackFunction(const Function& c_signature, + const Function& dart_target, + const Instance& exceptional_return) { + 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 they have may have duplicate names. + Zone* const zone = thread->zone(); + const auto& name = String::Handle( + zone, Symbols::FromConcat(thread, Symbols::FfiCallback(), + String::Handle(zone, dart_target.name()))); + const Library& lib = Library::Handle(zone, Library::FfiLibrary()); + const Class& owner_class = Class::Handle(zone, lib.toplevel_class()); + const Function& function = + Function::Handle(zone, Function::New(name, RawFunction::kFfiTrampoline, + /*is_static=*/true, + /*is_const=*/false, + /*is_abstract=*/false, + /*is_external=*/false, + /*is_native=*/false, owner_class, + TokenPosition::kNoSource)); + 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 need to load the exceptional return value as a constant in the generated + // function. Even though the FE ensures that it is a constant, it could still + // be a literal allocated in new space. We need to copy it into old space in + // that case. + // + // Exceptional return values currently cannot be pointers because we don't + // have constant pointers. + // + // TODO(36730): We'll need to extend this when we support passing/returning + // structs by value. + ASSERT(exceptional_return.IsNull() || exceptional_return.IsNumber()); + if (!exceptional_return.IsSmi() && exceptional_return.IsNew()) { + function.SetFfiCallbackExceptionalReturn(Instance::Handle( + zone, exceptional_return.CopyShallowToOldSpace(thread))); + } else { + function.SetFfiCallbackExceptionalReturn(exceptional_return); + } + + return function.raw(); +} + ZoneGrowableArray* ArgumentRepresentations( const Function& signature) { return ArgumentRepresentationsBase(signature); @@ -650,27 +702,6 @@ Representation FfiSignatureDescriptor::ResultRepresentation() const { #endif // defined(TARGET_ARCH_DBC) -bool IsAsFunctionInternal(Zone* zone, Isolate* isolate, const Function& func) { - Object& asFunctionInternal = - Object::Handle(zone, isolate->object_store()->ffi_as_function_internal()); - if (asFunctionInternal.raw() == Object::null()) { - // Cache the reference. - const Library& ffi = - Library::Handle(zone, isolate->object_store()->ffi_library()); - asFunctionInternal = - ffi.LookupFunctionAllowPrivate(Symbols::AsFunctionInternal()); - // Cannot assert that 'asFunctionInternal' is found because it may have been - // tree-shaken. - if (asFunctionInternal.IsNull()) { - // Set the entry in the object store to a sentinel so we don't try to look - // it up again. - asFunctionInternal = Object::sentinel().raw(); - } - isolate->object_store()->set_ffi_as_function_internal(asFunctionInternal); - } - return func.raw() == asFunctionInternal.raw(); -} - #endif // !defined(DART_PRECOMPILED_RUNTIME) } // namespace ffi diff --git a/runtime/vm/compiler/ffi.h b/runtime/vm/compiler/ffi.h index 5c743d4dff6..7922a80e2b1 100644 --- a/runtime/vm/compiler/ffi.h +++ b/runtime/vm/compiler/ffi.h @@ -56,6 +56,10 @@ RawFunction* TrampolineFunction(const Function& dart_signature, #if !defined(TARGET_ARCH_DBC) +RawFunction* NativeCallbackFunction(const Function& c_signature, + const Function& dart_target, + const Instance& exceptional_return); + // Unboxed representations of the arguments to a C signature function. ZoneGrowableArray* ArgumentRepresentations( const Function& signature); @@ -145,11 +149,8 @@ class CallbackArgumentTranslator : public ValueObject { intptr_t argument_slots_used_ = 0; intptr_t argument_slots_required_ = 0; }; - #endif // defined(TARGET_ARCH_DBC) -bool IsAsFunctionInternal(Zone* zone, Isolate* isolate, const Function& func); - } // namespace ffi } // namespace compiler diff --git a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc index b8077cd7a6d..034716b5958 100644 --- a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc +++ b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc @@ -807,9 +807,14 @@ void BytecodeFlowGraphBuilder::BuildDirectCall() { const Function& target = Function::Cast(ConstantAt(DecodeOperandD()).value()); const intptr_t argc = DecodeOperandF().value(); - if (compiler::ffi::IsAsFunctionInternal(Z, isolate(), target)) { + const auto recognized_kind = MethodRecognizer::RecognizeKind(target); + if (recognized_kind == MethodRecognizer::kFfiAsFunctionInternal) { BuildFfiAsFunction(); return; + } else if (FLAG_precompiled_mode && + recognized_kind == MethodRecognizer::kFfiNativeCallbackFunction) { + BuildFfiNativeCallbackFunction(); + return; } // Recognize identical() call. @@ -826,7 +831,7 @@ void BytecodeFlowGraphBuilder::BuildDirectCall() { } if (!FLAG_causal_async_stacks && - target.recognized_kind() == MethodRecognizer::kAsyncStackTraceHelper) { + recognized_kind == MethodRecognizer::kAsyncStackTraceHelper) { ASSERT(argc == 1); // Drop the ignored parameter to _asyncStackTraceHelper(:async_op). code_ += B->Drop(); @@ -834,7 +839,7 @@ void BytecodeFlowGraphBuilder::BuildDirectCall() { return; } - if (target.recognized_kind() == MethodRecognizer::kStringBaseInterpolate) { + if (recognized_kind == MethodRecognizer::kStringBaseInterpolate) { ASSERT(argc == 1); code_ += B->StringInterpolate(position_); return; @@ -1824,6 +1829,45 @@ void BytecodeFlowGraphBuilder::BuildFfiAsFunction() { code_ += B->BuildFfiAsFunctionInternalCall(type_args); } +// Builds graph for a call to 'dart:ffi::_nativeCallbackFunction'. +// The call-site must look like this (guaranteed by the FE which inserts it): +// +// _nativeCallbackFunction(target, exceptionalReturn) +// +// Therefore the stack shall look like: +// +// => ensured (by FE) to be a constant +// => closure, ensured (by FE) to be a (non-partially-instantiated) +// static tearoff +// => [NativeSignatureType] +void BytecodeFlowGraphBuilder::BuildFfiNativeCallbackFunction() { +#if defined(TARGET_ARCH_DBC) + UNREACHABLE(); +#else + const TypeArguments& type_args = + TypeArguments::Cast(B->Peek(/*depth=*/2)->AsConstant()->value()); + ASSERT(type_args.IsInstantiated() && type_args.Length() == 1); + const Function& native_sig = Function::Handle( + Z, Type::Cast(AbstractType::Handle(Z, type_args.TypeAt(0))).signature()); + + const Closure& target_closure = + Closure::Cast(B->Peek(/*depth=*/1)->AsConstant()->value()); + ASSERT(!target_closure.IsNull()); + Function& target = Function::Handle(Z, target_closure.function()); + ASSERT(!target.IsNull() && target.IsImplicitClosureFunction()); + target = target.parent_function(); + + const Instance& exceptional_return = + Instance::Cast(B->Peek(/*depth=*/0)->AsConstant()->value()); + + const Function& result = + Function::ZoneHandle(Z, compiler::ffi::NativeCallbackFunction( + native_sig, target, exceptional_return)); + code_ += B->Constant(result); + code_ += B->DropTempsPreserveTop(3); +#endif +} + void BytecodeFlowGraphBuilder::BuildDebugStepCheck() { #if !defined(PRODUCT) if (build_debug_step_checks_) { diff --git a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h index 88bfa443d06..1e84f92e49c 100644 --- a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h +++ b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h @@ -172,6 +172,7 @@ class BytecodeFlowGraphBuilder { void BuildInstruction(KernelBytecode::Opcode opcode); void BuildFfiAsFunction(); + void BuildFfiNativeCallbackFunction(); void BuildDebugStepCheck(); #define DECLARE_BUILD_METHOD(name, encoding, kind, op1, op2, op3) \ diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc index 54d2b6decfa..7ff851bae90 100644 --- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc +++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc @@ -3060,8 +3060,12 @@ Fragment StreamingFlowGraphBuilder::BuildStaticInvocation(bool is_const, ++argument_count; } - if (compiler::ffi::IsAsFunctionInternal(Z, H.isolate(), target)) { + const auto recognized_kind = MethodRecognizer::RecognizeKind(target); + if (recognized_kind == MethodRecognizer::kFfiAsFunctionInternal) { return BuildFfiAsFunctionInternal(); + } else if (FLAG_precompiled_mode && + recognized_kind == MethodRecognizer::kFfiNativeCallbackFunction) { + return BuildFfiNativeCallbackFunction(); } Fragment instructions; @@ -3069,7 +3073,7 @@ Fragment StreamingFlowGraphBuilder::BuildStaticInvocation(bool is_const, const bool special_case_nop_async_stack_trace_helper = !FLAG_causal_async_stacks && - target.recognized_kind() == MethodRecognizer::kAsyncStackTraceHelper; + recognized_kind == MethodRecognizer::kAsyncStackTraceHelper; const bool special_case_unchecked_cast = klass.IsTopLevel() && (klass.library() == Library::InternalLibrary()) && @@ -5048,6 +5052,65 @@ Fragment StreamingFlowGraphBuilder::BuildFfiAsFunctionInternal() { return code; } +Fragment StreamingFlowGraphBuilder::BuildFfiNativeCallbackFunction() { +#if defined(TARGET_ARCH_DBC) + UNREACHABLE(); +#else + // The call-site must look like this (guaranteed by the FE which inserts it): + // + // _nativeCallbackFunction(target, exceptionalReturn) + // + // The FE also guarantees that all three arguments are constants. + + const intptr_t argc = ReadUInt(); // read argument count + ASSERT(argc == 2); // target, exceptionalReturn + + const intptr_t list_length = ReadListLength(); // read types list length + ASSERT(list_length == 1); // native signature + const TypeArguments& type_arguments = + T.BuildTypeArguments(list_length); // read types. + ASSERT(type_arguments.Length() == 1 && type_arguments.IsInstantiated()); + const Function& native_sig = Function::Handle( + Z, Type::Cast(AbstractType::Handle(Z, type_arguments.TypeAt(0))) + .signature()); + + Fragment code; + const intptr_t positional_count = + ReadListLength(); // read positional argument count + ASSERT(positional_count == 2); + + // Read target expression and extract the target function. + code += BuildExpression(); // build first positional argument (target) + Definition* target_def = B->Peek(); + ASSERT(target_def->IsConstant()); + const Closure& target_closure = + Closure::Cast(target_def->AsConstant()->value()); + ASSERT(!target_closure.IsNull()); + Function& target = Function::Handle(Z, target_closure.function()); + ASSERT(!target.IsNull() && target.IsImplicitClosureFunction()); + target = target.parent_function(); + code += Drop(); + + // Build second positional argument (exceptionalReturn). + code += BuildExpression(); + Definition* exceptional_return_def = B->Peek(); + ASSERT(exceptional_return_def->IsConstant()); + const Instance& exceptional_return = + Instance::Cast(exceptional_return_def->AsConstant()->value()); + code += Drop(); + + const intptr_t named_args_len = + ReadListLength(); // skip (empty) named arguments list + ASSERT(named_args_len == 0); + + const Function& result = + Function::ZoneHandle(Z, compiler::ffi::NativeCallbackFunction( + native_sig, target, exceptional_return)); + code += Constant(result); + return code; +#endif +} + } // namespace kernel } // namespace dart diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h index 0b4f7d5505d..2cdbb285cd9 100644 --- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h +++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h @@ -356,6 +356,10 @@ class StreamingFlowGraphBuilder : public KernelReaderHelper { // Kernel buffer and pushes the resulting closure. Fragment BuildFfiAsFunctionInternal(); + // Build build FG for '_nativeCallbackFunction'. Reads an Arguments from the + // Kernel buffer and pushes the resulting Function object. + Fragment BuildFfiNativeCallbackFunction(); + FlowGraphBuilder* flow_graph_builder_; ActiveClass* const active_class_; TypeTranslator type_translator_; diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc index 6f7624d2661..4748658f24e 100644 --- a/runtime/vm/compiler/frontend/kernel_to_il.cc +++ b/runtime/vm/compiler/frontend/kernel_to_il.cc @@ -2398,6 +2398,7 @@ Fragment FlowGraphBuilder::FfiPointerFromAddress(const Type& result_type) { // do not appear in the type arguments to a any Pointer classes in an FFI // signature. ASSERT(args.IsNull() || args.IsInstantiated()); + args = args.Canonicalize(); Fragment code; code += Constant(args); @@ -2451,14 +2452,6 @@ Fragment FlowGraphBuilder::FfiConvertArgumentToNative( const Representation native_representation) { Fragment body; - // Return 0 for void. - if (compiler::ffi::NativeTypeIsVoid(ffi_type)) { - body += Drop(); - body += IntConstant(0); - body += UnboxTruncate(kUnboxedFfiIntPtr); - return body; - } - // Check for 'null'. body += LoadLocal(MakeTemporary()); body <<= new (Z) CheckNullInstr(Pop(), String::ZoneHandle(Z, function.name()), @@ -2615,9 +2608,20 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfFfiCallback(const Function& function) { /*needs_stacktrace=*/false, /*is_synthesized=*/true); // Return the "exceptional return" value given in 'fromFunction'. - catch_body += Constant( - Instance::ZoneHandle(Z, function.FfiCallbackExceptionalReturn())); - catch_body += FfiConvertArgumentToNative(function, ffi_type, result_rep); + // + // For pointer and void return types, the exceptional return is always null -- + // return 0 instead. + if (compiler::ffi::NativeTypeIsPointer(ffi_type) || + compiler::ffi::NativeTypeIsVoid(ffi_type)) { + ASSERT(function.FfiCallbackExceptionalReturn() == Object::null()); + catch_body += IntConstant(0); + catch_body += UnboxTruncate(kUnboxedFfiIntPtr); + } else { + catch_body += Constant( + Instance::ZoneHandle(Z, function.FfiCallbackExceptionalReturn())); + catch_body += FfiConvertArgumentToNative(function, ffi_type, result_rep); + } + catch_body += NativeReturn(result_rep); --catch_depth_; diff --git a/runtime/vm/compiler/recognized_methods_list.h b/runtime/vm/compiler/recognized_methods_list.h index 9ecb99466bb..3af03f5204d 100644 --- a/runtime/vm/compiler/recognized_methods_list.h +++ b/runtime/vm/compiler/recognized_methods_list.h @@ -143,6 +143,8 @@ namespace dart { V(::, _classRangeCheck, ClassRangeCheck, 0xca52e30a) \ V(::, _asyncStackTraceHelper, AsyncStackTraceHelper, 0xaeaed5cb) \ V(::, _abi, FfiAbi, 0xf2e89620) \ + V(::, _asFunctionInternal, FfiAsFunctionInternal, 0x82525e9e) \ + V(::, _nativeCallbackFunction, FfiNativeCallbackFunction, 0x591fb33c) \ // List of intrinsics: // (class-name, function-name, intrinsification method, fingerprint). diff --git a/runtime/vm/compiler/runtime_api.h b/runtime/vm/compiler/runtime_api.h index fe9e2532023..05794184aef 100644 --- a/runtime/vm/compiler/runtime_api.h +++ b/runtime/vm/compiler/runtime_api.h @@ -21,6 +21,7 @@ #include "platform/globals.h" #include "vm/allocation.h" #include "vm/bitfield.h" +#include "vm/bss_relocs.h" #include "vm/class_id.h" #include "vm/code_entry_kind.h" #include "vm/constants.h" diff --git a/runtime/vm/elf.cc b/runtime/vm/elf.cc index 96f58463445..63060295ed8 100644 --- a/runtime/vm/elf.cc +++ b/runtime/vm/elf.cc @@ -82,8 +82,6 @@ static const intptr_t kElfDynamicTableEntrySize = 16; static const intptr_t kElfSymbolHashTableEntrySize = 4; #endif -static const intptr_t kPageSize = 4096; - class Section : public ZoneAllocated { public: Section() {} @@ -115,23 +113,34 @@ class ProgramBits : public Section { public: ProgramBits(bool allocate, bool executable, + bool writable, const uint8_t* bytes, - intptr_t size) { + intptr_t filesz, + intptr_t memsz = -1) { + if (memsz == -1) memsz = filesz; + section_type = SHT_PROGBITS; if (allocate) { section_flags = SHF_ALLOC; if (executable) section_flags |= SHF_EXECINSTR; + if (writable) section_flags |= SHF_WRITE; segment_type = PT_LOAD; segment_flags = PF_R; if (executable) segment_flags |= PF_X; + if (writable) segment_flags |= PF_W; } bytes_ = bytes; - file_size = memory_size = size; + file_size = filesz; + memory_size = memsz; } - void Write(Elf* stream) { stream->WriteBytes(bytes_, memory_size); } + void Write(Elf* stream) { + if (bytes_ != nullptr) { + stream->WriteBytes(bytes_, file_size); + } + } const uint8_t* bytes_; }; @@ -371,7 +380,7 @@ static const intptr_t kNumInvalidSections = 1; // Elf::segments_. static const intptr_t kNumImplicitSegments = 3; -static const intptr_t kProgramTableSegmentSize = kPageSize; +static const intptr_t kProgramTableSegmentSize = Elf::kPageSize; Elf::Elf(Zone* zone, StreamingWriteStream* stream) : zone_(zone), stream_(stream), memory_offset_(0) { @@ -415,7 +424,7 @@ intptr_t Elf::NextMemoryOffset() { } intptr_t Elf::AddText(const char* name, const uint8_t* bytes, intptr_t size) { - ProgramBits* image = new (zone_) ProgramBits(true, true, bytes, size); + ProgramBits* image = new (zone_) ProgramBits(true, true, false, bytes, size); image->section_name = shstrtab_->AddString(".text"); AddSection(image); AddSegment(image); @@ -434,8 +443,29 @@ intptr_t Elf::AddText(const char* name, const uint8_t* bytes, intptr_t size) { return symbol->offset; } +intptr_t Elf::AddBSSData(const char* name, intptr_t size) { + ProgramBits* image = new (zone_) + ProgramBits(true, false, true, nullptr, /*filesz=*/0, /*memsz=*/size); + image->section_name = shstrtab_->AddString(".bss"); + AddSection(image); + AddSegment(image); + + Symbol* symbol = new (zone_) Symbol(); + symbol->cstr = name; + symbol->name = symstrtab_->AddString(name); + symbol->info = (STB_GLOBAL << 4) | STT_OBJECT; + symbol->section = image->section_index; + // For shared libraries, this is the offset from the DSO base. For static + // libraries, this is section relative. + symbol->offset = image->memory_offset; + symbol->size = size; + symtab_->AddSymbol(symbol); + + return symbol->offset; +} + intptr_t Elf::AddROData(const char* name, const uint8_t* bytes, intptr_t size) { - ProgramBits* image = new (zone_) ProgramBits(true, false, bytes, size); + ProgramBits* image = new (zone_) ProgramBits(true, false, false, bytes, size); image->section_name = shstrtab_->AddString(".rodata"); AddSection(image); AddSegment(image); @@ -455,7 +485,8 @@ intptr_t Elf::AddROData(const char* name, const uint8_t* bytes, intptr_t size) { } void Elf::AddDebug(const char* name, const uint8_t* bytes, intptr_t size) { - ProgramBits* image = new (zone_) ProgramBits(false, false, bytes, size); + ProgramBits* image = + new (zone_) ProgramBits(false, false, false, bytes, size); image->section_name = shstrtab_->AddString(name); AddSection(image); } diff --git a/runtime/vm/elf.h b/runtime/vm/elf.h index d6d63b717b8..882c9177b23 100644 --- a/runtime/vm/elf.h +++ b/runtime/vm/elf.h @@ -23,9 +23,12 @@ class Elf : public ZoneAllocated { public: Elf(Zone* zone, StreamingWriteStream* stream); + static const intptr_t kPageSize = 4096; + intptr_t NextMemoryOffset(); intptr_t AddText(const char* name, const uint8_t* bytes, intptr_t size); intptr_t AddROData(const char* name, const uint8_t* bytes, intptr_t size); + intptr_t AddBSSData(const char* name, intptr_t size); void AddDebug(const char* name, const uint8_t* bytes, intptr_t size); void Finalize(); diff --git a/runtime/vm/ffi_callback_trampolines.cc b/runtime/vm/ffi_callback_trampolines.cc index 5516ddbf157..af987dcc274 100644 --- a/runtime/vm/ffi_callback_trampolines.cc +++ b/runtime/vm/ffi_callback_trampolines.cc @@ -14,7 +14,22 @@ namespace dart { DECLARE_FLAG(bool, disassemble_stubs); #if !defined(DART_PRECOMPILED_RUNTIME) && !defined(TARGET_ARCH_DBC) -uword NativeCallbackTrampolines::AllocateTrampoline() { +uword NativeCallbackTrampolines::TrampolineForId(int32_t callback_id) { +#if defined(DART_PRECOMPILER) + ASSERT(!Enabled()); + UNREACHABLE(); +#else + const intptr_t trampolines_per_page = NumCallbackTrampolinesPerPage(); + const intptr_t page_index = callback_id / trampolines_per_page; + const uword entry_point = trampoline_pages_[page_index]->start(); + + return entry_point + + (callback_id % trampolines_per_page) * + compiler::StubCodeCompiler::kNativeCallbackTrampolineSize; +#endif +} + +void NativeCallbackTrampolines::AllocateTrampoline() { #if defined(DART_PRECOMPILER) ASSERT(!Enabled()); UNREACHABLE(); @@ -76,16 +91,11 @@ uword NativeCallbackTrampolines::AllocateTrampoline() { } #endif - next_callback_trampoline_ = memory->start(); trampolines_left_on_page_ = NumCallbackTrampolinesPerPage(); } trampolines_left_on_page_--; next_callback_id_++; - const uword entrypoint = next_callback_trampoline_; - next_callback_trampoline_ += - compiler::StubCodeCompiler::kNativeCallbackTrampolineSize; - return entrypoint; #endif // defined(DART_PRECOMPILER) } #endif // !defined(DART_PRECOMPILED_RUNTIME) && !defined(TARGET_ARCH_DBC) diff --git a/runtime/vm/ffi_callback_trampolines.h b/runtime/vm/ffi_callback_trampolines.h index 65c2a37ece6..77822d5a0fe 100644 --- a/runtime/vm/ffi_callback_trampolines.h +++ b/runtime/vm/ffi_callback_trampolines.h @@ -57,11 +57,13 @@ class NativeCallbackTrampolines : public ValueObject { // Allocates a callback trampoline corresponding to the callback id // 'next_callback_id()'. Returns an entrypoint to the trampoline. - uword AllocateTrampoline(); + void AllocateTrampoline(); + + // Get the entrypoint for a previously allocated callback ID. + uword TrampolineForId(int32_t callback_id); private: MallocGrowableArray trampoline_pages_; - uword next_callback_trampoline_ = 0; intptr_t trampolines_left_on_page_ = 0; intptr_t next_callback_id_ = 0; diff --git a/runtime/vm/image_snapshot.cc b/runtime/vm/image_snapshot.cc index 84c03163148..37fcf26f89d 100644 --- a/runtime/vm/image_snapshot.cc +++ b/runtime/vm/image_snapshot.cc @@ -556,6 +556,11 @@ const char* NameOfStubIsolateSpecificStub(ObjectStore* object_store, void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) { Zone* zone = Thread::Current()->zone(); +#if defined(DART_PRECOMPILER) + const char* bss_symbol = + vm ? "_kDartVmSnapshotBss" : "_kDartIsolateSnapshotBss"; +#endif + const char* instructions_symbol = vm ? "_kDartVmSnapshotInstructions" : "_kDartIsolateSnapshotInstructions"; assembly_stream_.Print(".text\n"); @@ -570,8 +575,16 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) { // look like a HeapPage. intptr_t instructions_length = next_text_offset_; WriteWordLiteralText(instructions_length); + +#if defined(DART_PRECOMPILER) + assembly_stream_.Print("%s %s - %s\n", kLiteralPrefix, bss_symbol, + instructions_symbol); +#else + WriteWordLiteralText(0); // No relocations. +#endif + intptr_t header_words = Image::kHeaderSize / sizeof(compiler::target::uword); - for (intptr_t i = 1; i < header_words; i++) { + for (intptr_t i = Image::kHeaderFields; i < header_words; i++) { WriteWordLiteralText(0); } @@ -579,6 +592,7 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) { Object& owner = Object::Handle(zone); String& str = String::Handle(zone); + PcDescriptors& descriptors = PcDescriptors::Handle(zone); ObjectStore* object_store = Isolate::Current()->object_store(); @@ -613,6 +627,7 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) { const Instructions& insns = *data.insns_; const Code& code = *data.code_; + descriptors = data.code_->pc_descriptors(); if (profile_writer_ != nullptr) { const intptr_t offset = Image::kHeaderSize + text_offset; @@ -717,7 +732,27 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) { ASSERT(Utils::IsAligned(entry, sizeof(uword))); ASSERT(Utils::IsAligned(end, sizeof(uword))); +#if defined(DART_PRECOMPILER) + PcDescriptors::Iterator iterator(descriptors, + RawPcDescriptors::kBSSRelocation); + uword next_reloc_offset = iterator.MoveNext() ? iterator.PcOffset() : -1; + + for (uword cursor = entry; cursor < end; + cursor += sizeof(compiler::target::uword)) { + compiler::target::uword data = + *reinterpret_cast(cursor); + if ((cursor - entry) == next_reloc_offset) { + assembly_stream_.Print("%s %s - (.) + %" Pd "\n", kLiteralPrefix, + bss_symbol, /*addend=*/data); + next_reloc_offset = iterator.MoveNext() ? iterator.PcOffset() : -1; + } else { + WriteWordLiteralText(data); + } + } + text_offset += end - entry; +#else text_offset += WriteByteSequence(entry, end); +#endif } ASSERT((text_offset - instr_start) == insns.raw()->HeapSize()); @@ -725,6 +760,16 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) { FrameUnwindEpilogue(); +#if defined(DART_PRECOMPILER) + assembly_stream_.Print(".bss\n"); + assembly_stream_.Print("%s:\n", bss_symbol); + + // Currently we only put one symbol in the data section, the address of + // DLRT_GetThreadForNativeCallback, which is populated when the snapshot is + // loaded. + WriteWordLiteralText(0); +#endif + #if defined(TARGET_OS_LINUX) || defined(TARGET_OS_ANDROID) || \ defined(TARGET_OS_FUCHSIA) assembly_stream_.Print(".section .rodata\n"); @@ -860,24 +905,42 @@ intptr_t BlobImageWriter::WriteByteSequence(uword start, uword end) { } void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) { + const intptr_t instructions_length = next_text_offset_; #ifdef DART_PRECOMPILER intptr_t segment_base = 0; if (elf_ != nullptr) { segment_base = elf_->NextMemoryOffset(); } + + // Calculate the start of the BSS section based on the known size of the + // text section and page alignment. + intptr_t bss_base = 0; + if (elf_ != nullptr) { + bss_base = + Utils::RoundUp(segment_base + instructions_length, Elf::kPageSize); + } #endif // This header provides the gap to make the instructions snapshot look like a // HeapPage. - intptr_t instructions_length = next_text_offset_; instructions_blob_stream_.WriteWord(instructions_length); +#if defined(DART_PRECOMPILER) + instructions_blob_stream_.WriteWord(elf_ != nullptr ? bss_base - segment_base + : 0); +#else + instructions_blob_stream_.WriteWord(0); // No relocations. +#endif intptr_t header_words = Image::kHeaderSize / sizeof(uword); - for (intptr_t i = 1; i < header_words; i++) { + for (intptr_t i = Image::kHeaderFields; i < header_words; i++) { instructions_blob_stream_.WriteWord(0); } intptr_t text_offset = 0; +#if defined(DART_PRECOMPILER) + PcDescriptors& descriptors = PcDescriptors::Handle(); +#endif + NoSafepointScope no_safepoint; for (intptr_t i = 0; i < instructions_.length(); i++) { auto& data = instructions_[i]; @@ -928,6 +991,8 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) { marked_tags |= static_cast(insns.raw_ptr()->hash_) << 32; #endif + intptr_t payload_stream_start = 0; + #if defined(IS_SIMARM_X64) const intptr_t start_offset = instructions_blob_stream_.bytes_written(); const intptr_t size_in_bytes = InstructionsSizeInSnapshot(insns.Size()); @@ -938,6 +1003,7 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) { instructions_blob_stream_.WriteFixed( insns.raw_ptr()->unchecked_entrypoint_pc_offset_); instructions_blob_stream_.Align(kSimarmX64InstructionsAlignment); + payload_stream_start = instructions_blob_stream_.Position(); instructions_blob_stream_.WriteBytes( reinterpret_cast(insns.PayloadStart()), insns.Size()); instructions_blob_stream_.Align(kSimarmX64InstructionsAlignment); @@ -945,16 +1011,61 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) { text_offset += (end_offset - start_offset); USE(end); #else // defined(IS_SIMARM_X64) + payload_stream_start = instructions_blob_stream_.Position() + + (insns.PayloadStart() - beginning); + instructions_blob_stream_.WriteWord(marked_tags); text_offset += sizeof(uword); beginning += sizeof(uword); text_offset += WriteByteSequence(beginning, end); #endif // defined(IS_SIMARM_X64) +#if defined(DART_PRECOMPILER) + // Don't patch the relocation if we're not generating ELF. The regular blobs + // format does not yet support these relocations. Use + // Code::VerifyBSSRelocations to check whether the relocations are patched + // or not after loading. + if (elf_ != nullptr) { + const intptr_t current_stream_position = + instructions_blob_stream_.Position(); + + descriptors = data.code_->pc_descriptors(); + + PcDescriptors::Iterator iterator( + descriptors, /*kind_mask=*/RawPcDescriptors::kBSSRelocation); + + while (iterator.MoveNext()) { + const intptr_t reloc_offset = iterator.PcOffset(); + + // The instruction stream at the relocation position holds an offset + // into BSS corresponding to the symbol being resolved. This addend is + // factored into the relocation. + const auto addend = *reinterpret_cast( + insns.PayloadStart() + reloc_offset); + + // Overwrite the relocation position in the instruction stream with the + // (positive) offset of the start of the payload from the start of the + // BSS segment plus the addend in the relocation. + instructions_blob_stream_.SetPosition(payload_stream_start + + reloc_offset); + + const uword offset = + bss_base - (segment_base + payload_stream_start + reloc_offset) + + addend; + instructions_blob_stream_.WriteTargetWord(offset); + } + + // Restore stream position after the relocation was patched. + instructions_blob_stream_.SetPosition(current_stream_position); + } +#endif + ASSERT((text_offset - instr_start) == ImageWriter::SizeInSnapshot(insns.raw())); } + ASSERT(instructions_blob_stream_.bytes_written() == instructions_length); + #ifdef DART_PRECOMPILER if (elf_ != nullptr) { const char* instructions_symbol = vm ? "_kDartVmSnapshotInstructions" @@ -963,6 +1074,9 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) { elf_->AddText(instructions_symbol, instructions_blob_stream_.buffer(), instructions_blob_stream_.bytes_written()); ASSERT(segment_base == segment_base2); + + const intptr_t real_bss_base = elf_->AddBSSData("_kDartVMBSSData", 8); + ASSERT(bss_base == real_bss_base); } #endif } diff --git a/runtime/vm/image_snapshot.h b/runtime/vm/image_snapshot.h index 5acb75d0504..deb94ef7942 100644 --- a/runtime/vm/image_snapshot.h +++ b/runtime/vm/image_snapshot.h @@ -48,6 +48,11 @@ class Image : ValueObject { return snapshot_size - kHeaderSize; } + uword bss_offset() const { + return *(reinterpret_cast(raw_memory_) + 1); + } + + static constexpr intptr_t kHeaderFields = 2; static const intptr_t kHeaderSize = OS::kMaxPreferredCodeAlignment; private: @@ -314,8 +319,15 @@ class AssemblyImageWriter : public ImageWriter { void FrameUnwindPrologue(); void FrameUnwindEpilogue(); intptr_t WriteByteSequence(uword start, uword end); + +#if defined(TARGET_ARCH_IS_64_BIT) + const char* kLiteralPrefix = ".quad"; +#else + const char* kLiteralPrefix = ".long"; +#endif + void WriteWordLiteralText(compiler::target::uword value) { -// Padding is helpful for comparing the .S with --disassemble. + // Padding is helpful for comparing the .S with --disassemble. #if defined(TARGET_ARCH_IS_64_BIT) assembly_stream_.Print(".quad 0x%0.16" Px "\n", value); #else diff --git a/runtime/vm/native_entry.h b/runtime/vm/native_entry.h index a4a5ee5bed1..6878c45a56e 100644 --- a/runtime/vm/native_entry.h +++ b/runtime/vm/native_entry.h @@ -35,15 +35,6 @@ class String; #define NATIVE_ENTRY_FUNCTION(name) BootstrapNatives::DN_##name -#ifdef DEBUG -#define SET_NATIVE_RETVAL(args, value) \ - RawObject* retval = value; \ - ASSERT(retval->IsDartInstance()); \ - arguments->SetReturnUnsafe(retval); -#else -#define SET_NATIVE_RETVAL(arguments, value) arguments->SetReturnUnsafe(value); -#endif - #define DEFINE_NATIVE_ENTRY(name, type_argument_count, argument_count) \ static RawObject* DN_Helper##name(Isolate* isolate, Thread* thread, \ Zone* zone, NativeArguments* arguments); \ @@ -63,9 +54,15 @@ class String; Isolate* isolate = thread->isolate(); \ TransitionGeneratedToVM transition(thread); \ StackZone zone(thread); \ - SET_NATIVE_RETVAL( \ - arguments, \ - DN_Helper##name(isolate, thread, zone.GetZone(), arguments)); \ + /* Be careful holding return_value_unsafe without a handle here. */ \ + /* A return of Object::sentinel means the return value has already */ \ + /* been set. */ \ + RawObject* return_value_unsafe = \ + DN_Helper##name(isolate, thread, zone.GetZone(), arguments); \ + if (return_value_unsafe != Object::sentinel().raw()) { \ + ASSERT(return_value_unsafe->IsDartInstance()); \ + arguments->SetReturnUnsafe(return_value_unsafe); \ + } \ DEOPTIMIZE_ALOT; \ } \ VERIFY_ON_TRANSITION; \ diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc index 4aeb20921c7..ad1e47c6ded 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc @@ -12485,8 +12485,8 @@ RawInstructions* Instructions::New(intptr_t size, result ^= raw; result.SetSize(size); result.SetHasSingleEntryPoint(has_single_entry_point); - result.set_stats(nullptr); result.set_unchecked_entrypoint_pc_offset(unchecked_entrypoint_pc_offset); + result.set_stats(nullptr); } return result.raw(); } @@ -12689,6 +12689,8 @@ const char* PcDescriptors::KindAsStr(RawPcDescriptors::Kind kind) { return "osr-entry "; case RawPcDescriptors::kRewind: return "rewind "; + case RawPcDescriptors::kBSSRelocation: + return "bss reloc "; case RawPcDescriptors::kOther: return "other "; case RawPcDescriptors::kAnyKind: @@ -15213,6 +15215,25 @@ void Code::DumpSourcePositions() const { reader.DumpSourcePositions(PayloadStart()); } +bool Code::VerifyBSSRelocations() const { + const auto& descriptors = PcDescriptors::Handle(pc_descriptors()); + const auto& insns = Instructions::Handle(instructions()); + PcDescriptors::Iterator iterator(descriptors, + RawPcDescriptors::kBSSRelocation); + while (iterator.MoveNext()) { + const uword reloc = insns.PayloadStart() + iterator.PcOffset(); + const word target = *reinterpret_cast(reloc); + // The relocation is in its original unpatched form -- the addend + // representing the target symbol itself. + if (target >= 0 && + target < + BSS::RelocationIndex(BSS::Relocation::NumRelocations) * kWordSize) { + return false; + } + } + return true; +} + void Bytecode::Disassemble(DisassemblyFormatter* formatter) const { #if !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER) #if !defined(DART_PRECOMPILED_RUNTIME) diff --git a/runtime/vm/object.h b/runtime/vm/object.h index ddb035fae3c..5b345e5d6e1 100644 --- a/runtime/vm/object.h +++ b/runtime/vm/object.h @@ -5416,6 +5416,9 @@ class Code : public Object { void Disassemble(DisassemblyFormatter* formatter = NULL) const; + // Returns true if all BSS relocations in the code have been patched. + bool VerifyBSSRelocations() const; + class Comments : public ZoneAllocated { public: static Comments& New(intptr_t count); diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h index 7ec6168e7d2..9a33d1bb719 100644 --- a/runtime/vm/raw_object.h +++ b/runtime/vm/raw_object.h @@ -1528,7 +1528,9 @@ class RawPcDescriptors : public RawObject { V(OsrEntry, kRuntimeCall << 1) \ /* Call rewind target address. */ \ V(Rewind, kOsrEntry << 1) \ - V(Other, kRewind << 1) \ + /* Target-word-size relocation. */ \ + V(BSSRelocation, kRewind << 1) \ + V(Other, kBSSRelocation << 1) \ V(AnyKind, -1) enum Kind { diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h index a6d41fd2aca..d6b7648ffa3 100644 --- a/runtime/vm/symbols.h +++ b/runtime/vm/symbols.h @@ -117,6 +117,7 @@ class ObjectPointerVisitor; V(ExternalTwoByteString, "_ExternalTwoByteString") \ V(FactoryResult, "factory result") \ V(FallThroughError, "FallThroughError") \ + V(FfiCallback, "_FfiCallback") \ V(FfiDouble, "Double") \ V(FfiDynamicLibrary, "DynamicLibrary") \ V(FfiFloat, "Float") \ diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc index 476a1cbfd91..688e88624b1 100644 --- a/runtime/vm/thread.cc +++ b/runtime/vm/thread.cc @@ -941,7 +941,7 @@ DisableThreadInterruptsScope::~DisableThreadInterruptsScope() { } const intptr_t kInitialCallbackIdsReserved = 1024; -int32_t Thread::AllocateFfiCallbackId(uword* trampoline) { +int32_t Thread::AllocateFfiCallbackId() { Zone* Z = isolate()->current_zone(); if (ffi_callback_code_ == GrowableObjectArray::null()) { ffi_callback_code_ = GrowableObjectArray::New(kInitialCallbackIdsReserved); @@ -955,7 +955,7 @@ int32_t Thread::AllocateFfiCallbackId(uword* trampoline) { if (NativeCallbackTrampolines::Enabled()) { auto* const tramps = isolate()->native_callback_trampolines(); ASSERT(tramps->next_callback_id() == id); - *trampoline = tramps->AllocateTrampoline(); + tramps->AllocateTrampoline(); } #endif @@ -964,7 +964,25 @@ int32_t Thread::AllocateFfiCallbackId(uword* trampoline) { void Thread::SetFfiCallbackCode(int32_t callback_id, const Code& code) { Zone* Z = isolate()->current_zone(); + + /// In AOT the callback ID might have been allocated during compilation but + /// 'ffi_callback_code_' is initialized to empty again when the program + /// starts. Therefore we may need to initialize or expand it to accomodate + /// the callback ID. + + if (ffi_callback_code_ == GrowableObjectArray::null()) { + ffi_callback_code_ = GrowableObjectArray::New(kInitialCallbackIdsReserved); + } + const auto& array = GrowableObjectArray::Handle(Z, ffi_callback_code_); + + if (callback_id >= array.Length()) { + if (callback_id >= array.Capacity()) { + array.Grow(callback_id + 1); + } + array.SetLength(callback_id + 1); + } + array.SetAt(callback_id, code); } diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h index 894197a1bf1..b1fa522c4f9 100644 --- a/runtime/vm/thread.h +++ b/runtime/vm/thread.h @@ -14,6 +14,7 @@ #include "platform/atomic.h" #include "platform/safe_stack.h" #include "vm/bitfield.h" +#include "vm/compiler/runtime_api.h" #include "vm/constants.h" #include "vm/globals.h" #include "vm/handles.h" @@ -23,7 +24,6 @@ #include "vm/runtime_entry_list.h" #include "vm/thread_stack_resource.h" #include "vm/thread_state.h" - namespace dart { class AbstractType; @@ -786,7 +786,11 @@ class Thread : public ThreadState { } } - int32_t AllocateFfiCallbackId(uword* trampoline); + int32_t AllocateFfiCallbackId(); + + // Store 'code' for the native callback identified by 'callback_id'. + // + // Expands the callback code array as necessary to accomodate the callback ID. void SetFfiCallbackCode(int32_t callback_id, const Code& code); // Ensure that 'callback_id' refers to a valid callback in this isolate. diff --git a/runtime/vm/vm_sources.gni b/runtime/vm/vm_sources.gni index fcc057f39ac..b692ab45763 100644 --- a/runtime/vm/vm_sources.gni +++ b/runtime/vm/vm_sources.gni @@ -19,6 +19,8 @@ vm_sources = [ "bootstrap.h", "bootstrap_natives.cc", "bootstrap_natives.h", + "bss_relocs.cc", + "bss_relocs.h", "class_finalizer.cc", "class_finalizer.h", "class_id.h", diff --git a/sdk/lib/ffi/ffi.dart b/sdk/lib/ffi/ffi.dart index 1a3c95c4849..a975a138447 100644 --- a/sdk/lib/ffi/ffi.dart +++ b/sdk/lib/ffi/ffi.dart @@ -58,7 +58,8 @@ class Pointer extends NativeType { /// Does not accept dynamic invocations -- where the type of the receiver is /// [dynamic]. external static Pointer> fromFunction( - @DartRepresentationOf("T") Function f, Object exceptionalReturn); + @DartRepresentationOf("T") Function f, + [Object exceptionalReturn]); /// Store a Dart value into this location. /// diff --git a/sdk_nnbd/lib/ffi/ffi.dart b/sdk_nnbd/lib/ffi/ffi.dart index 1a3c95c4849..a975a138447 100644 --- a/sdk_nnbd/lib/ffi/ffi.dart +++ b/sdk_nnbd/lib/ffi/ffi.dart @@ -58,7 +58,8 @@ class Pointer extends NativeType { /// Does not accept dynamic invocations -- where the type of the receiver is /// [dynamic]. external static Pointer> fromFunction( - @DartRepresentationOf("T") Function f, Object exceptionalReturn); + @DartRepresentationOf("T") Function f, + [Object exceptionalReturn]); /// Store a Dart value into this location. /// diff --git a/tests/ffi/ffi.status b/tests/ffi/ffi.status index 96e41a3aa07..46f4755abde 100644 --- a/tests/ffi/ffi.status +++ b/tests/ffi/ffi.status @@ -5,6 +5,15 @@ [ $arch == simdbc || $arch == simdbc64 ] *: Skip # SIMDBC will be deleted soon. +# Issue 37295, not yet supported in blobs snapshots at present. +[ $compiler == dartkp && $system == windows ] +function_callbacks_test: Skip +regress_37511_callbacks_test: Skip +stacktrace_regress_37910_test: Skip + +[ $compiler != dartkp || $system != windows ] +function_callbacks_unsupported_test: SkipByDesign # See above + [ $builder_tag == asan ] data_not_asan_test: SkipByDesign # This test tries to allocate too much memory on purpose. @@ -16,11 +25,6 @@ function_callbacks_test/01: Skip function_callbacks_test/02: Skip function_callbacks_test/03: Skip -[ $runtime == dart_precompiled ] -function_callbacks_test: Skip # Issue dartbug.com/37295 -regress_37511_callbacks_test: Skip # Issue dartbug.com/37295 -stacktrace_regress_37910_test: Skip # Issue dartbug.com/37295 - [ $arch == arm && $system != android ] *: Skip # "hardfp" calling convention is not yet supported (iOS is also supported but not tested): dartbug.com/36309 diff --git a/tests/ffi/function_callbacks_test.dart b/tests/ffi/function_callbacks_test.dart index 8c18fe66758..ca2197f3349 100644 --- a/tests/ffi/function_callbacks_test.dart +++ b/tests/ffi/function_callbacks_test.dart @@ -196,26 +196,26 @@ final List testcases = [ Test("ManyInts", Pointer.fromFunction(manyInts, 0)), Test("ManyDoubles", Pointer.fromFunction(manyDoubles, 0.0)), Test("ManyArgs", Pointer.fromFunction(manyArgs, 0.0)), - Test("Store", Pointer.fromFunction(store, null)), - Test("NullPointers", Pointer.fromFunction(nullPointers, null)), + Test("Store", Pointer.fromFunction(store)), + Test("NullPointers", Pointer.fromFunction(nullPointers)), Test("ReturnNull", Pointer.fromFunction(returnNull, 42)), - Test("ReturnVoid", Pointer.fromFunction(returnVoid, null)), + Test("ReturnVoid", Pointer.fromFunction(returnVoid)), Test("ThrowExceptionDouble", Pointer.fromFunction(throwExceptionDouble, 42.0)), Test( "ThrowExceptionPointer", Pointer.fromFunction( - throwExceptionPointer, Pointer.fromAddress(42))), + throwExceptionPointer)), Test("ThrowException", Pointer.fromFunction(throwExceptionInt, 42)), - Test("GC", Pointer.fromFunction(testGC, null)), - Test("UnprotectCode", Pointer.fromFunction(waitForHelper, null)), + Test("GC", Pointer.fromFunction(testGC)), + Test("UnprotectCode", Pointer.fromFunction(waitForHelper)), ]; testCallbackWrongThread() => - Test("CallbackWrongThread", Pointer.fromFunction(returnVoid, null)).run(); + Test("CallbackWrongThread", Pointer.fromFunction(returnVoid)).run(); testCallbackOutsideIsolate() => - Test("CallbackOutsideIsolate", Pointer.fromFunction(returnVoid, null)) + Test("CallbackOutsideIsolate", Pointer.fromFunction(returnVoid)) .run(); isolateHelper(int callbackPointer) { @@ -227,22 +227,25 @@ isolateHelper(int callbackPointer) { } testCallbackWrongIsolate() async { - final int callbackPointer = Pointer.fromFunction(returnVoid, null).address; + final int callbackPointer = Pointer.fromFunction(returnVoid).address; final ReceivePort exitPort = ReceivePort(); await Isolate.spawn(isolateHelper, callbackPointer, errorsAreFatal: true, onExit: exitPort.sendPort); await exitPort.first; } +const double zeroPointZero = 0.0; + // Correct type of exceptionalReturn argument to Pointer.fromFunction. double testExceptionalReturn() { Pointer.fromFunction(testExceptionalReturn, 0.0); - Expect.throwsArgumentError(() => Pointer.fromFunction(returnVoid, 0)); - Pointer.fromFunction(returnVoid, null); - Expect.throwsArgumentError(() => Pointer.fromFunction(returnVoid, null)); + Pointer.fromFunction(testExceptionalReturn, zeroPointZero); + Pointer.fromFunction(returnVoid, null); //# 59: compile-time error + Pointer.fromFunction(returnVoid, 0); //# 60: compile-time error Pointer.fromFunction(testExceptionalReturn, "abc"); //# 61: compile-time error Pointer.fromFunction(testExceptionalReturn, 0); //# 62: compile-time error + Pointer.fromFunction(testExceptionalReturn); //# 63: compile-time error } void main() async { @@ -267,9 +270,1012 @@ void testManyCallbacks() { // trampolines. The use of distinct exceptional return values forces separate // trampolines. final List pointers = []; - for (int i = 0; i < 1000; ++i) { - pointers.add(Pointer.fromFunction(simpleAddition, i)); - } + + // All the parameters of 'fromFunction' are forced to be constant so that we + // only need to generate one trampoline per 'fromFunction' call-site. + // + // As a consequence, to force the creation of 1000 trampolines (and prevent + // any possible caching), we need literally 1000 call-sites. + pointers.add(Pointer.fromFunction(simpleAddition, 0)); + pointers.add(Pointer.fromFunction(simpleAddition, 1)); + pointers.add(Pointer.fromFunction(simpleAddition, 2)); + pointers.add(Pointer.fromFunction(simpleAddition, 3)); + pointers.add(Pointer.fromFunction(simpleAddition, 4)); + pointers.add(Pointer.fromFunction(simpleAddition, 5)); + pointers.add(Pointer.fromFunction(simpleAddition, 6)); + pointers.add(Pointer.fromFunction(simpleAddition, 7)); + pointers.add(Pointer.fromFunction(simpleAddition, 8)); + pointers.add(Pointer.fromFunction(simpleAddition, 9)); + pointers.add(Pointer.fromFunction(simpleAddition, 10)); + pointers.add(Pointer.fromFunction(simpleAddition, 11)); + pointers.add(Pointer.fromFunction(simpleAddition, 12)); + pointers.add(Pointer.fromFunction(simpleAddition, 13)); + pointers.add(Pointer.fromFunction(simpleAddition, 14)); + pointers.add(Pointer.fromFunction(simpleAddition, 15)); + pointers.add(Pointer.fromFunction(simpleAddition, 16)); + pointers.add(Pointer.fromFunction(simpleAddition, 17)); + pointers.add(Pointer.fromFunction(simpleAddition, 18)); + pointers.add(Pointer.fromFunction(simpleAddition, 19)); + pointers.add(Pointer.fromFunction(simpleAddition, 20)); + pointers.add(Pointer.fromFunction(simpleAddition, 21)); + pointers.add(Pointer.fromFunction(simpleAddition, 22)); + pointers.add(Pointer.fromFunction(simpleAddition, 23)); + pointers.add(Pointer.fromFunction(simpleAddition, 24)); + pointers.add(Pointer.fromFunction(simpleAddition, 25)); + pointers.add(Pointer.fromFunction(simpleAddition, 26)); + pointers.add(Pointer.fromFunction(simpleAddition, 27)); + pointers.add(Pointer.fromFunction(simpleAddition, 28)); + pointers.add(Pointer.fromFunction(simpleAddition, 29)); + pointers.add(Pointer.fromFunction(simpleAddition, 30)); + pointers.add(Pointer.fromFunction(simpleAddition, 31)); + pointers.add(Pointer.fromFunction(simpleAddition, 32)); + pointers.add(Pointer.fromFunction(simpleAddition, 33)); + pointers.add(Pointer.fromFunction(simpleAddition, 34)); + pointers.add(Pointer.fromFunction(simpleAddition, 35)); + pointers.add(Pointer.fromFunction(simpleAddition, 36)); + pointers.add(Pointer.fromFunction(simpleAddition, 37)); + pointers.add(Pointer.fromFunction(simpleAddition, 38)); + pointers.add(Pointer.fromFunction(simpleAddition, 39)); + pointers.add(Pointer.fromFunction(simpleAddition, 40)); + pointers.add(Pointer.fromFunction(simpleAddition, 41)); + pointers.add(Pointer.fromFunction(simpleAddition, 42)); + pointers.add(Pointer.fromFunction(simpleAddition, 43)); + pointers.add(Pointer.fromFunction(simpleAddition, 44)); + pointers.add(Pointer.fromFunction(simpleAddition, 45)); + pointers.add(Pointer.fromFunction(simpleAddition, 46)); + pointers.add(Pointer.fromFunction(simpleAddition, 47)); + pointers.add(Pointer.fromFunction(simpleAddition, 48)); + pointers.add(Pointer.fromFunction(simpleAddition, 49)); + pointers.add(Pointer.fromFunction(simpleAddition, 50)); + pointers.add(Pointer.fromFunction(simpleAddition, 51)); + pointers.add(Pointer.fromFunction(simpleAddition, 52)); + pointers.add(Pointer.fromFunction(simpleAddition, 53)); + pointers.add(Pointer.fromFunction(simpleAddition, 54)); + pointers.add(Pointer.fromFunction(simpleAddition, 55)); + pointers.add(Pointer.fromFunction(simpleAddition, 56)); + pointers.add(Pointer.fromFunction(simpleAddition, 57)); + pointers.add(Pointer.fromFunction(simpleAddition, 58)); + pointers.add(Pointer.fromFunction(simpleAddition, 59)); + pointers.add(Pointer.fromFunction(simpleAddition, 60)); + pointers.add(Pointer.fromFunction(simpleAddition, 61)); + pointers.add(Pointer.fromFunction(simpleAddition, 62)); + pointers.add(Pointer.fromFunction(simpleAddition, 63)); + pointers.add(Pointer.fromFunction(simpleAddition, 64)); + pointers.add(Pointer.fromFunction(simpleAddition, 65)); + pointers.add(Pointer.fromFunction(simpleAddition, 66)); + pointers.add(Pointer.fromFunction(simpleAddition, 67)); + pointers.add(Pointer.fromFunction(simpleAddition, 68)); + pointers.add(Pointer.fromFunction(simpleAddition, 69)); + pointers.add(Pointer.fromFunction(simpleAddition, 70)); + pointers.add(Pointer.fromFunction(simpleAddition, 71)); + pointers.add(Pointer.fromFunction(simpleAddition, 72)); + pointers.add(Pointer.fromFunction(simpleAddition, 73)); + pointers.add(Pointer.fromFunction(simpleAddition, 74)); + pointers.add(Pointer.fromFunction(simpleAddition, 75)); + pointers.add(Pointer.fromFunction(simpleAddition, 76)); + pointers.add(Pointer.fromFunction(simpleAddition, 77)); + pointers.add(Pointer.fromFunction(simpleAddition, 78)); + pointers.add(Pointer.fromFunction(simpleAddition, 79)); + pointers.add(Pointer.fromFunction(simpleAddition, 80)); + pointers.add(Pointer.fromFunction(simpleAddition, 81)); + pointers.add(Pointer.fromFunction(simpleAddition, 82)); + pointers.add(Pointer.fromFunction(simpleAddition, 83)); + pointers.add(Pointer.fromFunction(simpleAddition, 84)); + pointers.add(Pointer.fromFunction(simpleAddition, 85)); + pointers.add(Pointer.fromFunction(simpleAddition, 86)); + pointers.add(Pointer.fromFunction(simpleAddition, 87)); + pointers.add(Pointer.fromFunction(simpleAddition, 88)); + pointers.add(Pointer.fromFunction(simpleAddition, 89)); + pointers.add(Pointer.fromFunction(simpleAddition, 90)); + pointers.add(Pointer.fromFunction(simpleAddition, 91)); + pointers.add(Pointer.fromFunction(simpleAddition, 92)); + pointers.add(Pointer.fromFunction(simpleAddition, 93)); + pointers.add(Pointer.fromFunction(simpleAddition, 94)); + pointers.add(Pointer.fromFunction(simpleAddition, 95)); + pointers.add(Pointer.fromFunction(simpleAddition, 96)); + pointers.add(Pointer.fromFunction(simpleAddition, 97)); + pointers.add(Pointer.fromFunction(simpleAddition, 98)); + pointers.add(Pointer.fromFunction(simpleAddition, 99)); + pointers.add(Pointer.fromFunction(simpleAddition, 100)); + pointers.add(Pointer.fromFunction(simpleAddition, 101)); + pointers.add(Pointer.fromFunction(simpleAddition, 102)); + pointers.add(Pointer.fromFunction(simpleAddition, 103)); + pointers.add(Pointer.fromFunction(simpleAddition, 104)); + pointers.add(Pointer.fromFunction(simpleAddition, 105)); + pointers.add(Pointer.fromFunction(simpleAddition, 106)); + pointers.add(Pointer.fromFunction(simpleAddition, 107)); + pointers.add(Pointer.fromFunction(simpleAddition, 108)); + pointers.add(Pointer.fromFunction(simpleAddition, 109)); + pointers.add(Pointer.fromFunction(simpleAddition, 110)); + pointers.add(Pointer.fromFunction(simpleAddition, 111)); + pointers.add(Pointer.fromFunction(simpleAddition, 112)); + pointers.add(Pointer.fromFunction(simpleAddition, 113)); + pointers.add(Pointer.fromFunction(simpleAddition, 114)); + pointers.add(Pointer.fromFunction(simpleAddition, 115)); + pointers.add(Pointer.fromFunction(simpleAddition, 116)); + pointers.add(Pointer.fromFunction(simpleAddition, 117)); + pointers.add(Pointer.fromFunction(simpleAddition, 118)); + pointers.add(Pointer.fromFunction(simpleAddition, 119)); + pointers.add(Pointer.fromFunction(simpleAddition, 120)); + pointers.add(Pointer.fromFunction(simpleAddition, 121)); + pointers.add(Pointer.fromFunction(simpleAddition, 122)); + pointers.add(Pointer.fromFunction(simpleAddition, 123)); + pointers.add(Pointer.fromFunction(simpleAddition, 124)); + pointers.add(Pointer.fromFunction(simpleAddition, 125)); + pointers.add(Pointer.fromFunction(simpleAddition, 126)); + pointers.add(Pointer.fromFunction(simpleAddition, 127)); + pointers.add(Pointer.fromFunction(simpleAddition, 128)); + pointers.add(Pointer.fromFunction(simpleAddition, 129)); + pointers.add(Pointer.fromFunction(simpleAddition, 130)); + pointers.add(Pointer.fromFunction(simpleAddition, 131)); + pointers.add(Pointer.fromFunction(simpleAddition, 132)); + pointers.add(Pointer.fromFunction(simpleAddition, 133)); + pointers.add(Pointer.fromFunction(simpleAddition, 134)); + pointers.add(Pointer.fromFunction(simpleAddition, 135)); + pointers.add(Pointer.fromFunction(simpleAddition, 136)); + pointers.add(Pointer.fromFunction(simpleAddition, 137)); + pointers.add(Pointer.fromFunction(simpleAddition, 138)); + pointers.add(Pointer.fromFunction(simpleAddition, 139)); + pointers.add(Pointer.fromFunction(simpleAddition, 140)); + pointers.add(Pointer.fromFunction(simpleAddition, 141)); + pointers.add(Pointer.fromFunction(simpleAddition, 142)); + pointers.add(Pointer.fromFunction(simpleAddition, 143)); + pointers.add(Pointer.fromFunction(simpleAddition, 144)); + pointers.add(Pointer.fromFunction(simpleAddition, 145)); + pointers.add(Pointer.fromFunction(simpleAddition, 146)); + pointers.add(Pointer.fromFunction(simpleAddition, 147)); + pointers.add(Pointer.fromFunction(simpleAddition, 148)); + pointers.add(Pointer.fromFunction(simpleAddition, 149)); + pointers.add(Pointer.fromFunction(simpleAddition, 150)); + pointers.add(Pointer.fromFunction(simpleAddition, 151)); + pointers.add(Pointer.fromFunction(simpleAddition, 152)); + pointers.add(Pointer.fromFunction(simpleAddition, 153)); + pointers.add(Pointer.fromFunction(simpleAddition, 154)); + pointers.add(Pointer.fromFunction(simpleAddition, 155)); + pointers.add(Pointer.fromFunction(simpleAddition, 156)); + pointers.add(Pointer.fromFunction(simpleAddition, 157)); + pointers.add(Pointer.fromFunction(simpleAddition, 158)); + pointers.add(Pointer.fromFunction(simpleAddition, 159)); + pointers.add(Pointer.fromFunction(simpleAddition, 160)); + pointers.add(Pointer.fromFunction(simpleAddition, 161)); + pointers.add(Pointer.fromFunction(simpleAddition, 162)); + pointers.add(Pointer.fromFunction(simpleAddition, 163)); + pointers.add(Pointer.fromFunction(simpleAddition, 164)); + pointers.add(Pointer.fromFunction(simpleAddition, 165)); + pointers.add(Pointer.fromFunction(simpleAddition, 166)); + pointers.add(Pointer.fromFunction(simpleAddition, 167)); + pointers.add(Pointer.fromFunction(simpleAddition, 168)); + pointers.add(Pointer.fromFunction(simpleAddition, 169)); + pointers.add(Pointer.fromFunction(simpleAddition, 170)); + pointers.add(Pointer.fromFunction(simpleAddition, 171)); + pointers.add(Pointer.fromFunction(simpleAddition, 172)); + pointers.add(Pointer.fromFunction(simpleAddition, 173)); + pointers.add(Pointer.fromFunction(simpleAddition, 174)); + pointers.add(Pointer.fromFunction(simpleAddition, 175)); + pointers.add(Pointer.fromFunction(simpleAddition, 176)); + pointers.add(Pointer.fromFunction(simpleAddition, 177)); + pointers.add(Pointer.fromFunction(simpleAddition, 178)); + pointers.add(Pointer.fromFunction(simpleAddition, 179)); + pointers.add(Pointer.fromFunction(simpleAddition, 180)); + pointers.add(Pointer.fromFunction(simpleAddition, 181)); + pointers.add(Pointer.fromFunction(simpleAddition, 182)); + pointers.add(Pointer.fromFunction(simpleAddition, 183)); + pointers.add(Pointer.fromFunction(simpleAddition, 184)); + pointers.add(Pointer.fromFunction(simpleAddition, 185)); + pointers.add(Pointer.fromFunction(simpleAddition, 186)); + pointers.add(Pointer.fromFunction(simpleAddition, 187)); + pointers.add(Pointer.fromFunction(simpleAddition, 188)); + pointers.add(Pointer.fromFunction(simpleAddition, 189)); + pointers.add(Pointer.fromFunction(simpleAddition, 190)); + pointers.add(Pointer.fromFunction(simpleAddition, 191)); + pointers.add(Pointer.fromFunction(simpleAddition, 192)); + pointers.add(Pointer.fromFunction(simpleAddition, 193)); + pointers.add(Pointer.fromFunction(simpleAddition, 194)); + pointers.add(Pointer.fromFunction(simpleAddition, 195)); + pointers.add(Pointer.fromFunction(simpleAddition, 196)); + pointers.add(Pointer.fromFunction(simpleAddition, 197)); + pointers.add(Pointer.fromFunction(simpleAddition, 198)); + pointers.add(Pointer.fromFunction(simpleAddition, 199)); + pointers.add(Pointer.fromFunction(simpleAddition, 200)); + pointers.add(Pointer.fromFunction(simpleAddition, 201)); + pointers.add(Pointer.fromFunction(simpleAddition, 202)); + pointers.add(Pointer.fromFunction(simpleAddition, 203)); + pointers.add(Pointer.fromFunction(simpleAddition, 204)); + pointers.add(Pointer.fromFunction(simpleAddition, 205)); + pointers.add(Pointer.fromFunction(simpleAddition, 206)); + pointers.add(Pointer.fromFunction(simpleAddition, 207)); + pointers.add(Pointer.fromFunction(simpleAddition, 208)); + pointers.add(Pointer.fromFunction(simpleAddition, 209)); + pointers.add(Pointer.fromFunction(simpleAddition, 210)); + pointers.add(Pointer.fromFunction(simpleAddition, 211)); + pointers.add(Pointer.fromFunction(simpleAddition, 212)); + pointers.add(Pointer.fromFunction(simpleAddition, 213)); + pointers.add(Pointer.fromFunction(simpleAddition, 214)); + pointers.add(Pointer.fromFunction(simpleAddition, 215)); + pointers.add(Pointer.fromFunction(simpleAddition, 216)); + pointers.add(Pointer.fromFunction(simpleAddition, 217)); + pointers.add(Pointer.fromFunction(simpleAddition, 218)); + pointers.add(Pointer.fromFunction(simpleAddition, 219)); + pointers.add(Pointer.fromFunction(simpleAddition, 220)); + pointers.add(Pointer.fromFunction(simpleAddition, 221)); + pointers.add(Pointer.fromFunction(simpleAddition, 222)); + pointers.add(Pointer.fromFunction(simpleAddition, 223)); + pointers.add(Pointer.fromFunction(simpleAddition, 224)); + pointers.add(Pointer.fromFunction(simpleAddition, 225)); + pointers.add(Pointer.fromFunction(simpleAddition, 226)); + pointers.add(Pointer.fromFunction(simpleAddition, 227)); + pointers.add(Pointer.fromFunction(simpleAddition, 228)); + pointers.add(Pointer.fromFunction(simpleAddition, 229)); + pointers.add(Pointer.fromFunction(simpleAddition, 230)); + pointers.add(Pointer.fromFunction(simpleAddition, 231)); + pointers.add(Pointer.fromFunction(simpleAddition, 232)); + pointers.add(Pointer.fromFunction(simpleAddition, 233)); + pointers.add(Pointer.fromFunction(simpleAddition, 234)); + pointers.add(Pointer.fromFunction(simpleAddition, 235)); + pointers.add(Pointer.fromFunction(simpleAddition, 236)); + pointers.add(Pointer.fromFunction(simpleAddition, 237)); + pointers.add(Pointer.fromFunction(simpleAddition, 238)); + pointers.add(Pointer.fromFunction(simpleAddition, 239)); + pointers.add(Pointer.fromFunction(simpleAddition, 240)); + pointers.add(Pointer.fromFunction(simpleAddition, 241)); + pointers.add(Pointer.fromFunction(simpleAddition, 242)); + pointers.add(Pointer.fromFunction(simpleAddition, 243)); + pointers.add(Pointer.fromFunction(simpleAddition, 244)); + pointers.add(Pointer.fromFunction(simpleAddition, 245)); + pointers.add(Pointer.fromFunction(simpleAddition, 246)); + pointers.add(Pointer.fromFunction(simpleAddition, 247)); + pointers.add(Pointer.fromFunction(simpleAddition, 248)); + pointers.add(Pointer.fromFunction(simpleAddition, 249)); + pointers.add(Pointer.fromFunction(simpleAddition, 250)); + pointers.add(Pointer.fromFunction(simpleAddition, 251)); + pointers.add(Pointer.fromFunction(simpleAddition, 252)); + pointers.add(Pointer.fromFunction(simpleAddition, 253)); + pointers.add(Pointer.fromFunction(simpleAddition, 254)); + pointers.add(Pointer.fromFunction(simpleAddition, 255)); + pointers.add(Pointer.fromFunction(simpleAddition, 256)); + pointers.add(Pointer.fromFunction(simpleAddition, 257)); + pointers.add(Pointer.fromFunction(simpleAddition, 258)); + pointers.add(Pointer.fromFunction(simpleAddition, 259)); + pointers.add(Pointer.fromFunction(simpleAddition, 260)); + pointers.add(Pointer.fromFunction(simpleAddition, 261)); + pointers.add(Pointer.fromFunction(simpleAddition, 262)); + pointers.add(Pointer.fromFunction(simpleAddition, 263)); + pointers.add(Pointer.fromFunction(simpleAddition, 264)); + pointers.add(Pointer.fromFunction(simpleAddition, 265)); + pointers.add(Pointer.fromFunction(simpleAddition, 266)); + pointers.add(Pointer.fromFunction(simpleAddition, 267)); + pointers.add(Pointer.fromFunction(simpleAddition, 268)); + pointers.add(Pointer.fromFunction(simpleAddition, 269)); + pointers.add(Pointer.fromFunction(simpleAddition, 270)); + pointers.add(Pointer.fromFunction(simpleAddition, 271)); + pointers.add(Pointer.fromFunction(simpleAddition, 272)); + pointers.add(Pointer.fromFunction(simpleAddition, 273)); + pointers.add(Pointer.fromFunction(simpleAddition, 274)); + pointers.add(Pointer.fromFunction(simpleAddition, 275)); + pointers.add(Pointer.fromFunction(simpleAddition, 276)); + pointers.add(Pointer.fromFunction(simpleAddition, 277)); + pointers.add(Pointer.fromFunction(simpleAddition, 278)); + pointers.add(Pointer.fromFunction(simpleAddition, 279)); + pointers.add(Pointer.fromFunction(simpleAddition, 280)); + pointers.add(Pointer.fromFunction(simpleAddition, 281)); + pointers.add(Pointer.fromFunction(simpleAddition, 282)); + pointers.add(Pointer.fromFunction(simpleAddition, 283)); + pointers.add(Pointer.fromFunction(simpleAddition, 284)); + pointers.add(Pointer.fromFunction(simpleAddition, 285)); + pointers.add(Pointer.fromFunction(simpleAddition, 286)); + pointers.add(Pointer.fromFunction(simpleAddition, 287)); + pointers.add(Pointer.fromFunction(simpleAddition, 288)); + pointers.add(Pointer.fromFunction(simpleAddition, 289)); + pointers.add(Pointer.fromFunction(simpleAddition, 290)); + pointers.add(Pointer.fromFunction(simpleAddition, 291)); + pointers.add(Pointer.fromFunction(simpleAddition, 292)); + pointers.add(Pointer.fromFunction(simpleAddition, 293)); + pointers.add(Pointer.fromFunction(simpleAddition, 294)); + pointers.add(Pointer.fromFunction(simpleAddition, 295)); + pointers.add(Pointer.fromFunction(simpleAddition, 296)); + pointers.add(Pointer.fromFunction(simpleAddition, 297)); + pointers.add(Pointer.fromFunction(simpleAddition, 298)); + pointers.add(Pointer.fromFunction(simpleAddition, 299)); + pointers.add(Pointer.fromFunction(simpleAddition, 300)); + pointers.add(Pointer.fromFunction(simpleAddition, 301)); + pointers.add(Pointer.fromFunction(simpleAddition, 302)); + pointers.add(Pointer.fromFunction(simpleAddition, 303)); + pointers.add(Pointer.fromFunction(simpleAddition, 304)); + pointers.add(Pointer.fromFunction(simpleAddition, 305)); + pointers.add(Pointer.fromFunction(simpleAddition, 306)); + pointers.add(Pointer.fromFunction(simpleAddition, 307)); + pointers.add(Pointer.fromFunction(simpleAddition, 308)); + pointers.add(Pointer.fromFunction(simpleAddition, 309)); + pointers.add(Pointer.fromFunction(simpleAddition, 310)); + pointers.add(Pointer.fromFunction(simpleAddition, 311)); + pointers.add(Pointer.fromFunction(simpleAddition, 312)); + pointers.add(Pointer.fromFunction(simpleAddition, 313)); + pointers.add(Pointer.fromFunction(simpleAddition, 314)); + pointers.add(Pointer.fromFunction(simpleAddition, 315)); + pointers.add(Pointer.fromFunction(simpleAddition, 316)); + pointers.add(Pointer.fromFunction(simpleAddition, 317)); + pointers.add(Pointer.fromFunction(simpleAddition, 318)); + pointers.add(Pointer.fromFunction(simpleAddition, 319)); + pointers.add(Pointer.fromFunction(simpleAddition, 320)); + pointers.add(Pointer.fromFunction(simpleAddition, 321)); + pointers.add(Pointer.fromFunction(simpleAddition, 322)); + pointers.add(Pointer.fromFunction(simpleAddition, 323)); + pointers.add(Pointer.fromFunction(simpleAddition, 324)); + pointers.add(Pointer.fromFunction(simpleAddition, 325)); + pointers.add(Pointer.fromFunction(simpleAddition, 326)); + pointers.add(Pointer.fromFunction(simpleAddition, 327)); + pointers.add(Pointer.fromFunction(simpleAddition, 328)); + pointers.add(Pointer.fromFunction(simpleAddition, 329)); + pointers.add(Pointer.fromFunction(simpleAddition, 330)); + pointers.add(Pointer.fromFunction(simpleAddition, 331)); + pointers.add(Pointer.fromFunction(simpleAddition, 332)); + pointers.add(Pointer.fromFunction(simpleAddition, 333)); + pointers.add(Pointer.fromFunction(simpleAddition, 334)); + pointers.add(Pointer.fromFunction(simpleAddition, 335)); + pointers.add(Pointer.fromFunction(simpleAddition, 336)); + pointers.add(Pointer.fromFunction(simpleAddition, 337)); + pointers.add(Pointer.fromFunction(simpleAddition, 338)); + pointers.add(Pointer.fromFunction(simpleAddition, 339)); + pointers.add(Pointer.fromFunction(simpleAddition, 340)); + pointers.add(Pointer.fromFunction(simpleAddition, 341)); + pointers.add(Pointer.fromFunction(simpleAddition, 342)); + pointers.add(Pointer.fromFunction(simpleAddition, 343)); + pointers.add(Pointer.fromFunction(simpleAddition, 344)); + pointers.add(Pointer.fromFunction(simpleAddition, 345)); + pointers.add(Pointer.fromFunction(simpleAddition, 346)); + pointers.add(Pointer.fromFunction(simpleAddition, 347)); + pointers.add(Pointer.fromFunction(simpleAddition, 348)); + pointers.add(Pointer.fromFunction(simpleAddition, 349)); + pointers.add(Pointer.fromFunction(simpleAddition, 350)); + pointers.add(Pointer.fromFunction(simpleAddition, 351)); + pointers.add(Pointer.fromFunction(simpleAddition, 352)); + pointers.add(Pointer.fromFunction(simpleAddition, 353)); + pointers.add(Pointer.fromFunction(simpleAddition, 354)); + pointers.add(Pointer.fromFunction(simpleAddition, 355)); + pointers.add(Pointer.fromFunction(simpleAddition, 356)); + pointers.add(Pointer.fromFunction(simpleAddition, 357)); + pointers.add(Pointer.fromFunction(simpleAddition, 358)); + pointers.add(Pointer.fromFunction(simpleAddition, 359)); + pointers.add(Pointer.fromFunction(simpleAddition, 360)); + pointers.add(Pointer.fromFunction(simpleAddition, 361)); + pointers.add(Pointer.fromFunction(simpleAddition, 362)); + pointers.add(Pointer.fromFunction(simpleAddition, 363)); + pointers.add(Pointer.fromFunction(simpleAddition, 364)); + pointers.add(Pointer.fromFunction(simpleAddition, 365)); + pointers.add(Pointer.fromFunction(simpleAddition, 366)); + pointers.add(Pointer.fromFunction(simpleAddition, 367)); + pointers.add(Pointer.fromFunction(simpleAddition, 368)); + pointers.add(Pointer.fromFunction(simpleAddition, 369)); + pointers.add(Pointer.fromFunction(simpleAddition, 370)); + pointers.add(Pointer.fromFunction(simpleAddition, 371)); + pointers.add(Pointer.fromFunction(simpleAddition, 372)); + pointers.add(Pointer.fromFunction(simpleAddition, 373)); + pointers.add(Pointer.fromFunction(simpleAddition, 374)); + pointers.add(Pointer.fromFunction(simpleAddition, 375)); + pointers.add(Pointer.fromFunction(simpleAddition, 376)); + pointers.add(Pointer.fromFunction(simpleAddition, 377)); + pointers.add(Pointer.fromFunction(simpleAddition, 378)); + pointers.add(Pointer.fromFunction(simpleAddition, 379)); + pointers.add(Pointer.fromFunction(simpleAddition, 380)); + pointers.add(Pointer.fromFunction(simpleAddition, 381)); + pointers.add(Pointer.fromFunction(simpleAddition, 382)); + pointers.add(Pointer.fromFunction(simpleAddition, 383)); + pointers.add(Pointer.fromFunction(simpleAddition, 384)); + pointers.add(Pointer.fromFunction(simpleAddition, 385)); + pointers.add(Pointer.fromFunction(simpleAddition, 386)); + pointers.add(Pointer.fromFunction(simpleAddition, 387)); + pointers.add(Pointer.fromFunction(simpleAddition, 388)); + pointers.add(Pointer.fromFunction(simpleAddition, 389)); + pointers.add(Pointer.fromFunction(simpleAddition, 390)); + pointers.add(Pointer.fromFunction(simpleAddition, 391)); + pointers.add(Pointer.fromFunction(simpleAddition, 392)); + pointers.add(Pointer.fromFunction(simpleAddition, 393)); + pointers.add(Pointer.fromFunction(simpleAddition, 394)); + pointers.add(Pointer.fromFunction(simpleAddition, 395)); + pointers.add(Pointer.fromFunction(simpleAddition, 396)); + pointers.add(Pointer.fromFunction(simpleAddition, 397)); + pointers.add(Pointer.fromFunction(simpleAddition, 398)); + pointers.add(Pointer.fromFunction(simpleAddition, 399)); + pointers.add(Pointer.fromFunction(simpleAddition, 400)); + pointers.add(Pointer.fromFunction(simpleAddition, 401)); + pointers.add(Pointer.fromFunction(simpleAddition, 402)); + pointers.add(Pointer.fromFunction(simpleAddition, 403)); + pointers.add(Pointer.fromFunction(simpleAddition, 404)); + pointers.add(Pointer.fromFunction(simpleAddition, 405)); + pointers.add(Pointer.fromFunction(simpleAddition, 406)); + pointers.add(Pointer.fromFunction(simpleAddition, 407)); + pointers.add(Pointer.fromFunction(simpleAddition, 408)); + pointers.add(Pointer.fromFunction(simpleAddition, 409)); + pointers.add(Pointer.fromFunction(simpleAddition, 410)); + pointers.add(Pointer.fromFunction(simpleAddition, 411)); + pointers.add(Pointer.fromFunction(simpleAddition, 412)); + pointers.add(Pointer.fromFunction(simpleAddition, 413)); + pointers.add(Pointer.fromFunction(simpleAddition, 414)); + pointers.add(Pointer.fromFunction(simpleAddition, 415)); + pointers.add(Pointer.fromFunction(simpleAddition, 416)); + pointers.add(Pointer.fromFunction(simpleAddition, 417)); + pointers.add(Pointer.fromFunction(simpleAddition, 418)); + pointers.add(Pointer.fromFunction(simpleAddition, 419)); + pointers.add(Pointer.fromFunction(simpleAddition, 420)); + pointers.add(Pointer.fromFunction(simpleAddition, 421)); + pointers.add(Pointer.fromFunction(simpleAddition, 422)); + pointers.add(Pointer.fromFunction(simpleAddition, 423)); + pointers.add(Pointer.fromFunction(simpleAddition, 424)); + pointers.add(Pointer.fromFunction(simpleAddition, 425)); + pointers.add(Pointer.fromFunction(simpleAddition, 426)); + pointers.add(Pointer.fromFunction(simpleAddition, 427)); + pointers.add(Pointer.fromFunction(simpleAddition, 428)); + pointers.add(Pointer.fromFunction(simpleAddition, 429)); + pointers.add(Pointer.fromFunction(simpleAddition, 430)); + pointers.add(Pointer.fromFunction(simpleAddition, 431)); + pointers.add(Pointer.fromFunction(simpleAddition, 432)); + pointers.add(Pointer.fromFunction(simpleAddition, 433)); + pointers.add(Pointer.fromFunction(simpleAddition, 434)); + pointers.add(Pointer.fromFunction(simpleAddition, 435)); + pointers.add(Pointer.fromFunction(simpleAddition, 436)); + pointers.add(Pointer.fromFunction(simpleAddition, 437)); + pointers.add(Pointer.fromFunction(simpleAddition, 438)); + pointers.add(Pointer.fromFunction(simpleAddition, 439)); + pointers.add(Pointer.fromFunction(simpleAddition, 440)); + pointers.add(Pointer.fromFunction(simpleAddition, 441)); + pointers.add(Pointer.fromFunction(simpleAddition, 442)); + pointers.add(Pointer.fromFunction(simpleAddition, 443)); + pointers.add(Pointer.fromFunction(simpleAddition, 444)); + pointers.add(Pointer.fromFunction(simpleAddition, 445)); + pointers.add(Pointer.fromFunction(simpleAddition, 446)); + pointers.add(Pointer.fromFunction(simpleAddition, 447)); + pointers.add(Pointer.fromFunction(simpleAddition, 448)); + pointers.add(Pointer.fromFunction(simpleAddition, 449)); + pointers.add(Pointer.fromFunction(simpleAddition, 450)); + pointers.add(Pointer.fromFunction(simpleAddition, 451)); + pointers.add(Pointer.fromFunction(simpleAddition, 452)); + pointers.add(Pointer.fromFunction(simpleAddition, 453)); + pointers.add(Pointer.fromFunction(simpleAddition, 454)); + pointers.add(Pointer.fromFunction(simpleAddition, 455)); + pointers.add(Pointer.fromFunction(simpleAddition, 456)); + pointers.add(Pointer.fromFunction(simpleAddition, 457)); + pointers.add(Pointer.fromFunction(simpleAddition, 458)); + pointers.add(Pointer.fromFunction(simpleAddition, 459)); + pointers.add(Pointer.fromFunction(simpleAddition, 460)); + pointers.add(Pointer.fromFunction(simpleAddition, 461)); + pointers.add(Pointer.fromFunction(simpleAddition, 462)); + pointers.add(Pointer.fromFunction(simpleAddition, 463)); + pointers.add(Pointer.fromFunction(simpleAddition, 464)); + pointers.add(Pointer.fromFunction(simpleAddition, 465)); + pointers.add(Pointer.fromFunction(simpleAddition, 466)); + pointers.add(Pointer.fromFunction(simpleAddition, 467)); + pointers.add(Pointer.fromFunction(simpleAddition, 468)); + pointers.add(Pointer.fromFunction(simpleAddition, 469)); + pointers.add(Pointer.fromFunction(simpleAddition, 470)); + pointers.add(Pointer.fromFunction(simpleAddition, 471)); + pointers.add(Pointer.fromFunction(simpleAddition, 472)); + pointers.add(Pointer.fromFunction(simpleAddition, 473)); + pointers.add(Pointer.fromFunction(simpleAddition, 474)); + pointers.add(Pointer.fromFunction(simpleAddition, 475)); + pointers.add(Pointer.fromFunction(simpleAddition, 476)); + pointers.add(Pointer.fromFunction(simpleAddition, 477)); + pointers.add(Pointer.fromFunction(simpleAddition, 478)); + pointers.add(Pointer.fromFunction(simpleAddition, 479)); + pointers.add(Pointer.fromFunction(simpleAddition, 480)); + pointers.add(Pointer.fromFunction(simpleAddition, 481)); + pointers.add(Pointer.fromFunction(simpleAddition, 482)); + pointers.add(Pointer.fromFunction(simpleAddition, 483)); + pointers.add(Pointer.fromFunction(simpleAddition, 484)); + pointers.add(Pointer.fromFunction(simpleAddition, 485)); + pointers.add(Pointer.fromFunction(simpleAddition, 486)); + pointers.add(Pointer.fromFunction(simpleAddition, 487)); + pointers.add(Pointer.fromFunction(simpleAddition, 488)); + pointers.add(Pointer.fromFunction(simpleAddition, 489)); + pointers.add(Pointer.fromFunction(simpleAddition, 490)); + pointers.add(Pointer.fromFunction(simpleAddition, 491)); + pointers.add(Pointer.fromFunction(simpleAddition, 492)); + pointers.add(Pointer.fromFunction(simpleAddition, 493)); + pointers.add(Pointer.fromFunction(simpleAddition, 494)); + pointers.add(Pointer.fromFunction(simpleAddition, 495)); + pointers.add(Pointer.fromFunction(simpleAddition, 496)); + pointers.add(Pointer.fromFunction(simpleAddition, 497)); + pointers.add(Pointer.fromFunction(simpleAddition, 498)); + pointers.add(Pointer.fromFunction(simpleAddition, 499)); + pointers.add(Pointer.fromFunction(simpleAddition, 500)); + pointers.add(Pointer.fromFunction(simpleAddition, 501)); + pointers.add(Pointer.fromFunction(simpleAddition, 502)); + pointers.add(Pointer.fromFunction(simpleAddition, 503)); + pointers.add(Pointer.fromFunction(simpleAddition, 504)); + pointers.add(Pointer.fromFunction(simpleAddition, 505)); + pointers.add(Pointer.fromFunction(simpleAddition, 506)); + pointers.add(Pointer.fromFunction(simpleAddition, 507)); + pointers.add(Pointer.fromFunction(simpleAddition, 508)); + pointers.add(Pointer.fromFunction(simpleAddition, 509)); + pointers.add(Pointer.fromFunction(simpleAddition, 510)); + pointers.add(Pointer.fromFunction(simpleAddition, 511)); + pointers.add(Pointer.fromFunction(simpleAddition, 512)); + pointers.add(Pointer.fromFunction(simpleAddition, 513)); + pointers.add(Pointer.fromFunction(simpleAddition, 514)); + pointers.add(Pointer.fromFunction(simpleAddition, 515)); + pointers.add(Pointer.fromFunction(simpleAddition, 516)); + pointers.add(Pointer.fromFunction(simpleAddition, 517)); + pointers.add(Pointer.fromFunction(simpleAddition, 518)); + pointers.add(Pointer.fromFunction(simpleAddition, 519)); + pointers.add(Pointer.fromFunction(simpleAddition, 520)); + pointers.add(Pointer.fromFunction(simpleAddition, 521)); + pointers.add(Pointer.fromFunction(simpleAddition, 522)); + pointers.add(Pointer.fromFunction(simpleAddition, 523)); + pointers.add(Pointer.fromFunction(simpleAddition, 524)); + pointers.add(Pointer.fromFunction(simpleAddition, 525)); + pointers.add(Pointer.fromFunction(simpleAddition, 526)); + pointers.add(Pointer.fromFunction(simpleAddition, 527)); + pointers.add(Pointer.fromFunction(simpleAddition, 528)); + pointers.add(Pointer.fromFunction(simpleAddition, 529)); + pointers.add(Pointer.fromFunction(simpleAddition, 530)); + pointers.add(Pointer.fromFunction(simpleAddition, 531)); + pointers.add(Pointer.fromFunction(simpleAddition, 532)); + pointers.add(Pointer.fromFunction(simpleAddition, 533)); + pointers.add(Pointer.fromFunction(simpleAddition, 534)); + pointers.add(Pointer.fromFunction(simpleAddition, 535)); + pointers.add(Pointer.fromFunction(simpleAddition, 536)); + pointers.add(Pointer.fromFunction(simpleAddition, 537)); + pointers.add(Pointer.fromFunction(simpleAddition, 538)); + pointers.add(Pointer.fromFunction(simpleAddition, 539)); + pointers.add(Pointer.fromFunction(simpleAddition, 540)); + pointers.add(Pointer.fromFunction(simpleAddition, 541)); + pointers.add(Pointer.fromFunction(simpleAddition, 542)); + pointers.add(Pointer.fromFunction(simpleAddition, 543)); + pointers.add(Pointer.fromFunction(simpleAddition, 544)); + pointers.add(Pointer.fromFunction(simpleAddition, 545)); + pointers.add(Pointer.fromFunction(simpleAddition, 546)); + pointers.add(Pointer.fromFunction(simpleAddition, 547)); + pointers.add(Pointer.fromFunction(simpleAddition, 548)); + pointers.add(Pointer.fromFunction(simpleAddition, 549)); + pointers.add(Pointer.fromFunction(simpleAddition, 550)); + pointers.add(Pointer.fromFunction(simpleAddition, 551)); + pointers.add(Pointer.fromFunction(simpleAddition, 552)); + pointers.add(Pointer.fromFunction(simpleAddition, 553)); + pointers.add(Pointer.fromFunction(simpleAddition, 554)); + pointers.add(Pointer.fromFunction(simpleAddition, 555)); + pointers.add(Pointer.fromFunction(simpleAddition, 556)); + pointers.add(Pointer.fromFunction(simpleAddition, 557)); + pointers.add(Pointer.fromFunction(simpleAddition, 558)); + pointers.add(Pointer.fromFunction(simpleAddition, 559)); + pointers.add(Pointer.fromFunction(simpleAddition, 560)); + pointers.add(Pointer.fromFunction(simpleAddition, 561)); + pointers.add(Pointer.fromFunction(simpleAddition, 562)); + pointers.add(Pointer.fromFunction(simpleAddition, 563)); + pointers.add(Pointer.fromFunction(simpleAddition, 564)); + pointers.add(Pointer.fromFunction(simpleAddition, 565)); + pointers.add(Pointer.fromFunction(simpleAddition, 566)); + pointers.add(Pointer.fromFunction(simpleAddition, 567)); + pointers.add(Pointer.fromFunction(simpleAddition, 568)); + pointers.add(Pointer.fromFunction(simpleAddition, 569)); + pointers.add(Pointer.fromFunction(simpleAddition, 570)); + pointers.add(Pointer.fromFunction(simpleAddition, 571)); + pointers.add(Pointer.fromFunction(simpleAddition, 572)); + pointers.add(Pointer.fromFunction(simpleAddition, 573)); + pointers.add(Pointer.fromFunction(simpleAddition, 574)); + pointers.add(Pointer.fromFunction(simpleAddition, 575)); + pointers.add(Pointer.fromFunction(simpleAddition, 576)); + pointers.add(Pointer.fromFunction(simpleAddition, 577)); + pointers.add(Pointer.fromFunction(simpleAddition, 578)); + pointers.add(Pointer.fromFunction(simpleAddition, 579)); + pointers.add(Pointer.fromFunction(simpleAddition, 580)); + pointers.add(Pointer.fromFunction(simpleAddition, 581)); + pointers.add(Pointer.fromFunction(simpleAddition, 582)); + pointers.add(Pointer.fromFunction(simpleAddition, 583)); + pointers.add(Pointer.fromFunction(simpleAddition, 584)); + pointers.add(Pointer.fromFunction(simpleAddition, 585)); + pointers.add(Pointer.fromFunction(simpleAddition, 586)); + pointers.add(Pointer.fromFunction(simpleAddition, 587)); + pointers.add(Pointer.fromFunction(simpleAddition, 588)); + pointers.add(Pointer.fromFunction(simpleAddition, 589)); + pointers.add(Pointer.fromFunction(simpleAddition, 590)); + pointers.add(Pointer.fromFunction(simpleAddition, 591)); + pointers.add(Pointer.fromFunction(simpleAddition, 592)); + pointers.add(Pointer.fromFunction(simpleAddition, 593)); + pointers.add(Pointer.fromFunction(simpleAddition, 594)); + pointers.add(Pointer.fromFunction(simpleAddition, 595)); + pointers.add(Pointer.fromFunction(simpleAddition, 596)); + pointers.add(Pointer.fromFunction(simpleAddition, 597)); + pointers.add(Pointer.fromFunction(simpleAddition, 598)); + pointers.add(Pointer.fromFunction(simpleAddition, 599)); + pointers.add(Pointer.fromFunction(simpleAddition, 600)); + pointers.add(Pointer.fromFunction(simpleAddition, 601)); + pointers.add(Pointer.fromFunction(simpleAddition, 602)); + pointers.add(Pointer.fromFunction(simpleAddition, 603)); + pointers.add(Pointer.fromFunction(simpleAddition, 604)); + pointers.add(Pointer.fromFunction(simpleAddition, 605)); + pointers.add(Pointer.fromFunction(simpleAddition, 606)); + pointers.add(Pointer.fromFunction(simpleAddition, 607)); + pointers.add(Pointer.fromFunction(simpleAddition, 608)); + pointers.add(Pointer.fromFunction(simpleAddition, 609)); + pointers.add(Pointer.fromFunction(simpleAddition, 610)); + pointers.add(Pointer.fromFunction(simpleAddition, 611)); + pointers.add(Pointer.fromFunction(simpleAddition, 612)); + pointers.add(Pointer.fromFunction(simpleAddition, 613)); + pointers.add(Pointer.fromFunction(simpleAddition, 614)); + pointers.add(Pointer.fromFunction(simpleAddition, 615)); + pointers.add(Pointer.fromFunction(simpleAddition, 616)); + pointers.add(Pointer.fromFunction(simpleAddition, 617)); + pointers.add(Pointer.fromFunction(simpleAddition, 618)); + pointers.add(Pointer.fromFunction(simpleAddition, 619)); + pointers.add(Pointer.fromFunction(simpleAddition, 620)); + pointers.add(Pointer.fromFunction(simpleAddition, 621)); + pointers.add(Pointer.fromFunction(simpleAddition, 622)); + pointers.add(Pointer.fromFunction(simpleAddition, 623)); + pointers.add(Pointer.fromFunction(simpleAddition, 624)); + pointers.add(Pointer.fromFunction(simpleAddition, 625)); + pointers.add(Pointer.fromFunction(simpleAddition, 626)); + pointers.add(Pointer.fromFunction(simpleAddition, 627)); + pointers.add(Pointer.fromFunction(simpleAddition, 628)); + pointers.add(Pointer.fromFunction(simpleAddition, 629)); + pointers.add(Pointer.fromFunction(simpleAddition, 630)); + pointers.add(Pointer.fromFunction(simpleAddition, 631)); + pointers.add(Pointer.fromFunction(simpleAddition, 632)); + pointers.add(Pointer.fromFunction(simpleAddition, 633)); + pointers.add(Pointer.fromFunction(simpleAddition, 634)); + pointers.add(Pointer.fromFunction(simpleAddition, 635)); + pointers.add(Pointer.fromFunction(simpleAddition, 636)); + pointers.add(Pointer.fromFunction(simpleAddition, 637)); + pointers.add(Pointer.fromFunction(simpleAddition, 638)); + pointers.add(Pointer.fromFunction(simpleAddition, 639)); + pointers.add(Pointer.fromFunction(simpleAddition, 640)); + pointers.add(Pointer.fromFunction(simpleAddition, 641)); + pointers.add(Pointer.fromFunction(simpleAddition, 642)); + pointers.add(Pointer.fromFunction(simpleAddition, 643)); + pointers.add(Pointer.fromFunction(simpleAddition, 644)); + pointers.add(Pointer.fromFunction(simpleAddition, 645)); + pointers.add(Pointer.fromFunction(simpleAddition, 646)); + pointers.add(Pointer.fromFunction(simpleAddition, 647)); + pointers.add(Pointer.fromFunction(simpleAddition, 648)); + pointers.add(Pointer.fromFunction(simpleAddition, 649)); + pointers.add(Pointer.fromFunction(simpleAddition, 650)); + pointers.add(Pointer.fromFunction(simpleAddition, 651)); + pointers.add(Pointer.fromFunction(simpleAddition, 652)); + pointers.add(Pointer.fromFunction(simpleAddition, 653)); + pointers.add(Pointer.fromFunction(simpleAddition, 654)); + pointers.add(Pointer.fromFunction(simpleAddition, 655)); + pointers.add(Pointer.fromFunction(simpleAddition, 656)); + pointers.add(Pointer.fromFunction(simpleAddition, 657)); + pointers.add(Pointer.fromFunction(simpleAddition, 658)); + pointers.add(Pointer.fromFunction(simpleAddition, 659)); + pointers.add(Pointer.fromFunction(simpleAddition, 660)); + pointers.add(Pointer.fromFunction(simpleAddition, 661)); + pointers.add(Pointer.fromFunction(simpleAddition, 662)); + pointers.add(Pointer.fromFunction(simpleAddition, 663)); + pointers.add(Pointer.fromFunction(simpleAddition, 664)); + pointers.add(Pointer.fromFunction(simpleAddition, 665)); + pointers.add(Pointer.fromFunction(simpleAddition, 666)); + pointers.add(Pointer.fromFunction(simpleAddition, 667)); + pointers.add(Pointer.fromFunction(simpleAddition, 668)); + pointers.add(Pointer.fromFunction(simpleAddition, 669)); + pointers.add(Pointer.fromFunction(simpleAddition, 670)); + pointers.add(Pointer.fromFunction(simpleAddition, 671)); + pointers.add(Pointer.fromFunction(simpleAddition, 672)); + pointers.add(Pointer.fromFunction(simpleAddition, 673)); + pointers.add(Pointer.fromFunction(simpleAddition, 674)); + pointers.add(Pointer.fromFunction(simpleAddition, 675)); + pointers.add(Pointer.fromFunction(simpleAddition, 676)); + pointers.add(Pointer.fromFunction(simpleAddition, 677)); + pointers.add(Pointer.fromFunction(simpleAddition, 678)); + pointers.add(Pointer.fromFunction(simpleAddition, 679)); + pointers.add(Pointer.fromFunction(simpleAddition, 680)); + pointers.add(Pointer.fromFunction(simpleAddition, 681)); + pointers.add(Pointer.fromFunction(simpleAddition, 682)); + pointers.add(Pointer.fromFunction(simpleAddition, 683)); + pointers.add(Pointer.fromFunction(simpleAddition, 684)); + pointers.add(Pointer.fromFunction(simpleAddition, 685)); + pointers.add(Pointer.fromFunction(simpleAddition, 686)); + pointers.add(Pointer.fromFunction(simpleAddition, 687)); + pointers.add(Pointer.fromFunction(simpleAddition, 688)); + pointers.add(Pointer.fromFunction(simpleAddition, 689)); + pointers.add(Pointer.fromFunction(simpleAddition, 690)); + pointers.add(Pointer.fromFunction(simpleAddition, 691)); + pointers.add(Pointer.fromFunction(simpleAddition, 692)); + pointers.add(Pointer.fromFunction(simpleAddition, 693)); + pointers.add(Pointer.fromFunction(simpleAddition, 694)); + pointers.add(Pointer.fromFunction(simpleAddition, 695)); + pointers.add(Pointer.fromFunction(simpleAddition, 696)); + pointers.add(Pointer.fromFunction(simpleAddition, 697)); + pointers.add(Pointer.fromFunction(simpleAddition, 698)); + pointers.add(Pointer.fromFunction(simpleAddition, 699)); + pointers.add(Pointer.fromFunction(simpleAddition, 700)); + pointers.add(Pointer.fromFunction(simpleAddition, 701)); + pointers.add(Pointer.fromFunction(simpleAddition, 702)); + pointers.add(Pointer.fromFunction(simpleAddition, 703)); + pointers.add(Pointer.fromFunction(simpleAddition, 704)); + pointers.add(Pointer.fromFunction(simpleAddition, 705)); + pointers.add(Pointer.fromFunction(simpleAddition, 706)); + pointers.add(Pointer.fromFunction(simpleAddition, 707)); + pointers.add(Pointer.fromFunction(simpleAddition, 708)); + pointers.add(Pointer.fromFunction(simpleAddition, 709)); + pointers.add(Pointer.fromFunction(simpleAddition, 710)); + pointers.add(Pointer.fromFunction(simpleAddition, 711)); + pointers.add(Pointer.fromFunction(simpleAddition, 712)); + pointers.add(Pointer.fromFunction(simpleAddition, 713)); + pointers.add(Pointer.fromFunction(simpleAddition, 714)); + pointers.add(Pointer.fromFunction(simpleAddition, 715)); + pointers.add(Pointer.fromFunction(simpleAddition, 716)); + pointers.add(Pointer.fromFunction(simpleAddition, 717)); + pointers.add(Pointer.fromFunction(simpleAddition, 718)); + pointers.add(Pointer.fromFunction(simpleAddition, 719)); + pointers.add(Pointer.fromFunction(simpleAddition, 720)); + pointers.add(Pointer.fromFunction(simpleAddition, 721)); + pointers.add(Pointer.fromFunction(simpleAddition, 722)); + pointers.add(Pointer.fromFunction(simpleAddition, 723)); + pointers.add(Pointer.fromFunction(simpleAddition, 724)); + pointers.add(Pointer.fromFunction(simpleAddition, 725)); + pointers.add(Pointer.fromFunction(simpleAddition, 726)); + pointers.add(Pointer.fromFunction(simpleAddition, 727)); + pointers.add(Pointer.fromFunction(simpleAddition, 728)); + pointers.add(Pointer.fromFunction(simpleAddition, 729)); + pointers.add(Pointer.fromFunction(simpleAddition, 730)); + pointers.add(Pointer.fromFunction(simpleAddition, 731)); + pointers.add(Pointer.fromFunction(simpleAddition, 732)); + pointers.add(Pointer.fromFunction(simpleAddition, 733)); + pointers.add(Pointer.fromFunction(simpleAddition, 734)); + pointers.add(Pointer.fromFunction(simpleAddition, 735)); + pointers.add(Pointer.fromFunction(simpleAddition, 736)); + pointers.add(Pointer.fromFunction(simpleAddition, 737)); + pointers.add(Pointer.fromFunction(simpleAddition, 738)); + pointers.add(Pointer.fromFunction(simpleAddition, 739)); + pointers.add(Pointer.fromFunction(simpleAddition, 740)); + pointers.add(Pointer.fromFunction(simpleAddition, 741)); + pointers.add(Pointer.fromFunction(simpleAddition, 742)); + pointers.add(Pointer.fromFunction(simpleAddition, 743)); + pointers.add(Pointer.fromFunction(simpleAddition, 744)); + pointers.add(Pointer.fromFunction(simpleAddition, 745)); + pointers.add(Pointer.fromFunction(simpleAddition, 746)); + pointers.add(Pointer.fromFunction(simpleAddition, 747)); + pointers.add(Pointer.fromFunction(simpleAddition, 748)); + pointers.add(Pointer.fromFunction(simpleAddition, 749)); + pointers.add(Pointer.fromFunction(simpleAddition, 750)); + pointers.add(Pointer.fromFunction(simpleAddition, 751)); + pointers.add(Pointer.fromFunction(simpleAddition, 752)); + pointers.add(Pointer.fromFunction(simpleAddition, 753)); + pointers.add(Pointer.fromFunction(simpleAddition, 754)); + pointers.add(Pointer.fromFunction(simpleAddition, 755)); + pointers.add(Pointer.fromFunction(simpleAddition, 756)); + pointers.add(Pointer.fromFunction(simpleAddition, 757)); + pointers.add(Pointer.fromFunction(simpleAddition, 758)); + pointers.add(Pointer.fromFunction(simpleAddition, 759)); + pointers.add(Pointer.fromFunction(simpleAddition, 760)); + pointers.add(Pointer.fromFunction(simpleAddition, 761)); + pointers.add(Pointer.fromFunction(simpleAddition, 762)); + pointers.add(Pointer.fromFunction(simpleAddition, 763)); + pointers.add(Pointer.fromFunction(simpleAddition, 764)); + pointers.add(Pointer.fromFunction(simpleAddition, 765)); + pointers.add(Pointer.fromFunction(simpleAddition, 766)); + pointers.add(Pointer.fromFunction(simpleAddition, 767)); + pointers.add(Pointer.fromFunction(simpleAddition, 768)); + pointers.add(Pointer.fromFunction(simpleAddition, 769)); + pointers.add(Pointer.fromFunction(simpleAddition, 770)); + pointers.add(Pointer.fromFunction(simpleAddition, 771)); + pointers.add(Pointer.fromFunction(simpleAddition, 772)); + pointers.add(Pointer.fromFunction(simpleAddition, 773)); + pointers.add(Pointer.fromFunction(simpleAddition, 774)); + pointers.add(Pointer.fromFunction(simpleAddition, 775)); + pointers.add(Pointer.fromFunction(simpleAddition, 776)); + pointers.add(Pointer.fromFunction(simpleAddition, 777)); + pointers.add(Pointer.fromFunction(simpleAddition, 778)); + pointers.add(Pointer.fromFunction(simpleAddition, 779)); + pointers.add(Pointer.fromFunction(simpleAddition, 780)); + pointers.add(Pointer.fromFunction(simpleAddition, 781)); + pointers.add(Pointer.fromFunction(simpleAddition, 782)); + pointers.add(Pointer.fromFunction(simpleAddition, 783)); + pointers.add(Pointer.fromFunction(simpleAddition, 784)); + pointers.add(Pointer.fromFunction(simpleAddition, 785)); + pointers.add(Pointer.fromFunction(simpleAddition, 786)); + pointers.add(Pointer.fromFunction(simpleAddition, 787)); + pointers.add(Pointer.fromFunction(simpleAddition, 788)); + pointers.add(Pointer.fromFunction(simpleAddition, 789)); + pointers.add(Pointer.fromFunction(simpleAddition, 790)); + pointers.add(Pointer.fromFunction(simpleAddition, 791)); + pointers.add(Pointer.fromFunction(simpleAddition, 792)); + pointers.add(Pointer.fromFunction(simpleAddition, 793)); + pointers.add(Pointer.fromFunction(simpleAddition, 794)); + pointers.add(Pointer.fromFunction(simpleAddition, 795)); + pointers.add(Pointer.fromFunction(simpleAddition, 796)); + pointers.add(Pointer.fromFunction(simpleAddition, 797)); + pointers.add(Pointer.fromFunction(simpleAddition, 798)); + pointers.add(Pointer.fromFunction(simpleAddition, 799)); + pointers.add(Pointer.fromFunction(simpleAddition, 800)); + pointers.add(Pointer.fromFunction(simpleAddition, 801)); + pointers.add(Pointer.fromFunction(simpleAddition, 802)); + pointers.add(Pointer.fromFunction(simpleAddition, 803)); + pointers.add(Pointer.fromFunction(simpleAddition, 804)); + pointers.add(Pointer.fromFunction(simpleAddition, 805)); + pointers.add(Pointer.fromFunction(simpleAddition, 806)); + pointers.add(Pointer.fromFunction(simpleAddition, 807)); + pointers.add(Pointer.fromFunction(simpleAddition, 808)); + pointers.add(Pointer.fromFunction(simpleAddition, 809)); + pointers.add(Pointer.fromFunction(simpleAddition, 810)); + pointers.add(Pointer.fromFunction(simpleAddition, 811)); + pointers.add(Pointer.fromFunction(simpleAddition, 812)); + pointers.add(Pointer.fromFunction(simpleAddition, 813)); + pointers.add(Pointer.fromFunction(simpleAddition, 814)); + pointers.add(Pointer.fromFunction(simpleAddition, 815)); + pointers.add(Pointer.fromFunction(simpleAddition, 816)); + pointers.add(Pointer.fromFunction(simpleAddition, 817)); + pointers.add(Pointer.fromFunction(simpleAddition, 818)); + pointers.add(Pointer.fromFunction(simpleAddition, 819)); + pointers.add(Pointer.fromFunction(simpleAddition, 820)); + pointers.add(Pointer.fromFunction(simpleAddition, 821)); + pointers.add(Pointer.fromFunction(simpleAddition, 822)); + pointers.add(Pointer.fromFunction(simpleAddition, 823)); + pointers.add(Pointer.fromFunction(simpleAddition, 824)); + pointers.add(Pointer.fromFunction(simpleAddition, 825)); + pointers.add(Pointer.fromFunction(simpleAddition, 826)); + pointers.add(Pointer.fromFunction(simpleAddition, 827)); + pointers.add(Pointer.fromFunction(simpleAddition, 828)); + pointers.add(Pointer.fromFunction(simpleAddition, 829)); + pointers.add(Pointer.fromFunction(simpleAddition, 830)); + pointers.add(Pointer.fromFunction(simpleAddition, 831)); + pointers.add(Pointer.fromFunction(simpleAddition, 832)); + pointers.add(Pointer.fromFunction(simpleAddition, 833)); + pointers.add(Pointer.fromFunction(simpleAddition, 834)); + pointers.add(Pointer.fromFunction(simpleAddition, 835)); + pointers.add(Pointer.fromFunction(simpleAddition, 836)); + pointers.add(Pointer.fromFunction(simpleAddition, 837)); + pointers.add(Pointer.fromFunction(simpleAddition, 838)); + pointers.add(Pointer.fromFunction(simpleAddition, 839)); + pointers.add(Pointer.fromFunction(simpleAddition, 840)); + pointers.add(Pointer.fromFunction(simpleAddition, 841)); + pointers.add(Pointer.fromFunction(simpleAddition, 842)); + pointers.add(Pointer.fromFunction(simpleAddition, 843)); + pointers.add(Pointer.fromFunction(simpleAddition, 844)); + pointers.add(Pointer.fromFunction(simpleAddition, 845)); + pointers.add(Pointer.fromFunction(simpleAddition, 846)); + pointers.add(Pointer.fromFunction(simpleAddition, 847)); + pointers.add(Pointer.fromFunction(simpleAddition, 848)); + pointers.add(Pointer.fromFunction(simpleAddition, 849)); + pointers.add(Pointer.fromFunction(simpleAddition, 850)); + pointers.add(Pointer.fromFunction(simpleAddition, 851)); + pointers.add(Pointer.fromFunction(simpleAddition, 852)); + pointers.add(Pointer.fromFunction(simpleAddition, 853)); + pointers.add(Pointer.fromFunction(simpleAddition, 854)); + pointers.add(Pointer.fromFunction(simpleAddition, 855)); + pointers.add(Pointer.fromFunction(simpleAddition, 856)); + pointers.add(Pointer.fromFunction(simpleAddition, 857)); + pointers.add(Pointer.fromFunction(simpleAddition, 858)); + pointers.add(Pointer.fromFunction(simpleAddition, 859)); + pointers.add(Pointer.fromFunction(simpleAddition, 860)); + pointers.add(Pointer.fromFunction(simpleAddition, 861)); + pointers.add(Pointer.fromFunction(simpleAddition, 862)); + pointers.add(Pointer.fromFunction(simpleAddition, 863)); + pointers.add(Pointer.fromFunction(simpleAddition, 864)); + pointers.add(Pointer.fromFunction(simpleAddition, 865)); + pointers.add(Pointer.fromFunction(simpleAddition, 866)); + pointers.add(Pointer.fromFunction(simpleAddition, 867)); + pointers.add(Pointer.fromFunction(simpleAddition, 868)); + pointers.add(Pointer.fromFunction(simpleAddition, 869)); + pointers.add(Pointer.fromFunction(simpleAddition, 870)); + pointers.add(Pointer.fromFunction(simpleAddition, 871)); + pointers.add(Pointer.fromFunction(simpleAddition, 872)); + pointers.add(Pointer.fromFunction(simpleAddition, 873)); + pointers.add(Pointer.fromFunction(simpleAddition, 874)); + pointers.add(Pointer.fromFunction(simpleAddition, 875)); + pointers.add(Pointer.fromFunction(simpleAddition, 876)); + pointers.add(Pointer.fromFunction(simpleAddition, 877)); + pointers.add(Pointer.fromFunction(simpleAddition, 878)); + pointers.add(Pointer.fromFunction(simpleAddition, 879)); + pointers.add(Pointer.fromFunction(simpleAddition, 880)); + pointers.add(Pointer.fromFunction(simpleAddition, 881)); + pointers.add(Pointer.fromFunction(simpleAddition, 882)); + pointers.add(Pointer.fromFunction(simpleAddition, 883)); + pointers.add(Pointer.fromFunction(simpleAddition, 884)); + pointers.add(Pointer.fromFunction(simpleAddition, 885)); + pointers.add(Pointer.fromFunction(simpleAddition, 886)); + pointers.add(Pointer.fromFunction(simpleAddition, 887)); + pointers.add(Pointer.fromFunction(simpleAddition, 888)); + pointers.add(Pointer.fromFunction(simpleAddition, 889)); + pointers.add(Pointer.fromFunction(simpleAddition, 890)); + pointers.add(Pointer.fromFunction(simpleAddition, 891)); + pointers.add(Pointer.fromFunction(simpleAddition, 892)); + pointers.add(Pointer.fromFunction(simpleAddition, 893)); + pointers.add(Pointer.fromFunction(simpleAddition, 894)); + pointers.add(Pointer.fromFunction(simpleAddition, 895)); + pointers.add(Pointer.fromFunction(simpleAddition, 896)); + pointers.add(Pointer.fromFunction(simpleAddition, 897)); + pointers.add(Pointer.fromFunction(simpleAddition, 898)); + pointers.add(Pointer.fromFunction(simpleAddition, 899)); + pointers.add(Pointer.fromFunction(simpleAddition, 900)); + pointers.add(Pointer.fromFunction(simpleAddition, 901)); + pointers.add(Pointer.fromFunction(simpleAddition, 902)); + pointers.add(Pointer.fromFunction(simpleAddition, 903)); + pointers.add(Pointer.fromFunction(simpleAddition, 904)); + pointers.add(Pointer.fromFunction(simpleAddition, 905)); + pointers.add(Pointer.fromFunction(simpleAddition, 906)); + pointers.add(Pointer.fromFunction(simpleAddition, 907)); + pointers.add(Pointer.fromFunction(simpleAddition, 908)); + pointers.add(Pointer.fromFunction(simpleAddition, 909)); + pointers.add(Pointer.fromFunction(simpleAddition, 910)); + pointers.add(Pointer.fromFunction(simpleAddition, 911)); + pointers.add(Pointer.fromFunction(simpleAddition, 912)); + pointers.add(Pointer.fromFunction(simpleAddition, 913)); + pointers.add(Pointer.fromFunction(simpleAddition, 914)); + pointers.add(Pointer.fromFunction(simpleAddition, 915)); + pointers.add(Pointer.fromFunction(simpleAddition, 916)); + pointers.add(Pointer.fromFunction(simpleAddition, 917)); + pointers.add(Pointer.fromFunction(simpleAddition, 918)); + pointers.add(Pointer.fromFunction(simpleAddition, 919)); + pointers.add(Pointer.fromFunction(simpleAddition, 920)); + pointers.add(Pointer.fromFunction(simpleAddition, 921)); + pointers.add(Pointer.fromFunction(simpleAddition, 922)); + pointers.add(Pointer.fromFunction(simpleAddition, 923)); + pointers.add(Pointer.fromFunction(simpleAddition, 924)); + pointers.add(Pointer.fromFunction(simpleAddition, 925)); + pointers.add(Pointer.fromFunction(simpleAddition, 926)); + pointers.add(Pointer.fromFunction(simpleAddition, 927)); + pointers.add(Pointer.fromFunction(simpleAddition, 928)); + pointers.add(Pointer.fromFunction(simpleAddition, 929)); + pointers.add(Pointer.fromFunction(simpleAddition, 930)); + pointers.add(Pointer.fromFunction(simpleAddition, 931)); + pointers.add(Pointer.fromFunction(simpleAddition, 932)); + pointers.add(Pointer.fromFunction(simpleAddition, 933)); + pointers.add(Pointer.fromFunction(simpleAddition, 934)); + pointers.add(Pointer.fromFunction(simpleAddition, 935)); + pointers.add(Pointer.fromFunction(simpleAddition, 936)); + pointers.add(Pointer.fromFunction(simpleAddition, 937)); + pointers.add(Pointer.fromFunction(simpleAddition, 938)); + pointers.add(Pointer.fromFunction(simpleAddition, 939)); + pointers.add(Pointer.fromFunction(simpleAddition, 940)); + pointers.add(Pointer.fromFunction(simpleAddition, 941)); + pointers.add(Pointer.fromFunction(simpleAddition, 942)); + pointers.add(Pointer.fromFunction(simpleAddition, 943)); + pointers.add(Pointer.fromFunction(simpleAddition, 944)); + pointers.add(Pointer.fromFunction(simpleAddition, 945)); + pointers.add(Pointer.fromFunction(simpleAddition, 946)); + pointers.add(Pointer.fromFunction(simpleAddition, 947)); + pointers.add(Pointer.fromFunction(simpleAddition, 948)); + pointers.add(Pointer.fromFunction(simpleAddition, 949)); + pointers.add(Pointer.fromFunction(simpleAddition, 950)); + pointers.add(Pointer.fromFunction(simpleAddition, 951)); + pointers.add(Pointer.fromFunction(simpleAddition, 952)); + pointers.add(Pointer.fromFunction(simpleAddition, 953)); + pointers.add(Pointer.fromFunction(simpleAddition, 954)); + pointers.add(Pointer.fromFunction(simpleAddition, 955)); + pointers.add(Pointer.fromFunction(simpleAddition, 956)); + pointers.add(Pointer.fromFunction(simpleAddition, 957)); + pointers.add(Pointer.fromFunction(simpleAddition, 958)); + pointers.add(Pointer.fromFunction(simpleAddition, 959)); + pointers.add(Pointer.fromFunction(simpleAddition, 960)); + pointers.add(Pointer.fromFunction(simpleAddition, 961)); + pointers.add(Pointer.fromFunction(simpleAddition, 962)); + pointers.add(Pointer.fromFunction(simpleAddition, 963)); + pointers.add(Pointer.fromFunction(simpleAddition, 964)); + pointers.add(Pointer.fromFunction(simpleAddition, 965)); + pointers.add(Pointer.fromFunction(simpleAddition, 966)); + pointers.add(Pointer.fromFunction(simpleAddition, 967)); + pointers.add(Pointer.fromFunction(simpleAddition, 968)); + pointers.add(Pointer.fromFunction(simpleAddition, 969)); + pointers.add(Pointer.fromFunction(simpleAddition, 970)); + pointers.add(Pointer.fromFunction(simpleAddition, 971)); + pointers.add(Pointer.fromFunction(simpleAddition, 972)); + pointers.add(Pointer.fromFunction(simpleAddition, 973)); + pointers.add(Pointer.fromFunction(simpleAddition, 974)); + pointers.add(Pointer.fromFunction(simpleAddition, 975)); + pointers.add(Pointer.fromFunction(simpleAddition, 976)); + pointers.add(Pointer.fromFunction(simpleAddition, 977)); + pointers.add(Pointer.fromFunction(simpleAddition, 978)); + pointers.add(Pointer.fromFunction(simpleAddition, 979)); + pointers.add(Pointer.fromFunction(simpleAddition, 980)); + pointers.add(Pointer.fromFunction(simpleAddition, 981)); + pointers.add(Pointer.fromFunction(simpleAddition, 982)); + pointers.add(Pointer.fromFunction(simpleAddition, 983)); + pointers.add(Pointer.fromFunction(simpleAddition, 984)); + pointers.add(Pointer.fromFunction(simpleAddition, 985)); + pointers.add(Pointer.fromFunction(simpleAddition, 986)); + pointers.add(Pointer.fromFunction(simpleAddition, 987)); + pointers.add(Pointer.fromFunction(simpleAddition, 988)); + pointers.add(Pointer.fromFunction(simpleAddition, 989)); + pointers.add(Pointer.fromFunction(simpleAddition, 990)); + pointers.add(Pointer.fromFunction(simpleAddition, 991)); + pointers.add(Pointer.fromFunction(simpleAddition, 992)); + pointers.add(Pointer.fromFunction(simpleAddition, 993)); + pointers.add(Pointer.fromFunction(simpleAddition, 994)); + pointers.add(Pointer.fromFunction(simpleAddition, 995)); + pointers.add(Pointer.fromFunction(simpleAddition, 996)); + pointers.add(Pointer.fromFunction(simpleAddition, 997)); + pointers.add(Pointer.fromFunction(simpleAddition, 998)); + pointers.add(Pointer.fromFunction(simpleAddition, 999)); for (final pointer in pointers) { Test("SimpleAddition", pointer).run(); diff --git a/tests/ffi/function_callbacks_unsupported_test.dart b/tests/ffi/function_callbacks_unsupported_test.dart new file mode 100644 index 00000000000..5ac1b5d93ed --- /dev/null +++ b/tests/ffi/function_callbacks_unsupported_test.dart @@ -0,0 +1,19 @@ +// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +// +// Dart test program for testing that FFI callbacks report an appropriate +// runtime error for unsupported snapshot formats. + +import 'dart:ffi'; + +import 'package:expect/expect.dart'; + +bool checkError(UnsupportedError err) { + return "$err".contains("callbacks are not yet supported in blobs"); +} + +void main() { + Expect.throws( + () => Pointer.fromFunction(main), checkError); +} diff --git a/tests/ffi/static_checks_test.dart b/tests/ffi/static_checks_test.dart index 0a24b6d935d..22d52567890 100644 --- a/tests/ffi/static_checks_test.dart +++ b/tests/ffi/static_checks_test.dart @@ -36,6 +36,7 @@ void main() { testFromFunctionTypeMismatch(); testFromFunctionClosure(); testFromFunctionTearOff(); + testFromFunctionAbstract(); testLookupFunctionGeneric(); testLookupFunctionGeneric2(); testLookupFunctionWrongNativeFunctionSignature(); @@ -248,6 +249,10 @@ void testFromFunctionTearOff() { p = ffi.fromFunction(fld); //# 75: compile-time error } +void testFromFunctionAbstract() { + ffi.Pointer.fromFunction(testFromFunctionAbstract); //# 76: compile-time error +} + void testLookupFunctionGeneric() { Function generic() { ffi.DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library"); diff --git a/tools/VERSION b/tools/VERSION index f1a4b101723..618fa3d5b20 100644 --- a/tools/VERSION +++ b/tools/VERSION @@ -35,5 +35,5 @@ MINOR 6 PATCH 0 PRERELEASE 0 PRERELEASE_PATCH 0 -ABI_VERSION 15 -OLDEST_SUPPORTED_ABI_VERSION 15 +ABI_VERSION 14 +OLDEST_SUPPORTED_ABI_VERSION 13