mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-28 12:45:27 +00:00
Revise js-facing API for js-ctypes, patch v1. b=513788, r=jorendorff
This commit is contained in:
parent
80dd558623
commit
afa52d32f7
4284
js/ctypes/CTypes.cpp
Normal file
4284
js/ctypes/CTypes.cpp
Normal file
File diff suppressed because it is too large
Load Diff
277
js/ctypes/CTypes.h
Normal file
277
js/ctypes/CTypes.h
Normal file
@ -0,0 +1,277 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
||||||
|
/* ***** 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 js-ctypes.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is
|
||||||
|
* The Mozilla Foundation <http://www.mozilla.org/>.
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* Dan Witte <dwitte@mozilla.com>
|
||||||
|
*
|
||||||
|
* 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 CTYPES_H
|
||||||
|
#define CTYPES_H
|
||||||
|
|
||||||
|
#include "jsapi.h"
|
||||||
|
#include "nsString.h"
|
||||||
|
#include "ffi.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace ctypes {
|
||||||
|
|
||||||
|
// for JS error reporting
|
||||||
|
enum ErrorNum {
|
||||||
|
#define MSG_DEF(name, number, count, exception, format) \
|
||||||
|
name = number,
|
||||||
|
#include "ctypes.msg"
|
||||||
|
#undef MSG_DEF
|
||||||
|
CTYPESERR_LIMIT
|
||||||
|
};
|
||||||
|
|
||||||
|
const JSErrorFormatString*
|
||||||
|
GetErrorMessage(void* userRef, const char* locale, const uintN errorNumber);
|
||||||
|
bool TypeError(JSContext* cx, const char* expected, jsval actual);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ABI constants that specify the calling convention to use.
|
||||||
|
* ctypes.default_abi corresponds to the cdecl convention, and in almost all
|
||||||
|
* cases is the correct choice. ctypes.stdcall_abi is provided for calling
|
||||||
|
* functions in the Microsoft Win32 API.
|
||||||
|
*/
|
||||||
|
enum ABICode {
|
||||||
|
ABI_DEFAULT,
|
||||||
|
ABI_STDCALL,
|
||||||
|
INVALID_ABI
|
||||||
|
};
|
||||||
|
|
||||||
|
enum TypeCode {
|
||||||
|
TYPE_void_t,
|
||||||
|
#define DEFINE_TYPE(name, type, ffiType) TYPE_##name,
|
||||||
|
#include "typedefs.h"
|
||||||
|
TYPE_pointer,
|
||||||
|
TYPE_array,
|
||||||
|
TYPE_struct
|
||||||
|
};
|
||||||
|
|
||||||
|
ABICode GetABICode(JSContext* cx, JSObject* obj);
|
||||||
|
|
||||||
|
struct FieldInfo
|
||||||
|
{
|
||||||
|
nsCString mName;
|
||||||
|
JSObject* mType;
|
||||||
|
size_t mOffset;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool InitTypeClasses(JSContext* cx, JSObject* parent);
|
||||||
|
|
||||||
|
bool ConvertToJS(JSContext* cx, JSObject* typeObj, JSObject* dataObj, void* data, bool wantPrimitive, jsval* result);
|
||||||
|
bool ImplicitConvert(JSContext* cx, jsval val, JSObject* targetType, void* buffer, bool isArgument, bool* freePointer);
|
||||||
|
bool ExplicitConvert(JSContext* cx, jsval val, JSObject* targetType, void* buffer);
|
||||||
|
|
||||||
|
// Contents of the various slots on each JSClass. The slot indexes are given
|
||||||
|
// enumerated names for readability.
|
||||||
|
enum CABISlot {
|
||||||
|
SLOT_ABICODE = 0, // ABICode of the CABI object
|
||||||
|
CABI_SLOTS
|
||||||
|
};
|
||||||
|
|
||||||
|
enum CTypeProtoSlot {
|
||||||
|
SLOT_POINTERPROTO = 0, // ctypes.PointerType.prototype object
|
||||||
|
SLOT_ARRAYPROTO = 1, // ctypes.ArrayType.prototype object
|
||||||
|
SLOT_STRUCTPROTO = 2, // ctypes.StructType.prototype object
|
||||||
|
SLOT_INT64PROTO = 3, // ctypes.Int64.prototype object
|
||||||
|
SLOT_UINT64PROTO = 4, // ctypes.UInt64.prototype object
|
||||||
|
CTYPEPROTO_SLOTS
|
||||||
|
};
|
||||||
|
|
||||||
|
enum CTypeSlot {
|
||||||
|
SLOT_TYPECODE = 0, // TypeCode of the CType object
|
||||||
|
SLOT_FFITYPE = 1, // ffi_type representing the type
|
||||||
|
SLOT_ALIGN = 2, // alignment of the data type, in bytes
|
||||||
|
SLOT_PTR = 3, // cached PointerType object for type.ptr
|
||||||
|
SLOT_FIELDINFO = 4, // (StructTypes only) FieldInfo array
|
||||||
|
CTYPE_SLOTS
|
||||||
|
};
|
||||||
|
|
||||||
|
enum CDataSlot {
|
||||||
|
SLOT_CTYPE = 0, // CType object representing the underlying type
|
||||||
|
SLOT_REFERENT = 1, // CData object this object refers to, if any
|
||||||
|
SLOT_DATA = 2, // pointer to a buffer containing the binary data
|
||||||
|
CDATA_SLOTS
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Int64Slot {
|
||||||
|
SLOT_INT64 = 0, // pointer to a 64-bit buffer containing the integer
|
||||||
|
INT64_SLOTS
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Int64FunctionSlot {
|
||||||
|
SLOT_FN_INT64PROTO = 0 // ctypes.{Int64,UInt64}.prototype object
|
||||||
|
// JSFunction objects always get exactly two slots.
|
||||||
|
};
|
||||||
|
|
||||||
|
class CType {
|
||||||
|
public:
|
||||||
|
static JSObject* Create(JSContext* cx, JSObject* proto, JSString* name, TypeCode type, jsval size, jsval align, ffi_type* ffiType);
|
||||||
|
static JSObject* DefineBuiltin(JSContext* cx, JSObject* parent, const char* propName, JSObject* proto, const char* name, TypeCode type, jsval size, jsval align, ffi_type* ffiType);
|
||||||
|
static void Finalize(JSContext* cx, JSObject* obj);
|
||||||
|
|
||||||
|
static JSBool ConstructAbstract(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval);
|
||||||
|
static JSBool ConstructData(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval);
|
||||||
|
static JSBool ConstructBasic(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval);
|
||||||
|
|
||||||
|
static bool IsCType(JSContext* cx, JSObject* obj);
|
||||||
|
static TypeCode GetTypeCode(JSContext* cx, JSObject* typeObj);
|
||||||
|
static bool TypesEqual(JSContext* cx, JSObject* t1, JSObject* t2);
|
||||||
|
static size_t GetSize(JSContext* cx, JSObject* obj);
|
||||||
|
static bool GetSafeSize(JSContext* cx, JSObject* obj, size_t* result);
|
||||||
|
static bool IsSizeDefined(JSContext* cx, JSObject* obj);
|
||||||
|
static size_t GetAlignment(JSContext* cx, JSObject* obj);
|
||||||
|
static ffi_type* GetFFIType(JSContext* cx, JSObject* obj);
|
||||||
|
static JSString* GetName(JSContext* cx, JSObject* obj);
|
||||||
|
static JSObject* GetProtoFromCtor(JSContext* cx, JSObject* obj, CTypeProtoSlot slot);
|
||||||
|
static JSObject* GetProtoFromType(JSContext* cx, JSObject* obj, CTypeProtoSlot slot);
|
||||||
|
|
||||||
|
static JSBool PtrGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp);
|
||||||
|
static JSBool Array(JSContext* cx, uintN argc, jsval* vp);
|
||||||
|
static JSBool ToString(JSContext* cx, uintN argc, jsval* vp);
|
||||||
|
static JSBool ToSource(JSContext* cx, uintN argc, jsval* vp);
|
||||||
|
};
|
||||||
|
|
||||||
|
class PointerType {
|
||||||
|
public:
|
||||||
|
static JSBool Create(JSContext* cx, uintN argc, jsval* vp);
|
||||||
|
static JSObject* CreateInternal(JSContext* cx, JSObject* ctor, JSObject* baseType, JSString* name);
|
||||||
|
|
||||||
|
static JSBool ConstructData(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval);
|
||||||
|
static JSObject* ConstructInternal(JSContext* cx, JSObject* typeObj, JSObject* parentObj, void* data);
|
||||||
|
|
||||||
|
static JSObject* GetBaseType(JSContext* cx, JSObject* obj);
|
||||||
|
|
||||||
|
static JSBool ContentsGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp);
|
||||||
|
static JSBool ContentsSetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ArrayType {
|
||||||
|
public:
|
||||||
|
static JSBool Create(JSContext* cx, uintN argc, jsval* vp);
|
||||||
|
static JSObject* CreateInternal(JSContext* cx, JSObject* baseType, size_t length, bool lengthDefined);
|
||||||
|
|
||||||
|
static JSBool ConstructData(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval);
|
||||||
|
static JSObject* ConstructInternal(JSContext* cx, JSObject* typeObj, JSObject* parentObj, void* data);
|
||||||
|
|
||||||
|
static JSObject* GetBaseType(JSContext* cx, JSObject* obj);
|
||||||
|
static size_t GetLength(JSContext* cx, JSObject* obj);
|
||||||
|
static bool GetSafeLength(JSContext* cx, JSObject* obj, size_t* result);
|
||||||
|
|
||||||
|
static JSBool Getter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp);
|
||||||
|
static JSBool Setter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp);
|
||||||
|
static JSBool AddressOfElement(JSContext* cx, uintN argc, jsval* vp);
|
||||||
|
};
|
||||||
|
|
||||||
|
class StructType {
|
||||||
|
public:
|
||||||
|
static JSBool Create(JSContext* cx, uintN argc, jsval* vp);
|
||||||
|
|
||||||
|
static JSBool ConstructData(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval);
|
||||||
|
static JSObject* ConstructInternal(JSContext* cx, JSObject* typeObj, JSObject* parentObj, void* data);
|
||||||
|
|
||||||
|
static nsTArray<FieldInfo>* GetFieldInfo(JSContext* cx, JSObject* obj);
|
||||||
|
static FieldInfo* LookupField(JSContext* cx, JSObject* obj, jsval idval);
|
||||||
|
|
||||||
|
static JSBool FieldGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp);
|
||||||
|
static JSBool FieldSetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp);
|
||||||
|
static JSBool AddressOfField(JSContext* cx, uintN argc, jsval* vp);
|
||||||
|
};
|
||||||
|
|
||||||
|
class CData {
|
||||||
|
public:
|
||||||
|
static JSObject* Create(JSContext* cx, JSObject* type, JSObject* base, void* data);
|
||||||
|
static void Finalize(JSContext* cx, JSObject* obj);
|
||||||
|
|
||||||
|
static JSObject* GetCType(JSContext* cx, JSObject* dataObj);
|
||||||
|
static void* GetData(JSContext* cx, JSObject* dataObj);
|
||||||
|
static bool IsCData(JSContext* cx, JSObject* obj);
|
||||||
|
|
||||||
|
static JSBool ValueGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp);
|
||||||
|
static JSBool ValueSetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp);
|
||||||
|
static JSBool Address(JSContext* cx, uintN argc, jsval* vp);
|
||||||
|
static JSBool Cast(JSContext* cx, uintN argc, jsval* vp);
|
||||||
|
static JSBool ReadString(JSContext* cx, uintN argc, jsval* vp);
|
||||||
|
static JSBool ToSource(JSContext* cx, uintN argc, jsval* vp);
|
||||||
|
};
|
||||||
|
|
||||||
|
class Int64Base {
|
||||||
|
public:
|
||||||
|
static JSObject* Construct(JSContext* cx, JSObject* proto, PRUint64 data, bool isUnsigned);
|
||||||
|
static void Finalize(JSContext* cx, JSObject* obj);
|
||||||
|
|
||||||
|
static PRUint64 GetInt(JSContext* cx, JSObject* obj);
|
||||||
|
|
||||||
|
static JSBool ToString(JSContext* cx, JSObject* obj, uintN argc, jsval* vp, bool isUnsigned);
|
||||||
|
static JSBool ToSource(JSContext* cx, JSObject* obj, uintN argc, jsval* vp, bool isUnsigned);
|
||||||
|
};
|
||||||
|
|
||||||
|
class Int64 : public Int64Base {
|
||||||
|
public:
|
||||||
|
static JSBool Construct(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval);
|
||||||
|
|
||||||
|
static bool IsInt64(JSContext* cx, JSObject* obj);
|
||||||
|
|
||||||
|
static JSBool ToString(JSContext* cx, uintN argc, jsval* vp);
|
||||||
|
static JSBool ToSource(JSContext* cx, uintN argc, jsval* vp);
|
||||||
|
|
||||||
|
// ctypes.Int64 static functions
|
||||||
|
static JSBool Compare(JSContext* cx, uintN argc, jsval* vp);
|
||||||
|
static JSBool Lo(JSContext* cx, uintN argc, jsval* vp);
|
||||||
|
static JSBool Hi(JSContext* cx, uintN argc, jsval* vp);
|
||||||
|
static JSBool Join(JSContext* cx, uintN argc, jsval* vp);
|
||||||
|
};
|
||||||
|
|
||||||
|
class UInt64 : public Int64Base {
|
||||||
|
public:
|
||||||
|
static JSBool Construct(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval);
|
||||||
|
|
||||||
|
static bool IsUInt64(JSContext* cx, JSObject* obj);
|
||||||
|
|
||||||
|
static JSBool ToString(JSContext* cx, uintN argc, jsval* vp);
|
||||||
|
static JSBool ToSource(JSContext* cx, uintN argc, jsval* vp);
|
||||||
|
|
||||||
|
// ctypes.UInt64 static functions
|
||||||
|
static JSBool Compare(JSContext* cx, uintN argc, jsval* vp);
|
||||||
|
static JSBool Lo(JSContext* cx, uintN argc, jsval* vp);
|
||||||
|
static JSBool Hi(JSContext* cx, uintN argc, jsval* vp);
|
||||||
|
static JSBool Join(JSContext* cx, uintN argc, jsval* vp);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -50,439 +50,101 @@ namespace ctypes {
|
|||||||
** Static helpers
|
** Static helpers
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
template<class IntegerType>
|
|
||||||
static IntegerType
|
|
||||||
Convert(jsdouble d)
|
|
||||||
{
|
|
||||||
return IntegerType(d);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
// MSVC can't perform double to unsigned __int64 conversion when the
|
|
||||||
// double is greater than 2^63 - 1. Help it along a little.
|
|
||||||
template<>
|
|
||||||
static PRUint64
|
|
||||||
Convert<PRUint64>(jsdouble d)
|
|
||||||
{
|
|
||||||
return d > 0x7fffffffffffffffui64 ?
|
|
||||||
PRUint64(d - 0x8000000000000000ui64) + 0x8000000000000000ui64 :
|
|
||||||
PRUint64(d);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template<class IntegerType>
|
|
||||||
static bool
|
|
||||||
jsvalToIntStrict(jsval aValue, IntegerType *aResult)
|
|
||||||
{
|
|
||||||
if (JSVAL_IS_INT(aValue)) {
|
|
||||||
jsint i = JSVAL_TO_INT(aValue);
|
|
||||||
*aResult = IntegerType(i);
|
|
||||||
|
|
||||||
// Make sure the integer fits in the alotted precision, and has the right sign.
|
|
||||||
return jsint(*aResult) == i &&
|
|
||||||
(i < 0) == (*aResult < 0);
|
|
||||||
}
|
|
||||||
if (JSVAL_IS_DOUBLE(aValue)) {
|
|
||||||
jsdouble d = *JSVAL_TO_DOUBLE(aValue);
|
|
||||||
*aResult = Convert<IntegerType>(d);
|
|
||||||
|
|
||||||
// Don't silently lose bits here -- check that aValue really is an
|
|
||||||
// integer value, and has the right sign.
|
|
||||||
return jsdouble(*aResult) == d &&
|
|
||||||
(d < 0) == (*aResult < 0);
|
|
||||||
}
|
|
||||||
if (JSVAL_IS_BOOLEAN(aValue)) {
|
|
||||||
// Implicitly promote boolean values to 0 or 1, like C.
|
|
||||||
*aResult = JSVAL_TO_BOOLEAN(aValue);
|
|
||||||
NS_ASSERTION(*aResult == 0 || *aResult == 1, "invalid boolean");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// Don't silently convert null to an integer. It's probably a mistake.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
jsvalToDoubleStrict(jsval aValue, jsdouble *dp)
|
|
||||||
{
|
|
||||||
// Don't silently convert true to 1.0 or false to 0.0, even though C/C++
|
|
||||||
// does it. It's likely to be a mistake.
|
|
||||||
if (JSVAL_IS_INT(aValue)) {
|
|
||||||
*dp = JSVAL_TO_INT(aValue);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (JSVAL_IS_DOUBLE(aValue)) {
|
|
||||||
*dp = *JSVAL_TO_DOUBLE(aValue);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSErrorFormatString ErrorFormatString[CTYPESERR_LIMIT] = {
|
|
||||||
#define MSG_DEF(name, number, count, exception, format) \
|
|
||||||
{ format, count, exception } ,
|
|
||||||
#include "ctypes.msg"
|
|
||||||
#undef MSG_DEF
|
|
||||||
};
|
|
||||||
|
|
||||||
const JSErrorFormatString*
|
|
||||||
GetErrorMessage(void* userRef, const char* locale, const uintN errorNumber)
|
|
||||||
{
|
|
||||||
if (0 < errorNumber && errorNumber < CTYPESERR_LIMIT)
|
|
||||||
return &ErrorFormatString[errorNumber];
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char*
|
|
||||||
ToSource(JSContext* cx, jsval vp)
|
|
||||||
{
|
|
||||||
JSString* str = JS_ValueToSource(cx, vp);
|
|
||||||
if (str)
|
|
||||||
return JS_GetStringBytes(str);
|
|
||||||
|
|
||||||
JS_ClearPendingException(cx);
|
|
||||||
return "<<error converting value to string>>";
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
TypeError(JSContext* cx, const char* expected, jsval actual)
|
|
||||||
{
|
|
||||||
const char* src = ToSource(cx, actual);
|
|
||||||
JS_ReportErrorNumber(cx, GetErrorMessage, NULL,
|
|
||||||
CTYPESMSG_TYPE_ERROR, expected, src);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
GetABI(JSContext* cx, jsval aCallType, ffi_abi& aResult)
|
GetABI(JSContext* cx, jsval aCallType, ffi_abi& aResult)
|
||||||
{
|
{
|
||||||
ABICode abi = Module::GetABICode(cx, aCallType);
|
if (!JSVAL_IS_OBJECT(aCallType) || JSVAL_IS_NULL(aCallType))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ABICode abi = GetABICode(cx, JSVAL_TO_OBJECT(aCallType));
|
||||||
|
|
||||||
// determine the ABI from the subset of those available on the
|
// determine the ABI from the subset of those available on the
|
||||||
// given platform. TYPE_DEFAULT specifies the default
|
// given platform. ABI_DEFAULT specifies the default
|
||||||
// C calling convention (cdecl) on each platform.
|
// C calling convention (cdecl) on each platform.
|
||||||
switch (abi) {
|
switch (abi) {
|
||||||
case ABI_default_abi:
|
case ABI_DEFAULT:
|
||||||
aResult = FFI_DEFAULT_ABI;
|
aResult = FFI_DEFAULT_ABI;
|
||||||
return true;
|
return true;
|
||||||
|
case ABI_STDCALL:
|
||||||
#if (defined(_WIN32) && !defined(_WIN64)) || defined(_OS2)
|
#if (defined(_WIN32) && !defined(_WIN64)) || defined(_OS2)
|
||||||
case ABI_stdcall_abi:
|
|
||||||
aResult = FFI_STDCALL;
|
aResult = FFI_STDCALL;
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
default:
|
case INVALID_ABI:
|
||||||
return false;
|
break;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
PrepareType(JSContext* aContext, jsval aType, Type& aResult)
|
PrepareType(JSContext* aContext, jsval aType, Type& aResult)
|
||||||
{
|
{
|
||||||
aResult.mType = Module::GetTypeCode(aContext, aType);
|
if (!JSVAL_IS_OBJECT(aType) ||
|
||||||
|
JSVAL_IS_NULL(aType) ||
|
||||||
switch (aResult.mType) {
|
!CType::IsCType(aContext, JSVAL_TO_OBJECT(aType))) {
|
||||||
case TYPE_void_t:
|
JS_ReportError(aContext, "not a ctypes type");
|
||||||
aResult.mFFIType = ffi_type_void;
|
|
||||||
break;
|
|
||||||
case TYPE_int8_t:
|
|
||||||
aResult.mFFIType = ffi_type_sint8;
|
|
||||||
break;
|
|
||||||
case TYPE_int16_t:
|
|
||||||
aResult.mFFIType = ffi_type_sint16;
|
|
||||||
break;
|
|
||||||
case TYPE_int32_t:
|
|
||||||
aResult.mFFIType = ffi_type_sint32;
|
|
||||||
break;
|
|
||||||
case TYPE_int64_t:
|
|
||||||
aResult.mFFIType = ffi_type_sint64;
|
|
||||||
break;
|
|
||||||
case TYPE_bool:
|
|
||||||
case TYPE_uint8_t:
|
|
||||||
aResult.mFFIType = ffi_type_uint8;
|
|
||||||
break;
|
|
||||||
case TYPE_uint16_t:
|
|
||||||
aResult.mFFIType = ffi_type_uint16;
|
|
||||||
break;
|
|
||||||
case TYPE_uint32_t:
|
|
||||||
aResult.mFFIType = ffi_type_uint32;
|
|
||||||
break;
|
|
||||||
case TYPE_uint64_t:
|
|
||||||
aResult.mFFIType = ffi_type_uint64;
|
|
||||||
break;
|
|
||||||
case TYPE_float:
|
|
||||||
aResult.mFFIType = ffi_type_float;
|
|
||||||
break;
|
|
||||||
case TYPE_double:
|
|
||||||
aResult.mFFIType = ffi_type_double;
|
|
||||||
break;
|
|
||||||
case TYPE_string:
|
|
||||||
case TYPE_ustring:
|
|
||||||
aResult.mFFIType = ffi_type_pointer;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
JS_ReportError(aContext, "Invalid type specification");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JSObject* typeObj = JSVAL_TO_OBJECT(aType);
|
||||||
|
TypeCode typeCode = CType::GetTypeCode(aContext, typeObj);
|
||||||
|
|
||||||
|
if (typeCode == TYPE_array) {
|
||||||
|
// convert array argument types to pointers, just like C.
|
||||||
|
// ImplicitConvert will do the same, when passing an array as data.
|
||||||
|
JSObject* baseType = ArrayType::GetBaseType(aContext, typeObj);
|
||||||
|
typeObj = PointerType::CreateInternal(aContext, NULL, baseType, NULL);
|
||||||
|
if (!typeObj) {
|
||||||
|
JS_ReportError(aContext, "couldn't create pointer type from array");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (typeCode == TYPE_void_t) {
|
||||||
|
// disallow void argument types
|
||||||
|
JS_ReportError(aContext, "Cannot have void argument type");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// libffi cannot pass types of zero size by value.
|
||||||
|
JS_ASSERT(CType::GetSize(aContext, typeObj) != 0);
|
||||||
|
|
||||||
|
aResult.mType = typeObj;
|
||||||
|
aResult.mFFIType = *CType::GetFFIType(aContext, typeObj);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
PrepareValue(JSContext* aContext, const Type& aType, jsval aValue, Value& aResult)
|
PrepareResultType(JSContext* aContext, jsval aType, Type& aResult)
|
||||||
{
|
{
|
||||||
jsdouble d;
|
if (!JSVAL_IS_OBJECT(aType) ||
|
||||||
|
JSVAL_IS_NULL(aType) ||
|
||||||
switch (aType.mType) {
|
!CType::IsCType(aContext, JSVAL_TO_OBJECT(aType))) {
|
||||||
case TYPE_bool:
|
JS_ReportError(aContext, "not a ctypes type");
|
||||||
// Do not implicitly lose bits, but allow the values 0, 1, and -0.
|
|
||||||
// Programs can convert explicitly, if needed, using `Boolean(v)` or `!!v`.
|
|
||||||
if (!jsvalToIntStrict(aValue, &aResult.mValue.mUint8) ||
|
|
||||||
aResult.mValue.mUint8 > 1)
|
|
||||||
return TypeError(aContext, "boolean", aValue);
|
|
||||||
|
|
||||||
aResult.mData = &aResult.mValue.mUint8;
|
|
||||||
break;
|
|
||||||
case TYPE_int8_t:
|
|
||||||
// Do not implicitly lose bits.
|
|
||||||
if (!jsvalToIntStrict(aValue, &aResult.mValue.mInt8))
|
|
||||||
return TypeError(aContext, "int8", aValue);
|
|
||||||
|
|
||||||
aResult.mData = &aResult.mValue.mInt8;
|
|
||||||
break;
|
|
||||||
case TYPE_int16_t:
|
|
||||||
// Do not implicitly lose bits.
|
|
||||||
if (!jsvalToIntStrict(aValue, &aResult.mValue.mInt16))
|
|
||||||
return TypeError(aContext, "int16", aValue);
|
|
||||||
|
|
||||||
aResult.mData = &aResult.mValue.mInt16;
|
|
||||||
break;
|
|
||||||
case TYPE_int32_t:
|
|
||||||
// Do not implicitly lose bits.
|
|
||||||
if (!jsvalToIntStrict(aValue, &aResult.mValue.mInt32))
|
|
||||||
return TypeError(aContext, "int32", aValue);
|
|
||||||
|
|
||||||
aResult.mData = &aResult.mValue.mInt32;
|
|
||||||
break;
|
|
||||||
case TYPE_int64_t:
|
|
||||||
// Do not implicitly lose bits.
|
|
||||||
if (!jsvalToIntStrict(aValue, &aResult.mValue.mInt64))
|
|
||||||
return TypeError(aContext, "int64", aValue);
|
|
||||||
|
|
||||||
aResult.mData = &aResult.mValue.mInt64;
|
|
||||||
break;
|
|
||||||
case TYPE_uint8_t:
|
|
||||||
// Do not implicitly lose bits.
|
|
||||||
if (!jsvalToIntStrict(aValue, &aResult.mValue.mUint8))
|
|
||||||
return TypeError(aContext, "uint8", aValue);
|
|
||||||
|
|
||||||
aResult.mData = &aResult.mValue.mUint8;
|
|
||||||
break;
|
|
||||||
case TYPE_uint16_t:
|
|
||||||
// Do not implicitly lose bits.
|
|
||||||
if (!jsvalToIntStrict(aValue, &aResult.mValue.mUint16))
|
|
||||||
return TypeError(aContext, "uint16", aValue);
|
|
||||||
|
|
||||||
aResult.mData = &aResult.mValue.mUint16;
|
|
||||||
break;
|
|
||||||
case TYPE_uint32_t:
|
|
||||||
// Do not implicitly lose bits.
|
|
||||||
if (!jsvalToIntStrict(aValue, &aResult.mValue.mUint32))
|
|
||||||
return TypeError(aContext, "uint32", aValue);
|
|
||||||
|
|
||||||
aResult.mData = &aResult.mValue.mUint32;
|
|
||||||
break;
|
|
||||||
case TYPE_uint64_t:
|
|
||||||
// Do not implicitly lose bits.
|
|
||||||
if (!jsvalToIntStrict(aValue, &aResult.mValue.mUint64))
|
|
||||||
return TypeError(aContext, "uint64", aValue);
|
|
||||||
|
|
||||||
aResult.mData = &aResult.mValue.mUint64;
|
|
||||||
break;
|
|
||||||
case TYPE_float:
|
|
||||||
if (!jsvalToDoubleStrict(aValue, &d))
|
|
||||||
return TypeError(aContext, "float", aValue);
|
|
||||||
|
|
||||||
// The following cast silently throws away some bits, but there's
|
|
||||||
// no good way around it. Sternly requiring that the 64-bit double
|
|
||||||
// argument be exactly representable as a 32-bit float is
|
|
||||||
// unrealistic: it would allow 1/2 to pass but not 1/3.
|
|
||||||
aResult.mValue.mFloat = float(d);
|
|
||||||
aResult.mData = &aResult.mValue.mFloat;
|
|
||||||
break;
|
|
||||||
case TYPE_double:
|
|
||||||
if (!jsvalToDoubleStrict(aValue, &d))
|
|
||||||
return TypeError(aContext, "double", aValue);
|
|
||||||
|
|
||||||
aResult.mValue.mDouble = d;
|
|
||||||
aResult.mData = &aResult.mValue.mDouble;
|
|
||||||
break;
|
|
||||||
case TYPE_string:
|
|
||||||
if (JSVAL_IS_NULL(aValue)) {
|
|
||||||
// Allow passing a null pointer.
|
|
||||||
aResult.mValue.mPointer = nsnull;
|
|
||||||
} else if (JSVAL_IS_STRING(aValue)) {
|
|
||||||
aResult.mValue.mPointer = JS_GetStringBytes(JSVAL_TO_STRING(aValue));
|
|
||||||
} else {
|
|
||||||
// Don't implicitly convert to string. Users can implicitly convert
|
|
||||||
// with `String(x)` or `""+x`.
|
|
||||||
return TypeError(aContext, "string", aValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
aResult.mData = &aResult.mValue.mPointer;
|
|
||||||
break;
|
|
||||||
case TYPE_ustring:
|
|
||||||
if (JSVAL_IS_NULL(aValue)) {
|
|
||||||
// Allow passing a null pointer.
|
|
||||||
aResult.mValue.mPointer = nsnull;
|
|
||||||
} else if (JSVAL_IS_STRING(aValue)) {
|
|
||||||
aResult.mValue.mPointer = JS_GetStringChars(JSVAL_TO_STRING(aValue));
|
|
||||||
} else {
|
|
||||||
// Don't implicitly convert to string. Users can implicitly convert
|
|
||||||
// with `String(x)` or `""+x`.
|
|
||||||
return TypeError(aContext, "ustring", aValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
aResult.mData = &aResult.mValue.mPointer;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
NS_NOTREACHED("invalid type");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
JSObject* typeObj = JSVAL_TO_OBJECT(aType);
|
||||||
}
|
TypeCode typeCode = CType::GetTypeCode(aContext, typeObj);
|
||||||
|
|
||||||
static void
|
// Arrays can never be return types.
|
||||||
PrepareReturnValue(const Type& aType, Value& aResult)
|
if (typeCode == TYPE_array) {
|
||||||
{
|
JS_ReportError(aContext, "Result type cannot be an array");
|
||||||
switch (aType.mType) {
|
|
||||||
case TYPE_void_t:
|
|
||||||
aResult.mData = nsnull;
|
|
||||||
break;
|
|
||||||
case TYPE_int8_t:
|
|
||||||
aResult.mData = &aResult.mValue.mInt8;
|
|
||||||
break;
|
|
||||||
case TYPE_int16_t:
|
|
||||||
aResult.mData = &aResult.mValue.mInt16;
|
|
||||||
break;
|
|
||||||
case TYPE_int32_t:
|
|
||||||
aResult.mData = &aResult.mValue.mInt32;
|
|
||||||
break;
|
|
||||||
case TYPE_int64_t:
|
|
||||||
aResult.mData = &aResult.mValue.mInt64;
|
|
||||||
break;
|
|
||||||
case TYPE_bool:
|
|
||||||
case TYPE_uint8_t:
|
|
||||||
aResult.mData = &aResult.mValue.mUint8;
|
|
||||||
break;
|
|
||||||
case TYPE_uint16_t:
|
|
||||||
aResult.mData = &aResult.mValue.mUint16;
|
|
||||||
break;
|
|
||||||
case TYPE_uint32_t:
|
|
||||||
aResult.mData = &aResult.mValue.mUint32;
|
|
||||||
break;
|
|
||||||
case TYPE_uint64_t:
|
|
||||||
aResult.mData = &aResult.mValue.mUint64;
|
|
||||||
break;
|
|
||||||
case TYPE_float:
|
|
||||||
aResult.mData = &aResult.mValue.mFloat;
|
|
||||||
break;
|
|
||||||
case TYPE_double:
|
|
||||||
aResult.mData = &aResult.mValue.mDouble;
|
|
||||||
break;
|
|
||||||
case TYPE_string:
|
|
||||||
case TYPE_ustring:
|
|
||||||
aResult.mData = &aResult.mValue.mPointer;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
NS_NOTREACHED("invalid type");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
ConvertReturnValue(JSContext* aContext,
|
|
||||||
const Type& aResultType,
|
|
||||||
const Value& aResultValue,
|
|
||||||
jsval* aValue)
|
|
||||||
{
|
|
||||||
switch (aResultType.mType) {
|
|
||||||
case TYPE_void_t:
|
|
||||||
*aValue = JSVAL_VOID;
|
|
||||||
break;
|
|
||||||
case TYPE_bool:
|
|
||||||
*aValue = aResultValue.mValue.mUint8 ? JSVAL_TRUE : JSVAL_FALSE;
|
|
||||||
break;
|
|
||||||
case TYPE_int8_t:
|
|
||||||
*aValue = INT_TO_JSVAL(aResultValue.mValue.mInt8);
|
|
||||||
break;
|
|
||||||
case TYPE_int16_t:
|
|
||||||
*aValue = INT_TO_JSVAL(aResultValue.mValue.mInt16);
|
|
||||||
break;
|
|
||||||
case TYPE_int32_t:
|
|
||||||
if (!JS_NewNumberValue(aContext, jsdouble(aResultValue.mValue.mInt32), aValue))
|
|
||||||
return false;
|
|
||||||
break;
|
|
||||||
case TYPE_int64_t:
|
|
||||||
// Implicit conversion with loss of bits. :-[
|
|
||||||
if (!JS_NewNumberValue(aContext, jsdouble(aResultValue.mValue.mInt64), aValue))
|
|
||||||
return false;
|
|
||||||
break;
|
|
||||||
case TYPE_uint8_t:
|
|
||||||
*aValue = INT_TO_JSVAL(aResultValue.mValue.mUint8);
|
|
||||||
break;
|
|
||||||
case TYPE_uint16_t:
|
|
||||||
*aValue = INT_TO_JSVAL(aResultValue.mValue.mUint16);
|
|
||||||
break;
|
|
||||||
case TYPE_uint32_t:
|
|
||||||
if (!JS_NewNumberValue(aContext, jsdouble(aResultValue.mValue.mUint32), aValue))
|
|
||||||
return false;
|
|
||||||
break;
|
|
||||||
case TYPE_uint64_t:
|
|
||||||
// Implicit conversion with loss of bits. :-[
|
|
||||||
if (!JS_NewNumberValue(aContext, jsdouble(aResultValue.mValue.mUint64), aValue))
|
|
||||||
return false;
|
|
||||||
break;
|
|
||||||
case TYPE_float:
|
|
||||||
if (!JS_NewNumberValue(aContext, jsdouble(aResultValue.mValue.mFloat), aValue))
|
|
||||||
return false;
|
|
||||||
break;
|
|
||||||
case TYPE_double:
|
|
||||||
if (!JS_NewNumberValue(aContext, jsdouble(aResultValue.mValue.mDouble), aValue))
|
|
||||||
return false;
|
|
||||||
break;
|
|
||||||
case TYPE_string: {
|
|
||||||
if (!aResultValue.mValue.mPointer) {
|
|
||||||
// Allow returning a null pointer.
|
|
||||||
*aValue = JSVAL_NULL;
|
|
||||||
} else {
|
|
||||||
JSString *jsstring = JS_NewStringCopyZ(aContext,
|
|
||||||
reinterpret_cast<const char*>(aResultValue.mValue.mPointer));
|
|
||||||
if (!jsstring)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
*aValue = STRING_TO_JSVAL(jsstring);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case TYPE_ustring: {
|
|
||||||
if (!aResultValue.mValue.mPointer) {
|
|
||||||
// Allow returning a null pointer.
|
|
||||||
*aValue = JSVAL_NULL;
|
|
||||||
} else {
|
|
||||||
JSString *jsstring = JS_NewUCStringCopyZ(aContext,
|
|
||||||
reinterpret_cast<const jschar*>(aResultValue.mValue.mPointer));
|
|
||||||
if (!jsstring)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
*aValue = STRING_TO_JSVAL(jsstring);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
NS_NOTREACHED("invalid type");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
// Our libffi_msvc fork doesn't support returning structs by value yet.
|
||||||
|
if (typeCode == TYPE_struct) {
|
||||||
|
JS_ReportError(aContext,
|
||||||
|
"Returning structs by value is unsupported on Windows");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// libffi cannot pass types of zero size by value.
|
||||||
|
JS_ASSERT(typeCode == TYPE_void_t || CType::GetSize(aContext, typeObj) != 0);
|
||||||
|
|
||||||
|
aResult.mType = typeObj;
|
||||||
|
aResult.mFFIType = *CType::GetFFIType(aContext, typeObj);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -516,7 +178,7 @@ Function::Init(JSContext* aContext,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// prepare the result type
|
// prepare the result type
|
||||||
if (!PrepareType(aContext, aResultType, mResultType))
|
if (!PrepareResultType(aContext, aResultType, mResultType))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// prepare the argument types
|
// prepare the argument types
|
||||||
@ -525,12 +187,6 @@ Function::Init(JSContext* aContext,
|
|||||||
if (!PrepareType(aContext, aArgTypes[i], *mArgTypes.AppendElement()))
|
if (!PrepareType(aContext, aArgTypes[i], *mArgTypes.AppendElement()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// disallow void argument types
|
|
||||||
if (mArgTypes[i].mType == TYPE_void_t) {
|
|
||||||
JS_ReportError(aContext, "Cannot have void argument type");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ffi_prep_cif requires an array of ffi_types; prepare it separately.
|
// ffi_prep_cif requires an array of ffi_types; prepare it separately.
|
||||||
mFFITypes.AppendElement(&mArgTypes[i].mFFIType);
|
mFFITypes.AppendElement(&mArgTypes[i].mFFIType);
|
||||||
}
|
}
|
||||||
@ -561,39 +217,63 @@ Function::Execute(JSContext* cx, PRUint32 argc, jsval* vp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// prepare the values for each argument
|
// prepare the values for each argument
|
||||||
nsAutoTArray<Value, 16> values;
|
nsAutoTArray<AutoValue, 16> values;
|
||||||
|
nsAutoTArray<AutoValue, 16> strings;
|
||||||
for (PRUint32 i = 0; i < mArgTypes.Length(); ++i) {
|
for (PRUint32 i = 0; i < mArgTypes.Length(); ++i) {
|
||||||
if (!PrepareValue(cx, mArgTypes[i], JS_ARGV(cx, vp)[i], *values.AppendElement()))
|
AutoValue& value = *values.AppendElement();
|
||||||
|
jsval arg = JS_ARGV(cx, vp)[i];
|
||||||
|
bool freePointer = false;
|
||||||
|
if (!value.SizeToType(cx, mArgTypes[i].mType)) {
|
||||||
|
JS_ReportAllocationOverflow(cx);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create an array of pointers to each value, for passing to ffi_call
|
if (!ImplicitConvert(cx, arg, mArgTypes[i].mType, value.mData, true, &freePointer))
|
||||||
nsAutoTArray<void*, 16> ffiValues;
|
return false;
|
||||||
for (PRUint32 i = 0; i < mArgTypes.Length(); ++i) {
|
|
||||||
ffiValues.AppendElement(values[i].mData);
|
if (freePointer) {
|
||||||
|
// ImplicitConvert converted a string for us, which we have to free.
|
||||||
|
// Keep track of it.
|
||||||
|
strings.AppendElement()->mData = *static_cast<char**>(value.mData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize a pointer to an appropriate location, for storing the result
|
// initialize a pointer to an appropriate location, for storing the result
|
||||||
Value resultValue;
|
AutoValue resultValue;
|
||||||
PrepareReturnValue(mResultType, resultValue);
|
if (CType::GetTypeCode(cx, mResultType.mType) != TYPE_void_t &&
|
||||||
|
!resultValue.SizeToType(cx, mResultType.mType)) {
|
||||||
|
JS_ReportAllocationOverflow(cx);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// suspend the request before we call into the function, since the call
|
// suspend the request before we call into the function, since the call
|
||||||
// may block or otherwise take a long time to return.
|
// may block or otherwise take a long time to return.
|
||||||
jsrefcount rc = JS_SuspendRequest(cx);
|
jsrefcount rc = JS_SuspendRequest(cx);
|
||||||
|
|
||||||
ffi_call(&mCIF, FFI_FN(mFunc), resultValue.mData, ffiValues.Elements());
|
ffi_call(&mCIF, FFI_FN(mFunc), resultValue.mData, reinterpret_cast<void**>(values.Elements()));
|
||||||
|
|
||||||
JS_ResumeRequest(cx, rc);
|
JS_ResumeRequest(cx, rc);
|
||||||
|
|
||||||
// prepare a JS object from the result
|
// prepare a JS object from the result
|
||||||
jsval rval;
|
jsval rval;
|
||||||
if (!ConvertReturnValue(cx, mResultType, resultValue, &rval))
|
if (!ConvertToJS(cx, mResultType.mType, NULL, resultValue.mData, false, &rval))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
JS_SET_RVAL(cx, vp, rval);
|
JS_SET_RVAL(cx, vp, rval);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Function::Trace(JSTracer *trc)
|
||||||
|
{
|
||||||
|
// Identify the result CType to the tracer.
|
||||||
|
JS_CALL_TRACER(trc, mResultType.mType, JSTRACE_OBJECT, "CType");
|
||||||
|
|
||||||
|
// Identify each argument CType to the tracer.
|
||||||
|
for (PRUint32 i = 0; i < mArgTypes.Length(); ++i)
|
||||||
|
JS_CALL_TRACER(trc, mArgTypes[i].mType, JSTRACE_OBJECT, "CType");
|
||||||
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** JSObject implementation
|
** JSObject implementation
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@ -627,15 +307,16 @@ Function::Create(JSContext* aContext,
|
|||||||
JSAutoTempValueRooter fnRoot(aContext, fnObj);
|
JSAutoTempValueRooter fnRoot(aContext, fnObj);
|
||||||
|
|
||||||
// stash a pointer to self, which Function::Call will need at call time
|
// stash a pointer to self, which Function::Call will need at call time
|
||||||
if (!JS_SetReservedSlot(aContext, fnObj, 0, PRIVATE_TO_JSVAL(self.get())))
|
if (!JS_SetReservedSlot(aContext, fnObj, SLOT_FUNCTION, PRIVATE_TO_JSVAL(self.get())))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
// make a strong reference to the library for GC-safety
|
// make a strong reference to the library for GC-safety
|
||||||
if (!JS_SetReservedSlot(aContext, fnObj, 1, OBJECT_TO_JSVAL(aLibrary)))
|
if (!JS_SetReservedSlot(aContext, fnObj, SLOT_LIBRARYOBJ, OBJECT_TO_JSVAL(aLibrary)))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
// tell the library we exist, so it can delete our Function instance
|
// Tell the library we exist, so it can (a) identify our CTypes to the tracer
|
||||||
// when it comes time to finalize. (JS functions don't have finalizers.)
|
// and (b) delete our Function instance when it comes time to finalize.
|
||||||
|
// (JS functions don't have finalizers.)
|
||||||
if (!Library::AddFunction(aContext, aLibrary, self))
|
if (!Library::AddFunction(aContext, aLibrary, self))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@ -647,7 +328,7 @@ static Function*
|
|||||||
GetFunction(JSContext* cx, JSObject* obj)
|
GetFunction(JSContext* cx, JSObject* obj)
|
||||||
{
|
{
|
||||||
jsval slot;
|
jsval slot;
|
||||||
JS_GetReservedSlot(cx, obj, 0, &slot);
|
JS_GetReservedSlot(cx, obj, SLOT_FUNCTION, &slot);
|
||||||
return static_cast<Function*>(JSVAL_TO_PRIVATE(slot));
|
return static_cast<Function*>(JSVAL_TO_PRIVATE(slot));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -657,7 +338,7 @@ Function::Call(JSContext* cx, uintN argc, jsval* vp)
|
|||||||
JSObject* callee = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp));
|
JSObject* callee = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp));
|
||||||
|
|
||||||
jsval slot;
|
jsval slot;
|
||||||
JS_GetReservedSlot(cx, callee, 1, &slot);
|
JS_GetReservedSlot(cx, callee, SLOT_LIBRARYOBJ, &slot);
|
||||||
|
|
||||||
PRLibrary* library = Library::GetLibrary(cx, JSVAL_TO_OBJECT(slot));
|
PRLibrary* library = Library::GetLibrary(cx, JSVAL_TO_OBJECT(slot));
|
||||||
if (!library) {
|
if (!library) {
|
||||||
|
@ -40,48 +40,45 @@
|
|||||||
#ifndef FUNCTION_H
|
#ifndef FUNCTION_H
|
||||||
#define FUNCTION_H
|
#define FUNCTION_H
|
||||||
|
|
||||||
#include "Module.h"
|
#include "CTypes.h"
|
||||||
#include "nsTArray.h"
|
#include "nsTArray.h"
|
||||||
#include "prlink.h"
|
#include "prlink.h"
|
||||||
#include "ffi.h"
|
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace ctypes {
|
namespace ctypes {
|
||||||
|
|
||||||
// for JS error reporting
|
enum FunctionSlot
|
||||||
enum ErrorNum {
|
{
|
||||||
#define MSG_DEF(name, number, count, exception, format) \
|
SLOT_FUNCTION = 0,
|
||||||
name = number,
|
SLOT_LIBRARYOBJ = 1
|
||||||
#include "ctypes.msg"
|
// JSFunction objects always get exactly two slots.
|
||||||
#undef MSG_DEF
|
|
||||||
CTYPESERR_LIMIT
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const JSErrorFormatString*
|
|
||||||
GetErrorMessage(void* userRef, const char* locale, const uintN errorNumber);
|
|
||||||
|
|
||||||
struct Type
|
struct Type
|
||||||
{
|
{
|
||||||
ffi_type mFFIType;
|
ffi_type mFFIType;
|
||||||
TypeCode mType;
|
JSObject* mType;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Value
|
struct AutoValue
|
||||||
{
|
{
|
||||||
|
AutoValue() : mData(NULL) { }
|
||||||
|
|
||||||
|
~AutoValue()
|
||||||
|
{
|
||||||
|
delete static_cast<char*>(mData);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SizeToType(JSContext* cx, JSObject* type)
|
||||||
|
{
|
||||||
|
size_t size = CType::GetSize(cx, type);
|
||||||
|
mData = new char[size];
|
||||||
|
if (mData)
|
||||||
|
memset(mData, 0, size);
|
||||||
|
return mData != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void* mData;
|
void* mData;
|
||||||
union {
|
|
||||||
PRInt8 mInt8;
|
|
||||||
PRInt16 mInt16;
|
|
||||||
PRInt32 mInt32;
|
|
||||||
PRInt64 mInt64;
|
|
||||||
PRUint8 mUint8;
|
|
||||||
PRUint16 mUint16;
|
|
||||||
PRUint32 mUint32;
|
|
||||||
PRUint64 mUint64;
|
|
||||||
float mFloat;
|
|
||||||
double mDouble;
|
|
||||||
void* mPointer;
|
|
||||||
} mValue;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Function
|
class Function
|
||||||
@ -90,6 +87,7 @@ public:
|
|||||||
Function();
|
Function();
|
||||||
|
|
||||||
Function*& Next() { return mNext; }
|
Function*& Next() { return mNext; }
|
||||||
|
void Trace(JSTracer *trc);
|
||||||
|
|
||||||
static JSObject* Create(JSContext* aContext, JSObject* aLibrary, PRFuncPtr aFunc, const char* aName, jsval aCallType, jsval aResultType, jsval* aArgTypes, uintN aArgLength);
|
static JSObject* Create(JSContext* aContext, JSObject* aLibrary, PRFuncPtr aFunc, const char* aName, jsval aCallType, jsval aResultType, jsval* aArgTypes, uintN aArgLength);
|
||||||
static JSBool Call(JSContext* cx, uintN argc, jsval* vp);
|
static JSBool Call(JSContext* cx, uintN argc, jsval* vp);
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
*
|
*
|
||||||
* ***** END LICENSE BLOCK ***** */
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
#include "jscntxt.h"
|
||||||
#include "Library.h"
|
#include "Library.h"
|
||||||
#include "Function.h"
|
#include "Function.h"
|
||||||
#include "nsServiceManagerUtils.h"
|
#include "nsServiceManagerUtils.h"
|
||||||
@ -55,15 +56,18 @@ namespace ctypes {
|
|||||||
|
|
||||||
static JSClass sLibraryClass = {
|
static JSClass sLibraryClass = {
|
||||||
"Library",
|
"Library",
|
||||||
JSCLASS_HAS_RESERVED_SLOTS(2),
|
JSCLASS_HAS_RESERVED_SLOTS(LIBRARY_SLOTS) | JSCLASS_MARK_IS_TRACE,
|
||||||
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
|
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
|
||||||
JS_EnumerateStub,JS_ResolveStub, JS_ConvertStub, Library::Finalize,
|
JS_EnumerateStub,JS_ResolveStub, JS_ConvertStub, Library::Finalize,
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
|
NULL, NULL, NULL, NULL, NULL, NULL, JS_CLASS_TRACE(Library::Trace), NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define CTYPESFN_FLAGS \
|
||||||
|
(JSFUN_FAST_NATIVE | JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)
|
||||||
|
|
||||||
static JSFunctionSpec sLibraryFunctions[] = {
|
static JSFunctionSpec sLibraryFunctions[] = {
|
||||||
JS_FN("close", Library::Close, 0, JSFUN_FAST_NATIVE | JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT),
|
JS_FN("close", Library::Close, 0, CTYPESFN_FLAGS),
|
||||||
JS_FN("declare", Library::Declare, 0, JSFUN_FAST_NATIVE | JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT),
|
JS_FN("declare", Library::Declare, 0, CTYPESFN_FLAGS),
|
||||||
JS_FS_END
|
JS_FS_END
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -73,13 +77,15 @@ Library::Create(JSContext* cx, jsval aPath)
|
|||||||
JSObject* libraryObj = JS_NewObject(cx, &sLibraryClass, NULL, NULL);
|
JSObject* libraryObj = JS_NewObject(cx, &sLibraryClass, NULL, NULL);
|
||||||
if (!libraryObj)
|
if (!libraryObj)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
JSAutoTempValueRooter root(cx, libraryObj);
|
||||||
|
|
||||||
// initialize the library
|
// initialize the library
|
||||||
if (!JS_SetReservedSlot(cx, libraryObj, 0, PRIVATE_TO_JSVAL(NULL)))
|
if (!JS_SetReservedSlot(cx, libraryObj, SLOT_LIBRARY, PRIVATE_TO_JSVAL(NULL)))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
// initialize our Function list to empty
|
// initialize our Function list to empty
|
||||||
if (!JS_SetReservedSlot(cx, libraryObj, 1, PRIVATE_TO_JSVAL(NULL)))
|
if (!JS_SetReservedSlot(cx, libraryObj, SLOT_FUNCTIONLIST,
|
||||||
|
PRIVATE_TO_JSVAL(NULL)))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
// attach API functions
|
// attach API functions
|
||||||
@ -92,21 +98,22 @@ Library::Create(JSContext* cx, jsval aPath)
|
|||||||
// get the path argument. we accept either an nsILocalFile or a string path.
|
// get the path argument. we accept either an nsILocalFile or a string path.
|
||||||
// determine which we have...
|
// determine which we have...
|
||||||
if (JSVAL_IS_STRING(aPath)) {
|
if (JSVAL_IS_STRING(aPath)) {
|
||||||
const jschar* path = JS_GetStringChars(JSVAL_TO_STRING(aPath));
|
const PRUnichar* path = reinterpret_cast<const PRUnichar*>(
|
||||||
|
JS_GetStringCharsZ(cx, JSVAL_TO_STRING(aPath)));
|
||||||
if (!path)
|
if (!path)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
// We don't use nsILocalFile.
|
// We don't use nsILocalFile, because it doesn't use the system search
|
||||||
// Because this interface doesn't resolve library path to use system search rule.
|
// rules when resolving library path.
|
||||||
PRLibSpec libSpec;
|
PRLibSpec libSpec;
|
||||||
#ifdef XP_WIN
|
#ifdef XP_WIN
|
||||||
// On Windows, converting to native charset may corrupt path string.
|
// On Windows, converting to native charset may corrupt path string.
|
||||||
// So, we have to use Unicode path directly.
|
// So, we have to use Unicode path directly.
|
||||||
libSpec.value.pathname_u = reinterpret_cast<const PRUnichar*>(path);
|
libSpec.value.pathname_u = path;
|
||||||
libSpec.type = PR_LibSpec_PathnameU;
|
libSpec.type = PR_LibSpec_PathnameU;
|
||||||
#else
|
#else
|
||||||
nsCAutoString nativePath;
|
nsCAutoString nativePath;
|
||||||
NS_CopyUnicodeToNative(nsDependentString(reinterpret_cast<const PRUnichar*>(path)), nativePath);
|
NS_CopyUnicodeToNative(nsDependentString(path), nativePath);
|
||||||
libSpec.value.pathname = nativePath.get();
|
libSpec.value.pathname = nativePath.get();
|
||||||
libSpec.type = PR_LibSpec_Pathname;
|
libSpec.type = PR_LibSpec_Pathname;
|
||||||
#endif
|
#endif
|
||||||
@ -132,7 +139,8 @@ Library::Create(JSContext* cx, jsval aPath)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// stash the library
|
// stash the library
|
||||||
if (!JS_SetReservedSlot(cx, libraryObj, 0, PRIVATE_TO_JSVAL(library)))
|
if (!JS_SetReservedSlot(cx, libraryObj, SLOT_LIBRARY,
|
||||||
|
PRIVATE_TO_JSVAL(library)))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return libraryObj;
|
return libraryObj;
|
||||||
@ -144,7 +152,7 @@ Library::GetLibrary(JSContext* cx, JSObject* obj)
|
|||||||
JS_ASSERT(JS_GET_CLASS(cx, obj) == &sLibraryClass);
|
JS_ASSERT(JS_GET_CLASS(cx, obj) == &sLibraryClass);
|
||||||
|
|
||||||
jsval slot;
|
jsval slot;
|
||||||
JS_GetReservedSlot(cx, obj, 0, &slot);
|
JS_GetReservedSlot(cx, obj, SLOT_LIBRARY, &slot);
|
||||||
return static_cast<PRLibrary*>(JSVAL_TO_PRIVATE(slot));
|
return static_cast<PRLibrary*>(JSVAL_TO_PRIVATE(slot));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,7 +162,7 @@ GetFunctionList(JSContext* cx, JSObject* obj)
|
|||||||
JS_ASSERT(JS_GET_CLASS(cx, obj) == &sLibraryClass);
|
JS_ASSERT(JS_GET_CLASS(cx, obj) == &sLibraryClass);
|
||||||
|
|
||||||
jsval slot;
|
jsval slot;
|
||||||
JS_GetReservedSlot(cx, obj, 1, &slot);
|
JS_GetReservedSlot(cx, obj, SLOT_FUNCTIONLIST, &slot);
|
||||||
return static_cast<Function*>(JSVAL_TO_PRIVATE(slot));
|
return static_cast<Function*>(JSVAL_TO_PRIVATE(slot));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,7 +171,20 @@ Library::AddFunction(JSContext* cx, JSObject* aLibrary, Function* aFunction)
|
|||||||
{
|
{
|
||||||
// add the new Function instance to the head of the list
|
// add the new Function instance to the head of the list
|
||||||
aFunction->Next() = GetFunctionList(cx, aLibrary);
|
aFunction->Next() = GetFunctionList(cx, aLibrary);
|
||||||
return JS_SetReservedSlot(cx, aLibrary, 1, PRIVATE_TO_JSVAL(aFunction));
|
return JS_SetReservedSlot(cx, aLibrary, SLOT_FUNCTIONLIST,
|
||||||
|
PRIVATE_TO_JSVAL(aFunction)) != JS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Library::Trace(JSTracer *trc, JSObject* obj)
|
||||||
|
{
|
||||||
|
// Walk the Function list and for each Function, identify each CType
|
||||||
|
// associated with it to the tracer.
|
||||||
|
Function* current = GetFunctionList(trc->context, obj);
|
||||||
|
while (current) {
|
||||||
|
current->Trace(trc);
|
||||||
|
current = current->Next();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -186,7 +207,7 @@ Library::Finalize(JSContext* cx, JSObject* obj)
|
|||||||
JSBool
|
JSBool
|
||||||
Library::Open(JSContext* cx, uintN argc, jsval *vp)
|
Library::Open(JSContext* cx, uintN argc, jsval *vp)
|
||||||
{
|
{
|
||||||
if (argc != 1) {
|
if (argc != 1 || JSVAL_IS_VOID(JS_ARGV(cx, vp)[0])) {
|
||||||
JS_ReportError(cx, "open requires a single argument");
|
JS_ReportError(cx, "open requires a single argument");
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
@ -217,8 +238,8 @@ Library::Close(JSContext* cx, uintN argc, jsval* vp)
|
|||||||
|
|
||||||
// delete our internal objects
|
// delete our internal objects
|
||||||
Finalize(cx, obj);
|
Finalize(cx, obj);
|
||||||
JS_SetReservedSlot(cx, obj, 0, PRIVATE_TO_JSVAL(NULL));
|
JS_SetReservedSlot(cx, obj, SLOT_LIBRARY, PRIVATE_TO_JSVAL(NULL));
|
||||||
JS_SetReservedSlot(cx, obj, 1, PRIVATE_TO_JSVAL(NULL));
|
JS_SetReservedSlot(cx, obj, SLOT_FUNCTIONLIST, PRIVATE_TO_JSVAL(NULL));
|
||||||
|
|
||||||
JS_SET_RVAL(cx, vp, JSVAL_VOID);
|
JS_SET_RVAL(cx, vp, JSVAL_VOID);
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
@ -251,14 +272,15 @@ Library::Declare(JSContext* cx, uintN argc, jsval* vp)
|
|||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* name = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]));
|
const char* name = JS_GetStringBytesZ(cx, JSVAL_TO_STRING(argv[0]));
|
||||||
PRFuncPtr func = PR_FindFunctionSymbol(library, name);
|
PRFuncPtr func = PR_FindFunctionSymbol(library, name);
|
||||||
if (!func) {
|
if (!func) {
|
||||||
JS_ReportError(cx, "couldn't find function symbol in library");
|
JS_ReportError(cx, "couldn't find function symbol in library");
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject* fn = Function::Create(cx, obj, func, name, argv[1], argv[2], &argv[3], argc - 3);
|
JSObject* fn = Function::Create(cx, obj, func, name, argv[1], argv[2],
|
||||||
|
&argv[3], argc - 3);
|
||||||
if (!fn)
|
if (!fn)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
|
@ -40,19 +40,24 @@
|
|||||||
#ifndef LIBRARY_H
|
#ifndef LIBRARY_H
|
||||||
#define LIBRARY_H
|
#define LIBRARY_H
|
||||||
|
|
||||||
#include "Function.h"
|
|
||||||
#include "jsapi.h"
|
|
||||||
|
|
||||||
struct PRLibrary;
|
struct PRLibrary;
|
||||||
class Function;
|
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace ctypes {
|
namespace ctypes {
|
||||||
|
|
||||||
|
class Function;
|
||||||
|
|
||||||
|
enum LibrarySlot {
|
||||||
|
SLOT_LIBRARY = 0,
|
||||||
|
SLOT_FUNCTIONLIST = 1,
|
||||||
|
LIBRARY_SLOTS
|
||||||
|
};
|
||||||
|
|
||||||
class Library
|
class Library
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static JSObject* Create(JSContext* cx, jsval aPath);
|
static JSObject* Create(JSContext* cx, jsval aPath);
|
||||||
|
static void Trace(JSTracer *trc, JSObject* obj);
|
||||||
static void Finalize(JSContext* cx, JSObject* obj);
|
static void Finalize(JSContext* cx, JSObject* obj);
|
||||||
|
|
||||||
static PRLibrary* GetLibrary(JSContext* cx, JSObject* obj);
|
static PRLibrary* GetLibrary(JSContext* cx, JSObject* obj);
|
||||||
|
@ -62,6 +62,7 @@ IS_COMPONENT = 1
|
|||||||
CPPSRCS = \
|
CPPSRCS = \
|
||||||
Function.cpp \
|
Function.cpp \
|
||||||
Library.cpp \
|
Library.cpp \
|
||||||
|
CTypes.cpp \
|
||||||
Module.cpp \
|
Module.cpp \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
|
|
||||||
#include "Module.h"
|
#include "Module.h"
|
||||||
#include "Library.h"
|
#include "Library.h"
|
||||||
|
#include "CTypes.h"
|
||||||
#include "nsIGenericFactory.h"
|
#include "nsIGenericFactory.h"
|
||||||
#include "nsMemory.h"
|
#include "nsMemory.h"
|
||||||
|
|
||||||
@ -83,74 +84,15 @@ Module::Call(nsIXPConnectWrappedNative* wrapper,
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSClass sCABIClass = {
|
#define CTYPESFN_FLAGS \
|
||||||
"CABI",
|
(JSFUN_FAST_NATIVE | JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)
|
||||||
JSCLASS_HAS_RESERVED_SLOTS(1),
|
|
||||||
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
|
|
||||||
JS_EnumerateStub,JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
static JSClass sCTypeClass = {
|
|
||||||
"CType",
|
|
||||||
JSCLASS_HAS_RESERVED_SLOTS(1),
|
|
||||||
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
|
|
||||||
JS_EnumerateStub,JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
static JSFunctionSpec sModuleFunctions[] = {
|
static JSFunctionSpec sModuleFunctions[] = {
|
||||||
JS_FN("open", Library::Open, 0, JSFUN_FAST_NATIVE | JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT),
|
JS_FN("open", Library::Open, 1, CTYPESFN_FLAGS),
|
||||||
|
JS_FN("cast", CData::Cast, 2, CTYPESFN_FLAGS),
|
||||||
JS_FS_END
|
JS_FS_END
|
||||||
};
|
};
|
||||||
|
|
||||||
ABICode
|
|
||||||
Module::GetABICode(JSContext* cx, jsval val)
|
|
||||||
{
|
|
||||||
// make sure we have an object representing a CABI class,
|
|
||||||
// and extract the enumerated class type from the reserved slot.
|
|
||||||
if (!JSVAL_IS_OBJECT(val))
|
|
||||||
return INVALID_ABI;
|
|
||||||
|
|
||||||
JSObject* obj = JSVAL_TO_OBJECT(val);
|
|
||||||
if (JS_GET_CLASS(cx, obj) != &sCABIClass)
|
|
||||||
return INVALID_ABI;
|
|
||||||
|
|
||||||
jsval result;
|
|
||||||
JS_GetReservedSlot(cx, obj, 0, &result);
|
|
||||||
|
|
||||||
return ABICode(JSVAL_TO_INT(result));
|
|
||||||
}
|
|
||||||
|
|
||||||
TypeCode
|
|
||||||
Module::GetTypeCode(JSContext* cx, jsval val)
|
|
||||||
{
|
|
||||||
// make sure we have an object representing a CType class,
|
|
||||||
// and extract the enumerated class type from the reserved slot.
|
|
||||||
if (!JSVAL_IS_OBJECT(val))
|
|
||||||
return INVALID_TYPE;
|
|
||||||
|
|
||||||
JSObject* obj = JSVAL_TO_OBJECT(val);
|
|
||||||
if (JS_GET_CLASS(cx, obj) != &sCTypeClass)
|
|
||||||
return INVALID_TYPE;
|
|
||||||
|
|
||||||
jsval result;
|
|
||||||
JS_GetReservedSlot(cx, obj, 0, &result);
|
|
||||||
|
|
||||||
return TypeCode(JSVAL_TO_INT(result));
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
DefineConstant(JSContext* cx, JSObject* parent, JSClass* clasp, const char* name, jsint code)
|
|
||||||
{
|
|
||||||
JSObject* obj = JS_DefineObject(cx, parent, name, clasp, NULL,
|
|
||||||
JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
|
|
||||||
if (!obj)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return JS_SetReservedSlot(cx, obj, 0, INT_TO_JSVAL(code));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Module::Init(JSContext* cx, JSObject* aGlobal)
|
Module::Init(JSContext* cx, JSObject* aGlobal)
|
||||||
{
|
{
|
||||||
@ -163,22 +105,16 @@ Module::Init(JSContext* cx, JSObject* aGlobal)
|
|||||||
NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
|
NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// attach classes representing ABI and type constants
|
if (!InitTypeClasses(cx, ctypes))
|
||||||
#define DEFINE_ABI(name) \
|
|
||||||
if (!DefineConstant(cx, ctypes, &sCABIClass, #name, ABI_##name)) \
|
|
||||||
return false;
|
return false;
|
||||||
#define DEFINE_TYPE(name) \
|
|
||||||
if (!DefineConstant(cx, ctypes, &sCTypeClass, #name, TYPE_##name)) \
|
|
||||||
return false;
|
|
||||||
#include "types.h"
|
|
||||||
#undef DEFINE_ABI
|
|
||||||
#undef DEFINE_TYPE
|
|
||||||
|
|
||||||
// attach API functions
|
// attach API functions
|
||||||
if (!JS_DefineFunctions(cx, ctypes, sModuleFunctions))
|
if (!JS_DefineFunctions(cx, ctypes, sModuleFunctions))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
// Seal the ctypes object, to prevent modification. (This single object
|
||||||
|
// instance is shared amongst everyone who imports the ctypes module.)
|
||||||
|
return JS_SealObject(cx, ctypes, JS_FALSE) != JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -44,27 +44,6 @@
|
|||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace ctypes {
|
namespace ctypes {
|
||||||
|
|
||||||
// Each internal CABI and CType class (representing ABI and type constants,
|
|
||||||
// respectively) has a unique identifier, stored in a reserved slot on the
|
|
||||||
// JSObject.
|
|
||||||
enum ABICode {
|
|
||||||
#define DEFINE_ABI(name) ABI_##name,
|
|
||||||
#define DEFINE_TYPE(name)
|
|
||||||
#include "types.h"
|
|
||||||
#undef DEFINE_ABI
|
|
||||||
#undef DEFINE_TYPE
|
|
||||||
INVALID_ABI
|
|
||||||
};
|
|
||||||
|
|
||||||
enum TypeCode {
|
|
||||||
#define DEFINE_ABI(name)
|
|
||||||
#define DEFINE_TYPE(name) TYPE_##name,
|
|
||||||
#include "types.h"
|
|
||||||
#undef DEFINE_ABI
|
|
||||||
#undef DEFINE_TYPE
|
|
||||||
INVALID_TYPE
|
|
||||||
};
|
|
||||||
|
|
||||||
class Module : public nsIXPCScriptable
|
class Module : public nsIXPCScriptable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -76,9 +55,6 @@ public:
|
|||||||
// Creates the ctypes object and attaches it to the global object.
|
// Creates the ctypes object and attaches it to the global object.
|
||||||
bool Init(JSContext* aContext, JSObject* aGlobal);
|
bool Init(JSContext* aContext, JSObject* aGlobal);
|
||||||
|
|
||||||
static ABICode GetABICode(JSContext* cx, jsval val);
|
|
||||||
static TypeCode GetTypeCode(JSContext* cx, jsval val);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
~Module();
|
~Module();
|
||||||
};
|
};
|
||||||
|
@ -44,123 +44,127 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
void
|
void
|
||||||
test_v()
|
test_void_t_cdecl()
|
||||||
{
|
{
|
||||||
// do nothing
|
// do nothing
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PRInt8
|
#define DEFINE_TYPE(name, type, ffiType) \
|
||||||
test_i8()
|
type \
|
||||||
{
|
get_##name##_cdecl() \
|
||||||
return 123;
|
{ \
|
||||||
|
return 109.25; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
type \
|
||||||
|
set_##name##_cdecl(type x) \
|
||||||
|
{ \
|
||||||
|
return x; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
type \
|
||||||
|
sum_##name##_cdecl(type x, type y) \
|
||||||
|
{ \
|
||||||
|
return x + y; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
type \
|
||||||
|
sum_alignb_##name##_cdecl(char a, type x, char b, type y, char c) \
|
||||||
|
{ \
|
||||||
|
return x + y; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
type \
|
||||||
|
sum_alignf_##name##_cdecl(float a, type x, float b, type y, float c) \
|
||||||
|
{ \
|
||||||
|
return x + y; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
type \
|
||||||
|
sum_many_##name##_cdecl( \
|
||||||
|
type a, type b, type c, type d, type e, type f, type g, type h, type i, \
|
||||||
|
type j, type k, type l, type m, type n, type o, type p, type q, type r) \
|
||||||
|
{ \
|
||||||
|
return a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p + q + r;\
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
struct align_##name { \
|
||||||
|
char x; \
|
||||||
|
type y; \
|
||||||
|
}; \
|
||||||
|
struct nested_##name { \
|
||||||
|
char a; \
|
||||||
|
align_##name b; \
|
||||||
|
char c; \
|
||||||
|
}; \
|
||||||
|
\
|
||||||
|
void \
|
||||||
|
get_##name##_stats(size_t* align, size_t* size, size_t* nalign, size_t* nsize, \
|
||||||
|
size_t offsets[]) \
|
||||||
|
{ \
|
||||||
|
*align = offsetof(align_##name, y); \
|
||||||
|
*size = sizeof(align_##name); \
|
||||||
|
*nalign = offsetof(nested_##name, b); \
|
||||||
|
*nsize = sizeof(nested_##name); \
|
||||||
|
offsets[0] = offsetof(align_##name, y); \
|
||||||
|
offsets[1] = offsetof(nested_##name, b); \
|
||||||
|
offsets[2] = offsetof(nested_##name, c); \
|
||||||
}
|
}
|
||||||
|
|
||||||
PRInt8
|
#include "../typedefs.h"
|
||||||
test_i8_i8(PRInt8 number)
|
|
||||||
{
|
#if defined(_WIN32) && !defined(__WIN64)
|
||||||
return number;
|
|
||||||
|
#define DEFINE_TYPE(name, type, ffiType) \
|
||||||
|
type NS_STDCALL \
|
||||||
|
get_##name##_stdcall() \
|
||||||
|
{ \
|
||||||
|
return 109.25; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
type NS_STDCALL \
|
||||||
|
set_##name##_stdcall(type x) \
|
||||||
|
{ \
|
||||||
|
return x; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
type NS_STDCALL \
|
||||||
|
sum_##name##_stdcall(type x, type y) \
|
||||||
|
{ \
|
||||||
|
return x + y; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
type NS_STDCALL \
|
||||||
|
sum_alignb_##name##_stdcall(char a, type x, char b, type y, char c) \
|
||||||
|
{ \
|
||||||
|
return x + y; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
type NS_STDCALL \
|
||||||
|
sum_alignf_##name##_stdcall(float a, type x, float b, type y, float c) \
|
||||||
|
{ \
|
||||||
|
return x + y; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
type NS_STDCALL \
|
||||||
|
sum_many_##name##_stdcall( \
|
||||||
|
type a, type b, type c, type d, type e, type f, type g, type h, type i, \
|
||||||
|
type j, type k, type l, type m, type n, type o, type p, type q, type r) \
|
||||||
|
{ \
|
||||||
|
return a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p + q + r;\
|
||||||
}
|
}
|
||||||
|
|
||||||
PRInt8
|
#include "../typedefs.h"
|
||||||
test_i8_i8_sum(PRInt8 number1, PRInt8 number2)
|
|
||||||
|
void NS_STDCALL
|
||||||
|
test_void_t_stdcall()
|
||||||
{
|
{
|
||||||
return number1 + number2;
|
// do nothing
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PRInt16
|
#endif /* defined(_WIN32) && !defined(__WIN64) */
|
||||||
test_i16()
|
|
||||||
{
|
|
||||||
return 12345;
|
|
||||||
}
|
|
||||||
|
|
||||||
PRInt16
|
|
||||||
test_i16_i16(PRInt16 number)
|
|
||||||
{
|
|
||||||
return number;
|
|
||||||
}
|
|
||||||
|
|
||||||
PRInt16
|
|
||||||
test_i16_i16_sum(PRInt16 number1, PRInt16 number2)
|
|
||||||
{
|
|
||||||
return number1 + number2;
|
|
||||||
}
|
|
||||||
|
|
||||||
PRInt32
|
|
||||||
test_i32()
|
|
||||||
{
|
|
||||||
return 123456789;
|
|
||||||
}
|
|
||||||
|
|
||||||
PRInt32
|
|
||||||
test_i32_i32(PRInt32 number)
|
|
||||||
{
|
|
||||||
return number;
|
|
||||||
}
|
|
||||||
|
|
||||||
PRInt32
|
|
||||||
test_i32_i32_sum(PRInt32 number1, PRInt32 number2)
|
|
||||||
{
|
|
||||||
return number1 + number2;
|
|
||||||
}
|
|
||||||
|
|
||||||
PRInt64
|
|
||||||
test_i64()
|
|
||||||
{
|
|
||||||
#if defined(WIN32) && !defined(__GNUC__)
|
|
||||||
return 0x28590a1c921de000i64;
|
|
||||||
#else
|
|
||||||
return 0x28590a1c921de000LL;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
PRInt64
|
|
||||||
test_i64_i64(PRInt64 number)
|
|
||||||
{
|
|
||||||
return number;
|
|
||||||
}
|
|
||||||
|
|
||||||
PRInt64
|
|
||||||
test_i64_i64_sum(PRInt64 number1, PRInt64 number2)
|
|
||||||
{
|
|
||||||
return number1 + number2;
|
|
||||||
}
|
|
||||||
|
|
||||||
float
|
|
||||||
test_f()
|
|
||||||
{
|
|
||||||
return 123456.5f;
|
|
||||||
}
|
|
||||||
|
|
||||||
float
|
|
||||||
test_f_f(float number)
|
|
||||||
{
|
|
||||||
return number;
|
|
||||||
}
|
|
||||||
|
|
||||||
float
|
|
||||||
test_f_f_sum(float number1, float number2)
|
|
||||||
{
|
|
||||||
return (number1 + number2);
|
|
||||||
}
|
|
||||||
|
|
||||||
double
|
|
||||||
test_d()
|
|
||||||
{
|
|
||||||
return 1234567890123456789.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
double
|
|
||||||
test_d_d(double number)
|
|
||||||
{
|
|
||||||
return number;
|
|
||||||
}
|
|
||||||
|
|
||||||
double
|
|
||||||
test_d_d_sum(double number1, double number2)
|
|
||||||
{
|
|
||||||
return (number1 + number2);
|
|
||||||
}
|
|
||||||
|
|
||||||
PRInt32
|
PRInt32
|
||||||
test_ansi_len(const char* string)
|
test_ansi_len(const char* string)
|
||||||
@ -194,8 +198,33 @@ test_ansi_echo(const char* string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
PRInt32
|
PRInt32
|
||||||
test_floor(PRInt32 number1, float number2)
|
test_pt_in_rect(RECT rc, POINT pt)
|
||||||
{
|
{
|
||||||
return PRInt32(floor(float(number1) + number2));
|
if (pt.x < rc.left || pt.x > rc.right)
|
||||||
|
return 0;
|
||||||
|
if (pt.y < rc.bottom || pt.y > rc.top)
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
test_init_pt(POINT* pt, PRInt32 x, PRInt32 y)
|
||||||
|
{
|
||||||
|
pt->x = x;
|
||||||
|
pt->y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRInt32
|
||||||
|
test_nested_struct(NESTED n)
|
||||||
|
{
|
||||||
|
return PRInt32(n.n1 + n.n2 + n.inner.i1 + n.inner.i2 + n.inner.i3 + n.n3 + n.n4);
|
||||||
|
}
|
||||||
|
|
||||||
|
POINT
|
||||||
|
test_struct_return(RECT r)
|
||||||
|
{
|
||||||
|
POINT p;
|
||||||
|
p.x = r.left; p.y = r.top;
|
||||||
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,34 +40,56 @@
|
|||||||
|
|
||||||
#include "nscore.h"
|
#include "nscore.h"
|
||||||
#include "prtypes.h"
|
#include "prtypes.h"
|
||||||
|
#include "jsapi.h"
|
||||||
|
|
||||||
|
#define EXPORT_CDECL(type) NS_EXPORT type
|
||||||
|
#define EXPORT_STDCALL(type) NS_EXPORT type NS_STDCALL
|
||||||
|
|
||||||
NS_EXTERN_C
|
NS_EXTERN_C
|
||||||
{
|
{
|
||||||
NS_EXPORT void test_v();
|
EXPORT_CDECL(void) test_void_t_cdecl();
|
||||||
|
|
||||||
NS_EXPORT PRInt8 test_i8();
|
EXPORT_CDECL(void*) get_voidptr_t_cdecl();
|
||||||
NS_EXPORT PRInt8 test_i8_i8(PRInt8);
|
EXPORT_CDECL(void*) set_voidptr_t_cdecl(void*);
|
||||||
NS_EXPORT PRInt8 test_i8_i8_sum(PRInt8, PRInt8);
|
|
||||||
|
|
||||||
NS_EXPORT PRInt16 test_i16();
|
#define DEFINE_TYPE(name, type, ffiType) \
|
||||||
NS_EXPORT PRInt16 test_i16_i16(PRInt16);
|
EXPORT_CDECL(type) get_##name##_cdecl(); \
|
||||||
NS_EXPORT PRInt16 test_i16_i16_sum(PRInt16, PRInt16);
|
EXPORT_CDECL(type) set_##name##_cdecl(type); \
|
||||||
|
EXPORT_CDECL(type) sum_##name##_cdecl(type, type); \
|
||||||
|
EXPORT_CDECL(type) sum_alignb_##name##_cdecl(char, type, char, type, char); \
|
||||||
|
EXPORT_CDECL(type) sum_alignf_##name##_cdecl( \
|
||||||
|
float, type, float, type, float); \
|
||||||
|
EXPORT_CDECL(type) sum_many_##name##_cdecl( \
|
||||||
|
type, type, type, type, type, type, type, type, type, \
|
||||||
|
type, type, type, type, type, type, type, type, type); \
|
||||||
|
\
|
||||||
|
EXPORT_CDECL(void) get_##name##_stats(size_t* align, size_t* size, \
|
||||||
|
size_t* nalign, size_t* nsize, \
|
||||||
|
size_t offsets[]);
|
||||||
|
|
||||||
NS_EXPORT PRInt32 test_i32();
|
#include "../typedefs.h"
|
||||||
NS_EXPORT PRInt32 test_i32_i32(PRInt32);
|
|
||||||
NS_EXPORT PRInt32 test_i32_i32_sum(PRInt32, PRInt32);
|
|
||||||
|
|
||||||
NS_EXPORT PRInt64 test_i64();
|
#if defined(_WIN32) && !defined(__WIN64)
|
||||||
NS_EXPORT PRInt64 test_i64_i64(PRInt64);
|
EXPORT_STDCALL(void) test_void_t_stdcall();
|
||||||
NS_EXPORT PRInt64 test_i64_i64_sum(PRInt64, PRInt64);
|
|
||||||
|
|
||||||
NS_EXPORT float test_f();
|
EXPORT_STDCALL(void*) get_voidptr_t_stdcall();
|
||||||
NS_EXPORT float test_f_f(float);
|
EXPORT_STDCALL(void*) set_voidptr_t_stdcall(void*);
|
||||||
NS_EXPORT float test_f_f_sum(float, float);
|
|
||||||
|
|
||||||
NS_EXPORT double test_d();
|
#define DEFINE_TYPE(name, type, ffiType) \
|
||||||
NS_EXPORT double test_d_d(double);
|
EXPORT_STDCALL(type) get_##name##_stdcall(); \
|
||||||
NS_EXPORT double test_d_d_sum(double, double);
|
EXPORT_STDCALL(type) set_##name##_stdcall(type); \
|
||||||
|
EXPORT_STDCALL(type) sum_##name##_stdcall(type, type); \
|
||||||
|
EXPORT_STDCALL(type) sum_alignb_##name##_stdcall( \
|
||||||
|
char, type, char, type, char); \
|
||||||
|
EXPORT_STDCALL(type) sum_alignf_##name##_stdcall( \
|
||||||
|
float, type, float, type, float); \
|
||||||
|
EXPORT_STDCALL(type) sum_many_##name##_stdcall( \
|
||||||
|
type, type, type, type, type, type, type, type, type, \
|
||||||
|
type, type, type, type, type, type, type, type, type);
|
||||||
|
|
||||||
|
#include "../typedefs.h"
|
||||||
|
|
||||||
|
#endif /* defined(_WIN32) && !defined(__WIN64) */
|
||||||
|
|
||||||
NS_EXPORT PRInt32 test_ansi_len(const char*);
|
NS_EXPORT PRInt32 test_ansi_len(const char*);
|
||||||
NS_EXPORT PRInt32 test_wide_len(const PRUnichar*);
|
NS_EXPORT PRInt32 test_wide_len(const PRUnichar*);
|
||||||
@ -75,6 +97,36 @@ NS_EXTERN_C
|
|||||||
NS_EXPORT const PRUnichar* test_wide_ret();
|
NS_EXPORT const PRUnichar* test_wide_ret();
|
||||||
NS_EXPORT char* test_ansi_echo(const char*);
|
NS_EXPORT char* test_ansi_echo(const char*);
|
||||||
|
|
||||||
NS_EXPORT PRInt32 test_floor(PRInt32, float);
|
struct POINT {
|
||||||
|
PRInt32 x;
|
||||||
|
PRInt32 y;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RECT {
|
||||||
|
PRInt32 top;
|
||||||
|
PRInt32 left;
|
||||||
|
PRInt32 bottom;
|
||||||
|
PRInt32 right;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct INNER {
|
||||||
|
PRUint8 i1;
|
||||||
|
PRInt64 i2;
|
||||||
|
PRUint8 i3;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NESTED {
|
||||||
|
PRInt32 n1;
|
||||||
|
PRInt16 n2;
|
||||||
|
INNER inner;
|
||||||
|
PRInt64 n3;
|
||||||
|
PRInt32 n4;
|
||||||
|
};
|
||||||
|
|
||||||
|
NS_EXPORT PRInt32 test_pt_in_rect(RECT, POINT);
|
||||||
|
NS_EXPORT void test_init_pt(POINT* pt, PRInt32 x, PRInt32 y);
|
||||||
|
|
||||||
|
NS_EXPORT PRInt32 test_nested_struct(NESTED);
|
||||||
|
NS_EXPORT POINT test_struct_return(RECT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
141
js/ctypes/typedefs.h
Normal file
141
js/ctypes/typedefs.h
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
||||||
|
/* ***** 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 js-ctypes.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is
|
||||||
|
* The Mozilla Foundation <http://www.mozilla.org/>.
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* Dan Witte <dwitte@mozilla.com>
|
||||||
|
*
|
||||||
|
* 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 ***** */
|
||||||
|
|
||||||
|
// If we're not breaking the types out, combine them together under one
|
||||||
|
// DEFINE_TYPE macro. Otherwise, turn off whichever ones we're not using.
|
||||||
|
#if defined(DEFINE_TYPE)
|
||||||
|
# define DEFINE_CHAR_TYPE(x, y, z) DEFINE_TYPE(x, y, z)
|
||||||
|
# define DEFINE_BOOL_TYPE(x, y, z) DEFINE_TYPE(x, y, z)
|
||||||
|
# define DEFINE_INT_TYPE(x, y, z) DEFINE_TYPE(x, y, z)
|
||||||
|
# define DEFINE_WRAPPED_INT_TYPE(x, y, z) DEFINE_TYPE(x, y, z)
|
||||||
|
# define DEFINE_FLOAT_TYPE(x, y, z) DEFINE_TYPE(x, y, z)
|
||||||
|
#else
|
||||||
|
# ifndef DEFINE_BOOL_TYPE
|
||||||
|
# define DEFINE_BOOL_TYPE(x, y, z)
|
||||||
|
# endif
|
||||||
|
# ifndef DEFINE_CHAR_TYPE
|
||||||
|
# define DEFINE_CHAR_TYPE(x, y, z)
|
||||||
|
# endif
|
||||||
|
# ifndef DEFINE_INT_TYPE
|
||||||
|
# define DEFINE_INT_TYPE(x, y, z)
|
||||||
|
# endif
|
||||||
|
# ifndef DEFINE_WRAPPED_INT_TYPE
|
||||||
|
# define DEFINE_WRAPPED_INT_TYPE(x, y, z)
|
||||||
|
# endif
|
||||||
|
# ifndef DEFINE_FLOAT_TYPE
|
||||||
|
# define DEFINE_FLOAT_TYPE(x, y, z)
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// MSVC doesn't have ssize_t. Help it along a little.
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
#define CTYPES_SSIZE_T ssize_t
|
||||||
|
#else
|
||||||
|
#define CTYPES_SSIZE_T intptr_t
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Some #defines to make handling of types whose length varies by platform
|
||||||
|
// easier. These could be implemented as configure tests, but the expressions
|
||||||
|
// are all statically resolvable so there's no need.
|
||||||
|
#define CTYPES_FFI_BOOL (sizeof(bool) == 1 ? ffi_type_uint8 : ffi_type_uint32)
|
||||||
|
#define CTYPES_FFI_LONG (sizeof(long) == 4 ? ffi_type_sint32 : ffi_type_sint64)
|
||||||
|
#define CTYPES_FFI_ULONG (sizeof(long) == 4 ? ffi_type_uint32 : ffi_type_uint64)
|
||||||
|
#define CTYPES_FFI_SIZE_T (sizeof(size_t) == 4 ? ffi_type_uint32 : ffi_type_uint64)
|
||||||
|
#define CTYPES_FFI_SSIZE_T (sizeof(size_t) == 4 ? ffi_type_sint32 : ffi_type_sint64)
|
||||||
|
#define CTYPES_FFI_INTPTR_T (sizeof(uintptr_t) == 4 ? ffi_type_sint32 : ffi_type_sint64)
|
||||||
|
#define CTYPES_FFI_UINTPTR_T (sizeof(uintptr_t) == 4 ? ffi_type_uint32 : ffi_type_uint64)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builtin types available for arguments and return values, representing
|
||||||
|
* their C counterparts. Format is:
|
||||||
|
*
|
||||||
|
* DEFINE_X_TYPE(typename, ctype, ffitype)
|
||||||
|
*
|
||||||
|
* where 'typename' is the name of the type constructor (accessible as
|
||||||
|
* ctypes.typename), 'ctype' is the corresponding C type declaration (from
|
||||||
|
* which sizeof(ctype) and templated type conversions will be derived), and
|
||||||
|
* 'ffitype' is the ffi_type to use. (Special types, such as 'void' and the
|
||||||
|
* pointer, array, and struct types are handled separately.)
|
||||||
|
*/
|
||||||
|
DEFINE_BOOL_TYPE (bool, bool, CTYPES_FFI_BOOL)
|
||||||
|
DEFINE_INT_TYPE (int8_t, PRInt8, ffi_type_sint8)
|
||||||
|
DEFINE_INT_TYPE (int16_t, PRInt16, ffi_type_sint16)
|
||||||
|
DEFINE_INT_TYPE (int32_t, PRInt32, ffi_type_sint32)
|
||||||
|
DEFINE_INT_TYPE (uint8_t, PRUint8, ffi_type_uint8)
|
||||||
|
DEFINE_INT_TYPE (uint16_t, PRUint16, ffi_type_uint16)
|
||||||
|
DEFINE_INT_TYPE (uint32_t, PRUint32, ffi_type_uint32)
|
||||||
|
DEFINE_INT_TYPE (short, short, ffi_type_sint16)
|
||||||
|
DEFINE_INT_TYPE (unsigned_short, unsigned short, ffi_type_uint16)
|
||||||
|
DEFINE_INT_TYPE (int, int, ffi_type_sint32)
|
||||||
|
DEFINE_INT_TYPE (unsigned_int, unsigned int, ffi_type_uint32)
|
||||||
|
DEFINE_INT_TYPE (unsigned, unsigned, ffi_type_uint32)
|
||||||
|
DEFINE_WRAPPED_INT_TYPE(int64_t, PRInt64, ffi_type_sint64)
|
||||||
|
DEFINE_WRAPPED_INT_TYPE(uint64_t, PRUint64, ffi_type_uint64)
|
||||||
|
DEFINE_WRAPPED_INT_TYPE(long, long, CTYPES_FFI_LONG)
|
||||||
|
DEFINE_WRAPPED_INT_TYPE(unsigned_long, unsigned long, CTYPES_FFI_ULONG)
|
||||||
|
DEFINE_WRAPPED_INT_TYPE(long_long, long long, ffi_type_sint64)
|
||||||
|
DEFINE_WRAPPED_INT_TYPE(unsigned_long_long, unsigned long long, ffi_type_uint64)
|
||||||
|
DEFINE_WRAPPED_INT_TYPE(size_t, size_t, CTYPES_FFI_SIZE_T)
|
||||||
|
DEFINE_WRAPPED_INT_TYPE(ssize_t, CTYPES_SSIZE_T, CTYPES_FFI_SSIZE_T)
|
||||||
|
DEFINE_WRAPPED_INT_TYPE(intptr_t, intptr_t, CTYPES_FFI_INTPTR_T)
|
||||||
|
DEFINE_WRAPPED_INT_TYPE(uintptr_t, uintptr_t, CTYPES_FFI_UINTPTR_T)
|
||||||
|
DEFINE_FLOAT_TYPE (float32_t, float, ffi_type_float)
|
||||||
|
DEFINE_FLOAT_TYPE (float64_t, double, ffi_type_double)
|
||||||
|
DEFINE_FLOAT_TYPE (float, float, ffi_type_float)
|
||||||
|
DEFINE_FLOAT_TYPE (double, double, ffi_type_double)
|
||||||
|
DEFINE_CHAR_TYPE (char, char, ffi_type_uint8)
|
||||||
|
DEFINE_CHAR_TYPE (signed_char, signed char, ffi_type_sint8)
|
||||||
|
DEFINE_CHAR_TYPE (unsigned_char, unsigned char, ffi_type_uint8)
|
||||||
|
DEFINE_CHAR_TYPE (jschar, jschar, ffi_type_uint16)
|
||||||
|
|
||||||
|
#undef CTYPES_SSIZE_T
|
||||||
|
#undef CTYPES_FFI_BOOL
|
||||||
|
#undef CTYPES_FFI_LONG
|
||||||
|
#undef CTYPES_FFI_ULONG
|
||||||
|
#undef CTYPES_FFI_SIZE_T
|
||||||
|
#undef CTYPES_FFI_SSIZE_T
|
||||||
|
#undef CTYPES_FFI_INTPTR_T
|
||||||
|
#undef CTYPES_FFI_UINTPTR_T
|
||||||
|
|
||||||
|
#undef DEFINE_TYPE
|
||||||
|
#undef DEFINE_CHAR_TYPE
|
||||||
|
#undef DEFINE_BOOL_TYPE
|
||||||
|
#undef DEFINE_INT_TYPE
|
||||||
|
#undef DEFINE_WRAPPED_INT_TYPE
|
||||||
|
#undef DEFINE_FLOAT_TYPE
|
||||||
|
|
@ -1,72 +0,0 @@
|
|||||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
|
||||||
/* ***** 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 js-ctypes.
|
|
||||||
*
|
|
||||||
* The Initial Developer of the Original Code is
|
|
||||||
* The Mozilla Foundation <http://www.mozilla.org/>.
|
|
||||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
|
||||||
* the Initial Developer. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Contributor(s):
|
|
||||||
* Dan Witte <dwitte@mozilla.com>
|
|
||||||
*
|
|
||||||
* 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 ***** */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This file defines the constants available on the ctypes.types object (e.g.
|
|
||||||
* ctypes.types.VOID). They do not have any interesting properties; they simply
|
|
||||||
* exist as unique identifiers for the type they represent.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ABI constants that specify the calling convention to use.
|
|
||||||
* DEFAULT corresponds to the cdecl convention, and in almost all
|
|
||||||
* cases is the correct choice. STDCALL is provided for calling
|
|
||||||
* functions in the Microsoft Win32 API.
|
|
||||||
*/
|
|
||||||
DEFINE_ABI(default_abi) // corresponds to cdecl
|
|
||||||
DEFINE_ABI(stdcall_abi) // for calling Win32 API functions
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Types available for arguments and return values, representing
|
|
||||||
* their C counterparts.
|
|
||||||
*/
|
|
||||||
DEFINE_TYPE(void_t) // Only allowed for return types.
|
|
||||||
DEFINE_TYPE(bool) // _Bool type (assumed 8 bits wide).
|
|
||||||
DEFINE_TYPE(int8_t) // int8_t (signed char) type.
|
|
||||||
DEFINE_TYPE(int16_t) // int16_t (short) type.
|
|
||||||
DEFINE_TYPE(int32_t) // int32_t (int) type.
|
|
||||||
DEFINE_TYPE(int64_t) // int64_t (long long) type.
|
|
||||||
DEFINE_TYPE(uint8_t) // uint8_t (unsigned char) type.
|
|
||||||
DEFINE_TYPE(uint16_t) // uint16_t (unsigned short) type.
|
|
||||||
DEFINE_TYPE(uint32_t) // uint32_t (unsigned int) type.
|
|
||||||
DEFINE_TYPE(uint64_t) // uint64_t (unsigned long long) type.
|
|
||||||
DEFINE_TYPE(float) // float type.
|
|
||||||
DEFINE_TYPE(double) // double type.
|
|
||||||
DEFINE_TYPE(string) // C string (char *).
|
|
||||||
DEFINE_TYPE(ustring) // 16-bit string (char16_t *).
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user