// Copyright (c) 2011, 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_NATIVE_ENTRY_H_ #define RUNTIME_VM_NATIVE_ENTRY_H_ #include "vm/allocation.h" #include "vm/log.h" #include "vm/native_arguments.h" #include "vm/native_function.h" namespace dart { // Forward declarations. class Class; class String; #ifdef DEBUG #define TRACE_NATIVE_CALL(format, name) \ if (FLAG_trace_natives) { \ THR_Print("Calling native: " format "\n", name); \ } #else #define TRACE_NATIVE_CALL(format, name) \ do { \ } while (0) #endif typedef ObjectPtr (*BootstrapNativeFunction)(Thread* thread, Zone* zone, NativeArguments* arguments); #define DEFINE_NATIVE_ENTRY(name, type_argument_count, argument_count) \ static ObjectPtr DN_Helper##name(Isolate* isolate, Thread* thread, \ Zone* zone, NativeArguments* arguments); \ ObjectPtr BootstrapNatives::DN_##name(Thread* thread, Zone* zone, \ NativeArguments* arguments) { \ TRACE_NATIVE_CALL("%s", "" #name); \ ASSERT(arguments->NativeArgCount() == argument_count); \ /* Note: a longer type arguments vector may be passed */ \ ASSERT(arguments->NativeTypeArgCount() >= type_argument_count); \ return DN_Helper##name(thread->isolate(), thread, zone, arguments); \ } \ static ObjectPtr DN_Helper##name(Isolate* isolate, Thread* thread, \ Zone* zone, NativeArguments* arguments) #define DEFINE_FFI_NATIVE_ENTRY(name, return_type, argument_types) \ return_type BootstrapNatives::FN_##name argument_types // Helpers that throw an argument exception. void DartNativeThrowTypeArgumentCountException(int num_type_args, int num_type_args_expected); void DartNativeThrowArgumentException(const Instance& instance); // Native should throw an exception if the wrong number of type arguments is // passed. #define NATIVE_TYPE_ARGUMENT_COUNT(expected) \ int __num_type_arguments = arguments->NativeTypeArgCount(); \ if (__num_type_arguments != expected) { \ DartNativeThrowTypeArgumentCountException(__num_type_arguments, expected); \ } #define GET_NATIVE_TYPE_ARGUMENT(name, value) \ AbstractType& name = AbstractType::Handle(value); // Natives should throw an exception if an illegal argument or null is passed. // type name = value. #define GET_NON_NULL_NATIVE_ARGUMENT(type, name, value) \ const Instance& __##name##_instance__ = \ Instance::CheckedHandle(zone, value); \ if (!__##name##_instance__.Is##type()) { \ DartNativeThrowArgumentException(__##name##_instance__); \ } \ const type& name = type::Cast(__##name##_instance__); // Natives should throw an exception if an illegal argument is passed. // type name = value. #define GET_NATIVE_ARGUMENT(type, name, value) \ const Instance& __##name##_instance__ = \ Instance::CheckedHandle(zone, value); \ type& name = type::Handle(zone); \ if (!__##name##_instance__.IsNull()) { \ if (!__##name##_instance__.Is##type()) { \ DartNativeThrowArgumentException(__##name##_instance__); \ } \ } \ name ^= value; // Helper class for resolving and handling native functions. class NativeEntry : public AllStatic { public: static constexpr intptr_t kNumArguments = 1; static constexpr intptr_t kNumCallWrapperArguments = 2; // Resolve specified dart native function to the actual native entrypoint. static NativeFunction ResolveNative(const Library& library, const String& function_name, int number_of_arguments, bool* auto_setup_scope); static const uint8_t* ResolveSymbolInLibrary(const Library& library, uword pc); static const uint8_t* ResolveSymbol(uword pc); static uword BootstrapNativeCallWrapperEntry(); static void BootstrapNativeCallWrapper(Dart_NativeArguments args, Dart_NativeFunction func); static uword NoScopeNativeCallWrapperEntry(); static void NoScopeNativeCallWrapper(Dart_NativeArguments args, Dart_NativeFunction func); static uword AutoScopeNativeCallWrapperEntry(); static void AutoScopeNativeCallWrapper(Dart_NativeArguments args, Dart_NativeFunction func); static uword LinkNativeCallEntry(); static void LinkNativeCall(Dart_NativeArguments args); private: static void MaybePropagateError(NativeArguments* arguments); }; #if !defined(DART_PRECOMPILED_RUNTIME) class NativeEntryData : public ValueObject { public: explicit NativeEntryData(const TypedData& data) : data_(data) {} MethodRecognizer::Kind kind() const; void set_kind(MethodRecognizer::Kind value) const; static MethodRecognizer::Kind GetKind(TypedDataPtr data); NativeFunctionWrapper trampoline() const; void set_trampoline(NativeFunctionWrapper value) const; static NativeFunctionWrapper GetTrampoline(TypedDataPtr data); NativeFunction native_function() const; void set_native_function(NativeFunction value) const; static NativeFunction GetNativeFunction(TypedDataPtr data); intptr_t argc_tag() const; void set_argc_tag(intptr_t value) const; static intptr_t GetArgcTag(TypedDataPtr data); static TypedDataPtr New(MethodRecognizer::Kind kind, NativeFunctionWrapper trampoline, NativeFunction native_function, intptr_t argc_tag); private: struct Payload { NativeFunctionWrapper trampoline; NativeFunction native_function; intptr_t argc_tag; MethodRecognizer::Kind kind; }; static Payload* FromTypedArray(TypedDataPtr data); const TypedData& data_; friend class ObjectPoolSerializationCluster; DISALLOW_COPY_AND_ASSIGN(NativeEntryData); }; #endif // !defined(DART_PRECOMPILED_RUNTIME) } // namespace dart #endif // RUNTIME_VM_NATIVE_ENTRY_H_