root/core/NativeFunction.h
/* [<][>][^][v][top][bottom][index][help] */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is [Open Source Virtual Machine.].
*
* The Initial Developer of the Original Code is
* Adobe System Incorporated.
* Portions created by the Initial Developer are Copyright (C) 1993-2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Adobe AS3 Team
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __avmplus_NativeFunction__
#define __avmplus_NativeFunction__
#ifdef VMCFG_AOT
#include "CdeclThunk.h"
struct AOTInfo;
#endif
namespace avmplus
{
typedef avmplus::AbcEnv* AvmInstance;
typedef avmplus::ScriptObject* AvmObject;
typedef avmplus::String* AvmString;
typedef avmplus::Namespace* AvmNamespace;
typedef avmplus::Atom AvmBox;
typedef avmplus::MethodEnv* AvmMethodEnv;
typedef int32_t AvmBool32;
#define kAvmThunkNull nullObjectAtom
#define kAvmThunkUndefined undefinedAtom
#define kAvmThunkInfinity (MathUtils::kInfinity)
#define kAvmThunkNegInfinity (MathUtils::kNegInfinity)
#define kAvmThunkNaN (MathUtils::kNaN)
typedef AvmObject AvmRetType_AvmObject;
typedef bool AvmRetType_AvmBool32; // bools are passed in as int32, but returned as bool, for historic reasons
typedef int32_t AvmRetType_int32_t;
typedef uint32_t AvmRetType_uint32_t;
typedef AvmNamespace AvmRetType_AvmNamespace;
typedef AvmBox AvmRetType_AvmBox;
typedef AvmString AvmRetType_AvmString;
typedef void AvmRetType_void;
typedef double AvmRetType_double;
typedef avmplus::ScriptObject AvmObjectT;
typedef avmplus::String AvmStringT;
typedef avmplus::Namespace AvmNamespaceT;
typedef AvmBox (*AvmThunkNativeThunker)(AvmMethodEnv env, uint32_t argc, AvmBox* argv);
typedef double (*AvmThunkNativeThunkerN)(AvmMethodEnv env, uint32_t argc, AvmBox* argv);
#ifdef AVMPLUS_INDIRECT_NATIVE_THUNKS
typedef void (AvmPlusScriptableObject::*AvmThunkNativeMethodHandler)();
typedef void (*AvmThunkNativeFunctionHandler)(AvmPlusScriptableObject* obj);
#endif
const uintptr_t kUnboxMask = ~uintptr_t(7);
#ifdef _DEBUG
extern void FASTCALL check_unbox(MethodEnv* env, bool u);
inline uintptr_t _AvmThunkUnbox_AvmReceiver(AvmMethodEnv env, uintptr_t r)
{
check_unbox(env, false);
AvmAssert((r & ~kUnboxMask) == 0);
return r;
}
#define AvmThunkUnbox_AvmReceiver(t,r) ((t)(_AvmThunkUnbox_AvmReceiver(env, uintptr_t(r))))
inline uintptr_t _AvmThunkUnbox_AvmAtomReceiver(AvmMethodEnv env, uintptr_t r)
{
check_unbox(env, true);
return r & kUnboxMask;
}
#define AvmThunkUnbox_AvmAtomReceiver(t,r) ((t)(_AvmThunkUnbox_AvmAtomReceiver(env, uintptr_t(r))))
#else
#define AvmThunkUnbox_AvmReceiver(t,r) ((t)(uintptr_t(r)))
#define AvmThunkUnbox_AvmAtomReceiver(t,r) ((t)(uintptr_t(r) & kUnboxMask))
#endif
#define AvmThunkUnbox_AvmObject(r) ((ScriptObject*)(r))
#define AvmThunkUnbox_AvmBool32(r) ((r) != 0)
#define AvmThunkUnbox_int32_t(r) int32_t(r)
#define AvmThunkUnbox_uint32_t(r) uint32_t(r)
#define AvmThunkUnbox_AvmNamespace(r) ((Namespace*)(r))
#define AvmThunkUnbox_AvmBox(r) (r)
#define AvmThunkUnbox_AvmString(r) ((String*)(r))
#define AvmThunkUnbox_void(r) (error ??? illegal)
#define AvmThunkUnbox_double(r) AvmThunkUnbox_double_impl(&(r))
#define AvmThunkArgSize_AvmObject 1
#define AvmThunkArgSize_AvmBool32 1
#define AvmThunkArgSize_int32_t 1
#define AvmThunkArgSize_uint32_t 1
#define AvmThunkArgSize_AvmNamespace 1
#define AvmThunkArgSize_AvmBox 1
#define AvmThunkArgSize_AvmString 1
#define AvmThunkArgSize_void (error ??? illegal)
#ifdef AVMPLUS_64BIT
#define AvmThunkArgSize_double 1
#else
#define AvmThunkArgSize_double 2
#endif
inline double AvmThunkUnbox_double_impl(const AvmBox* b)
{
#if defined(AVMPLUS_64BIT)
AvmAssert(sizeof(AvmBox) == sizeof(double));
return *(const double*)b;
#elif defined(AVMPLUS_UNALIGNED_ACCESS)
AvmAssert(sizeof(AvmBox)*2 == sizeof(double));
return *(const double*)b;
#else
AvmAssert(sizeof(AvmBox)*2 == sizeof(double));
union {
double d;
AvmBox b[2];
} u;
// @todo, does this need endian attention?
u.b[0] = b[0];
u.b[1] = b[1];
return u.d;
#endif
}
// trick, since values are compile-time known we usually don't need to call intToAtom, can statically transform them
// good for ints and ints currently
#define AvmThunkCanBeSmallIntAtom(v) (!((v) & 0xF0000000))
#define AvmThunkSmallIntAtom(v) ((((Atom)(v))<<3) | kIntptrType)
// note, this isn't complete -- only the ones currently needed are defined.
// expand as necessary. macros to take advantage of the fact that most
// args are compile-time constants.
#define AvmThunkCoerce_int32_t_double(v) double(v)
#define AvmThunkCoerce_int32_t_uint32_t(v) uint32_t(v)
#define AvmThunkCoerce_int32_t_AvmBox(v) (AvmThunkCanBeSmallIntAtom(v) ? AvmThunkSmallIntAtom(v) : env->core()->intAtom(v))
#define AvmThunkCoerce_uint32_t_double(v) double(v)
#define AvmThunkCoerce_uint32_t_int32_t(v) int32_t(v)
#define AvmThunkCoerce_uint32_t_AvmBox(v) (AvmThunkCanBeSmallIntAtom(v) ? AvmThunkSmallIntAtom(v) : env->core()->intAtom(v))
#define AvmThunkCoerce_AvmBool32_AvmBox(v) ((v) ? trueAtom : falseAtom)
#ifdef _DEBUG
inline double AvmThunkCoerce_AvmBox_double(AvmBox v) { AvmAssert((v) == kAvmThunkUndefined); (void)v; return kAvmThunkNaN; }
inline AvmString AvmThunkCoerce_AvmBox_AvmString(AvmBox v) { AvmAssert((v) == kAvmThunkUndefined || (v) == kAvmThunkNull); (void)v; return NULL; }
inline AvmObject AvmThunkCoerce_AvmBox_AvmObject(AvmBox v) { AvmAssert((v) == kAvmThunkUndefined || (v) == kAvmThunkNull); (void)v; return NULL; }
#else
#define AvmThunkCoerce_AvmBox_double(v) (kAvmThunkNaN)
#define AvmThunkCoerce_AvmBox_AvmString(v) (NULL)
#define AvmThunkCoerce_AvmBox_AvmObject(v) (NULL)
#endif
#define AvmThunkCoerce_AvmString_AvmBox(v) ((v) ? (v)->atom() : nullStringAtom)
#define AvmThunkConstant_AvmString(v) (env->method->pool()->getString(v))
#ifdef AVMPLUS_INDIRECT_NATIVE_THUNKS
#define AVMTHUNK_GET_METHOD_HANDLER(env) ((env)->method->handler_method())
#define AVMTHUNK_GET_FUNCTION_HANDLER(env) ((env)->method->handler_function())
#endif
#ifdef AVMPLUS_INDIRECT_NATIVE_THUNKS
union AvmThunkNativeHandler
{
AvmThunkNativeMethodHandler method;
AvmThunkNativeFunctionHandler function;
};
#endif
struct NativeMethodInfo
{
public:
#ifdef AVMPLUS_INDIRECT_NATIVE_THUNKS
AvmThunkNativeHandler handler;
#endif
AvmThunkNativeThunker thunker;
#ifdef AVMPLUS_STATIC_POINTERS
int32_t method_id;
#endif
};
struct NativeClassInfo
{
public:
CreateClassClosureProc createClassClosure;
#ifdef AVMPLUS_STATIC_POINTERS
int32_t class_id;
#endif
uint16_t sizeofClass;
uint16_t offsetofSlotsClass;
uint16_t sizeofInstance;
uint16_t offsetofSlotsInstance;
};
// ---------------
class NativeInitializer
{
public:
NativeInitializer(AvmCore* core,
#ifdef VMCFG_AOT
const AOTInfo *aotInfo,
#else
const uint8_t* abcData,
uint32_t abcDataLen,
#endif
uint32_t methodCount,
uint32_t classCount);
~NativeInitializer();
PoolObject* parseBuiltinABC(Domain* domain);
const NativeMethodInfo* getNativeInfo(uint32_t i) const { return get_method(i); }
#ifdef VMCFG_AOT
bool getCompiledInfo(NativeMethodInfo *info, Multiname &returnTypeName, uint32_t i) const;
bool hasBuiltins() const { return methodCount || classCount; }
const AOTInfo* get_aotInfo() const { return aotInfo; }
#endif
#ifdef AVMPLUS_STATIC_POINTERS
void fillInMethods(const NativeMethodInfo* methodEntry);
void fillInClasses(const NativeClassInfo* classEntry);
#ifdef VMCFG_AOT
inline const NativeClassInfo* get_class(uint32_t i) const
{
return i < classCount ? classes[i] : 0;
}
#else
inline const NativeClassInfo* get_class(uint32_t i) const { AvmAssert(i < classCount); return classes[i]; }
#endif
#else
typedef void (*FillInProc)(NativeMethodInfo* m, NativeClassInfo* c);
void fillIn(FillInProc p);
inline const NativeClassInfo* get_class(uint32_t i) const { AvmAssert(i < classCount); return &classes[i]; }
#endif
private:
#ifdef AVMPLUS_STATIC_POINTERS
typedef const NativeMethodInfo* MethodType;
typedef const NativeClassInfo* ClassType;
inline const NativeMethodInfo* get_method(uint32_t i) const { AvmAssert(i < methodCount); return methods[i]; }
#else
typedef NativeMethodInfo MethodType;
typedef NativeClassInfo ClassType;
inline const NativeMethodInfo* get_method(uint32_t i) const { AvmAssert(i < methodCount); return &methods[i]; }
#endif
private:
AvmCore* const core;
const uint8_t* const abcData;
uint32_t const abcDataLen;
MethodType* const methods;
ClassType* const classes;
const uint32_t methodCount;
const uint32_t classCount;
#ifdef VMCFG_AOT
const AOTInfo* aotInfo;
const AvmThunkNativeFunctionHandler* compiledMethods;
const uint32_t compiledMethodCount;
#endif
};
#ifdef AVMPLUS_INDIRECT_NATIVE_THUNKS
#define _NATIVE_METHOD_CAST_PTR(CLS, PTR) \
reinterpret_cast<AvmThunkNativeMethodHandler>((void(CLS::*)())(PTR))
#endif
#ifdef _DEBUG
#define AVMTHUNK_NATIVE_CLASS_GLUE(CLS, FQCLS, ASSERT_FUNC) \
static ClassClosure* CLS##_createClassClosure(VTable* cvtable) \
{ \
FQCLS* cc = new (cvtable->gc(), cvtable->getExtraSize()) FQCLS(cvtable); \
ASSERT_FUNC(cc->traits(), cc->traits()->itraits); \
return cc; \
}
#else
#define AVMTHUNK_NATIVE_CLASS_GLUE(CLS, FQCLS, ASSERT_FUNC) \
static ClassClosure* CLS##_createClassClosure(VTable* cvtable) \
{ return new (cvtable->gc(), cvtable->getExtraSize()) FQCLS(cvtable); }
#endif
#ifdef VMCFG_AOT
#define AVMTHUNK_DECLARE_NATIVE_INITIALIZER(NAME) \
extern PoolObject* initBuiltinABC_##NAME(AvmCore* core, Domain* domain); \
extern const NativeClassInfo NAME##_classEntries[]; \
extern const NativeMethodInfo NAME##_methodEntries[];
#else
#define AVMTHUNK_DECLARE_NATIVE_INITIALIZER(NAME) \
extern PoolObject* initBuiltinABC_##NAME(AvmCore* core, Domain* domain);
#endif
#ifdef AVMPLUS_STATIC_POINTERS
#define AVMTHUNK_BEGIN_NATIVE_TABLES(NAME)
#define AVMTHUNK_END_NATIVE_TABLES()
// ---------------
#ifdef VMCFG_AOT
#define AVMTHUNK_BEGIN_NATIVE_METHODS(NAME) \
const NativeMethodInfo NAME##_methodEntries[] = {
#else
#define AVMTHUNK_BEGIN_NATIVE_METHODS(NAME) \
static const NativeMethodInfo NAME##_methodEntries[] = {
#endif
#ifdef AVMPLUS_INDIRECT_NATIVE_THUNKS
#define _AVMTHUNK_NATIVE_METHOD(CLS, METHID, IMPL) \
{ { _NATIVE_METHOD_CAST_PTR(CLS, &IMPL) }, (AvmThunkNativeThunker)avmplus::NativeID::METHID##_thunk, avmplus::NativeID::METHID },
#else
#define _AVMTHUNK_NATIVE_METHOD(CLS, METHID, IMPL) \
{ (AvmThunkNativeThunker)avmplus::NativeID::METHID##_thunk, avmplus::NativeID::METHID },
#endif
#define AVMTHUNK_NATIVE_METHOD(METHID, IMPL) \
_AVMTHUNK_NATIVE_METHOD(ScriptObject, METHID, IMPL)
#define AVMTHUNK_NATIVE_METHOD_STRING(METHID, IMPL) \
_AVMTHUNK_NATIVE_METHOD(avmplus::String, METHID, IMPL)
#define AVMTHUNK_NATIVE_METHOD_NAMESPACE(METHID, IMPL) \
_AVMTHUNK_NATIVE_METHOD(avmplus::Namespace, METHID, IMPL)
#ifdef VMCFG_AOT
// AOT build env is ok with designated inits
#define AVMTHUNK_NATIVE_FUNCTION(METHID, IMPL) \
{ { function: reinterpret_cast<AvmThunkNativeFunctionHandler>(IMPL) }, (AvmThunkNativeThunker)avmplus::NativeID::METHID##_thunk, avmplus::NativeID::METHID },
#define AVMTHUNK_END_NATIVE_METHODS() \
{ { NULL }, NULL, -1 } };
#else
#ifdef AVMPLUS_INDIRECT_NATIVE_THUNKS
// C++ won't let us auto-init a union to a field other than the first one, nor will it
// allow us to reliably cast between a pointer-to-function and pointer-to-member-function,
// thus this inline function to massage the few places that need it.
inline AvmThunkNativeMethodHandler _to_method_handler(AvmThunkNativeFunctionHandler function)
{
AvmThunkNativeHandler handler;
handler.function = function;
return handler.method;
}
#define AVMTHUNK_NATIVE_FUNCTION(METHID, IMPL) \
{ { _to_method_handler(reinterpret_cast<AvmThunkNativeFunctionHandler>(IMPL)) }, (AvmThunkNativeThunker)avmplus::NativeID::METHID##_thunk, avmplus::NativeID::METHID },
#define AVMTHUNK_END_NATIVE_METHODS() \
{ { NULL }, NULL, -1 } };
#else
#define AVMTHUNK_NATIVE_FUNCTION(METHID, IMPL) \
{ (AvmThunkNativeThunker)avmplus::NativeID::METHID##_thunk, avmplus::NativeID::METHID },
#define AVMTHUNK_END_NATIVE_METHODS() \
{ NULL, -1 } };
#endif
#endif
// ---------------
#define AVMTHUNK_BEGIN_NATIVE_CLASSES(NAME) \
const NativeClassInfo NAME##_classEntries[] = {
#define AVMTHUNK_NATIVE_CLASS(CLSID, CLS, FQCLS, OFFSETOFSLOTSCLS, INST, OFFSETOFSLOTSINST) \
{ (CreateClassClosureProc)CLS##_createClassClosure, avmplus::NativeID::CLSID, sizeof(FQCLS), OFFSETOFSLOTSCLS, sizeof(INST), OFFSETOFSLOTSINST },
#define AVMTHUNK_END_NATIVE_CLASSES() \
{ NULL, -1, 0, 0, 0, 0 } };
#ifdef VMCFG_AOT
#define AVMTHUNK_DEFINE_NATIVE_INITIALIZER(NAME)
#else
#define AVMTHUNK_DEFINE_NATIVE_INITIALIZER(NAME) \
PoolObject* initBuiltinABC_##NAME(AvmCore* core, Domain* domain) { \
NativeInitializer ninit(core, \
avmplus::NativeID::NAME##_abc_data, \
avmplus::NativeID::NAME##_abc_length, \
avmplus::NativeID::NAME##_abc_method_count, \
avmplus::NativeID::NAME##_abc_class_count); \
ninit.fillInClasses(NAME##_classEntries); \
ninit.fillInMethods(NAME##_methodEntries); \
return ninit.parseBuiltinABC(domain); \
}
#endif
#else
#define AVMTHUNK_BEGIN_NATIVE_TABLES(NAME) \
static void fillIn_##NAME(NativeMethodInfo* m, NativeClassInfo* c) {
#define AVMTHUNK_END_NATIVE_TABLES() \
}
// ---------------
#define AVMTHUNK_BEGIN_NATIVE_METHODS(NAME)
#ifdef AVMPLUS_INDIRECT_NATIVE_THUNKS
#define _AVMTHUNK_NATIVE_METHOD(CLS, METHID, IMPL) \
m[METHID].handler.method = _NATIVE_METHOD_CAST_PTR(CLS, &IMPL); \
m[METHID].thunker = (AvmThunkNativeThunker)avmplus::NativeID::METHID##_thunk;
#else
#define _AVMTHUNK_NATIVE_METHOD(CLS, METHID, IMPL) \
m[METHID].thunker = (AvmThunkNativeThunker)avmplus::NativeID::METHID##_thunk;
#endif
#define AVMTHUNK_NATIVE_METHOD(METHID, IMPL) \
_AVMTHUNK_NATIVE_METHOD(ScriptObject, METHID, IMPL)
#define AVMTHUNK_NATIVE_METHOD_STRING(METHID, IMPL) \
_AVMTHUNK_NATIVE_METHOD(avmplus::String, METHID, IMPL)
#define AVMTHUNK_NATIVE_METHOD_NAMESPACE(METHID, IMPL) \
_AVMTHUNK_NATIVE_METHOD(avmplus::Namespace, METHID, IMPL)
#ifdef AVMPLUS_INDIRECT_NATIVE_THUNKS
#define AVMTHUNK_NATIVE_FUNCTION(METHID, IMPL) \
m[METHID].handler.function = reinterpret_cast<AvmThunkNativeFunctionHandler>(IMPL); \
m[METHID].thunker = (AvmThunkNativeThunker)avmplus::NativeID::METHID##_thunk;
#else
#define AVMTHUNK_NATIVE_FUNCTION(METHID, IMPL) \
m[METHID].thunker = (AvmThunkNativeThunker)avmplus::NativeID::METHID##_thunk;
#endif
#define AVMTHUNK_END_NATIVE_METHODS()
// ---------------
#define AVMTHUNK_BEGIN_NATIVE_CLASSES(NAME)
#define AVMTHUNK_NATIVE_CLASS(CLSID, CLS, FQCLS, OFFSETOFSLOTSCLS, INST, OFFSETOFSLOTSINST) \
c[CLSID].createClassClosure = (CreateClassClosureProc)CLS##_createClassClosure; \
c[CLSID].sizeofClass = sizeof(FQCLS); \
c[CLSID].offsetofSlotsClass = OFFSETOFSLOTSCLS; \
c[CLSID].sizeofInstance = sizeof(INST); \
c[CLSID].offsetofSlotsInstance = OFFSETOFSLOTSINST;
#define AVMTHUNK_END_NATIVE_CLASSES()
#define AVMTHUNK_DEFINE_NATIVE_INITIALIZER(NAME) \
PoolObject* initBuiltinABC_##NAME(AvmCore* core, Domain* domain) { \
NativeInitializer ninit(core, \
avmplus::NativeID::NAME##_abc_data, \
avmplus::NativeID::NAME##_abc_length, \
avmplus::NativeID::NAME##_abc_method_count, \
avmplus::NativeID::NAME##_abc_class_count); \
ninit.fillIn(fillIn_##NAME); \
return ninit.parseBuiltinABC(domain); \
}
#endif // AVMPLUS_STATIC_POINTERS
#define AVM_INIT_BUILTIN_ABC_IN_DOMAIN(MAPNAME, CORE, DOMAIN) \
avmplus::NativeID::initBuiltinABC_##MAPNAME((CORE), (DOMAIN))
#define AVM_INIT_BUILTIN_ABC(MAPNAME, CORE) \
avmplus::NativeID::initBuiltinABC_##MAPNAME((CORE), (CORE)->builtinDomain)
}
#endif /* __avmplus_NativeFunction__ */