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
|
||||
*******************************************************************************/
|
||||
|
||||
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
|
||||
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
|
||||
// given platform. TYPE_DEFAULT specifies the default
|
||||
// given platform. ABI_DEFAULT specifies the default
|
||||
// C calling convention (cdecl) on each platform.
|
||||
switch (abi) {
|
||||
case ABI_default_abi:
|
||||
case ABI_DEFAULT:
|
||||
aResult = FFI_DEFAULT_ABI;
|
||||
return true;
|
||||
case ABI_STDCALL:
|
||||
#if (defined(_WIN32) && !defined(_WIN64)) || defined(_OS2)
|
||||
case ABI_stdcall_abi:
|
||||
aResult = FFI_STDCALL;
|
||||
return true;
|
||||
#endif
|
||||
default:
|
||||
return false;
|
||||
case INVALID_ABI:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
PrepareType(JSContext* aContext, jsval aType, Type& aResult)
|
||||
{
|
||||
aResult.mType = Module::GetTypeCode(aContext, aType);
|
||||
|
||||
switch (aResult.mType) {
|
||||
case TYPE_void_t:
|
||||
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");
|
||||
if (!JSVAL_IS_OBJECT(aType) ||
|
||||
JSVAL_IS_NULL(aType) ||
|
||||
!CType::IsCType(aContext, JSVAL_TO_OBJECT(aType))) {
|
||||
JS_ReportError(aContext, "not a ctypes type");
|
||||
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;
|
||||
}
|
||||
|
||||
static bool
|
||||
PrepareValue(JSContext* aContext, const Type& aType, jsval aValue, Value& aResult)
|
||||
PrepareResultType(JSContext* aContext, jsval aType, Type& aResult)
|
||||
{
|
||||
jsdouble d;
|
||||
|
||||
switch (aType.mType) {
|
||||
case TYPE_bool:
|
||||
// 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");
|
||||
if (!JSVAL_IS_OBJECT(aType) ||
|
||||
JSVAL_IS_NULL(aType) ||
|
||||
!CType::IsCType(aContext, JSVAL_TO_OBJECT(aType))) {
|
||||
JS_ReportError(aContext, "not a ctypes type");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
JSObject* typeObj = JSVAL_TO_OBJECT(aType);
|
||||
TypeCode typeCode = CType::GetTypeCode(aContext, typeObj);
|
||||
|
||||
static void
|
||||
PrepareReturnValue(const Type& aType, Value& aResult)
|
||||
{
|
||||
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");
|
||||
// Arrays can never be return types.
|
||||
if (typeCode == TYPE_array) {
|
||||
JS_ReportError(aContext, "Result type cannot be an array");
|
||||
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;
|
||||
}
|
||||
|
||||
@ -516,7 +178,7 @@ Function::Init(JSContext* aContext,
|
||||
}
|
||||
|
||||
// prepare the result type
|
||||
if (!PrepareType(aContext, aResultType, mResultType))
|
||||
if (!PrepareResultType(aContext, aResultType, mResultType))
|
||||
return false;
|
||||
|
||||
// prepare the argument types
|
||||
@ -525,12 +187,6 @@ Function::Init(JSContext* aContext,
|
||||
if (!PrepareType(aContext, aArgTypes[i], *mArgTypes.AppendElement()))
|
||||
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.
|
||||
mFFITypes.AppendElement(&mArgTypes[i].mFFIType);
|
||||
}
|
||||
@ -561,39 +217,63 @@ Function::Execute(JSContext* cx, PRUint32 argc, jsval* vp)
|
||||
}
|
||||
|
||||
// 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) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// create an array of pointers to each value, for passing to ffi_call
|
||||
nsAutoTArray<void*, 16> ffiValues;
|
||||
for (PRUint32 i = 0; i < mArgTypes.Length(); ++i) {
|
||||
ffiValues.AppendElement(values[i].mData);
|
||||
if (!ImplicitConvert(cx, arg, mArgTypes[i].mType, value.mData, true, &freePointer))
|
||||
return false;
|
||||
|
||||
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
|
||||
Value resultValue;
|
||||
PrepareReturnValue(mResultType, resultValue);
|
||||
AutoValue 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
|
||||
// may block or otherwise take a long time to return.
|
||||
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);
|
||||
|
||||
// prepare a JS object from the result
|
||||
jsval rval;
|
||||
if (!ConvertReturnValue(cx, mResultType, resultValue, &rval))
|
||||
if (!ConvertToJS(cx, mResultType.mType, NULL, resultValue.mData, false, &rval))
|
||||
return false;
|
||||
|
||||
JS_SET_RVAL(cx, vp, rval);
|
||||
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
|
||||
*******************************************************************************/
|
||||
@ -627,15 +307,16 @@ Function::Create(JSContext* aContext,
|
||||
JSAutoTempValueRooter fnRoot(aContext, fnObj);
|
||||
|
||||
// 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;
|
||||
|
||||
// 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;
|
||||
|
||||
// tell the library we exist, so it can delete our Function instance
|
||||
// when it comes time to finalize. (JS functions don't have finalizers.)
|
||||
// Tell the library we exist, so it can (a) identify our CTypes to the tracer
|
||||
// and (b) delete our Function instance when it comes time to finalize.
|
||||
// (JS functions don't have finalizers.)
|
||||
if (!Library::AddFunction(aContext, aLibrary, self))
|
||||
return NULL;
|
||||
|
||||
@ -647,7 +328,7 @@ static Function*
|
||||
GetFunction(JSContext* cx, JSObject* obj)
|
||||
{
|
||||
jsval slot;
|
||||
JS_GetReservedSlot(cx, obj, 0, &slot);
|
||||
JS_GetReservedSlot(cx, obj, SLOT_FUNCTION, &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));
|
||||
|
||||
jsval slot;
|
||||
JS_GetReservedSlot(cx, callee, 1, &slot);
|
||||
JS_GetReservedSlot(cx, callee, SLOT_LIBRARYOBJ, &slot);
|
||||
|
||||
PRLibrary* library = Library::GetLibrary(cx, JSVAL_TO_OBJECT(slot));
|
||||
if (!library) {
|
||||
|
@ -40,48 +40,45 @@
|
||||
#ifndef FUNCTION_H
|
||||
#define FUNCTION_H
|
||||
|
||||
#include "Module.h"
|
||||
#include "CTypes.h"
|
||||
#include "nsTArray.h"
|
||||
#include "prlink.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
|
||||
enum FunctionSlot
|
||||
{
|
||||
SLOT_FUNCTION = 0,
|
||||
SLOT_LIBRARYOBJ = 1
|
||||
// JSFunction objects always get exactly two slots.
|
||||
};
|
||||
|
||||
const JSErrorFormatString*
|
||||
GetErrorMessage(void* userRef, const char* locale, const uintN errorNumber);
|
||||
|
||||
struct Type
|
||||
{
|
||||
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;
|
||||
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
|
||||
@ -90,6 +87,7 @@ public:
|
||||
Function();
|
||||
|
||||
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 JSBool Call(JSContext* cx, uintN argc, jsval* vp);
|
||||
|
@ -38,6 +38,7 @@
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "jscntxt.h"
|
||||
#include "Library.h"
|
||||
#include "Function.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
@ -55,15 +56,18 @@ namespace ctypes {
|
||||
|
||||
static JSClass sLibraryClass = {
|
||||
"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_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[] = {
|
||||
JS_FN("close", Library::Close, 0, JSFUN_FAST_NATIVE | JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT),
|
||||
JS_FN("declare", Library::Declare, 0, JSFUN_FAST_NATIVE | JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT),
|
||||
JS_FN("close", Library::Close, 0, CTYPESFN_FLAGS),
|
||||
JS_FN("declare", Library::Declare, 0, CTYPESFN_FLAGS),
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
@ -73,13 +77,15 @@ Library::Create(JSContext* cx, jsval aPath)
|
||||
JSObject* libraryObj = JS_NewObject(cx, &sLibraryClass, NULL, NULL);
|
||||
if (!libraryObj)
|
||||
return NULL;
|
||||
JSAutoTempValueRooter root(cx, libraryObj);
|
||||
|
||||
// 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;
|
||||
|
||||
// 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;
|
||||
|
||||
// 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.
|
||||
// determine which we have...
|
||||
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)
|
||||
return NULL;
|
||||
|
||||
// We don't use nsILocalFile.
|
||||
// Because this interface doesn't resolve library path to use system search rule.
|
||||
// We don't use nsILocalFile, because it doesn't use the system search
|
||||
// rules when resolving library path.
|
||||
PRLibSpec libSpec;
|
||||
#ifdef XP_WIN
|
||||
// On Windows, converting to native charset may corrupt path string.
|
||||
// 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;
|
||||
#else
|
||||
nsCAutoString nativePath;
|
||||
NS_CopyUnicodeToNative(nsDependentString(reinterpret_cast<const PRUnichar*>(path)), nativePath);
|
||||
NS_CopyUnicodeToNative(nsDependentString(path), nativePath);
|
||||
libSpec.value.pathname = nativePath.get();
|
||||
libSpec.type = PR_LibSpec_Pathname;
|
||||
#endif
|
||||
@ -132,7 +139,8 @@ Library::Create(JSContext* cx, jsval aPath)
|
||||
}
|
||||
|
||||
// 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 libraryObj;
|
||||
@ -144,7 +152,7 @@ Library::GetLibrary(JSContext* cx, JSObject* obj)
|
||||
JS_ASSERT(JS_GET_CLASS(cx, obj) == &sLibraryClass);
|
||||
|
||||
jsval slot;
|
||||
JS_GetReservedSlot(cx, obj, 0, &slot);
|
||||
JS_GetReservedSlot(cx, obj, SLOT_LIBRARY, &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);
|
||||
|
||||
jsval slot;
|
||||
JS_GetReservedSlot(cx, obj, 1, &slot);
|
||||
JS_GetReservedSlot(cx, obj, SLOT_FUNCTIONLIST, &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
|
||||
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
|
||||
@ -186,7 +207,7 @@ Library::Finalize(JSContext* cx, JSObject* obj)
|
||||
JSBool
|
||||
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");
|
||||
return JS_FALSE;
|
||||
}
|
||||
@ -217,8 +238,8 @@ Library::Close(JSContext* cx, uintN argc, jsval* vp)
|
||||
|
||||
// delete our internal objects
|
||||
Finalize(cx, obj);
|
||||
JS_SetReservedSlot(cx, obj, 0, PRIVATE_TO_JSVAL(NULL));
|
||||
JS_SetReservedSlot(cx, obj, 1, PRIVATE_TO_JSVAL(NULL));
|
||||
JS_SetReservedSlot(cx, obj, SLOT_LIBRARY, PRIVATE_TO_JSVAL(NULL));
|
||||
JS_SetReservedSlot(cx, obj, SLOT_FUNCTIONLIST, PRIVATE_TO_JSVAL(NULL));
|
||||
|
||||
JS_SET_RVAL(cx, vp, JSVAL_VOID);
|
||||
return JS_TRUE;
|
||||
@ -251,14 +272,15 @@ Library::Declare(JSContext* cx, uintN argc, jsval* vp)
|
||||
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);
|
||||
if (!func) {
|
||||
JS_ReportError(cx, "couldn't find function symbol in library");
|
||||
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)
|
||||
return JS_FALSE;
|
||||
|
||||
|
@ -40,19 +40,24 @@
|
||||
#ifndef LIBRARY_H
|
||||
#define LIBRARY_H
|
||||
|
||||
#include "Function.h"
|
||||
#include "jsapi.h"
|
||||
|
||||
struct PRLibrary;
|
||||
class Function;
|
||||
|
||||
namespace mozilla {
|
||||
namespace ctypes {
|
||||
|
||||
class Function;
|
||||
|
||||
enum LibrarySlot {
|
||||
SLOT_LIBRARY = 0,
|
||||
SLOT_FUNCTIONLIST = 1,
|
||||
LIBRARY_SLOTS
|
||||
};
|
||||
|
||||
class Library
|
||||
{
|
||||
public:
|
||||
static JSObject* Create(JSContext* cx, jsval aPath);
|
||||
static void Trace(JSTracer *trc, JSObject* obj);
|
||||
static void Finalize(JSContext* cx, JSObject* obj);
|
||||
|
||||
static PRLibrary* GetLibrary(JSContext* cx, JSObject* obj);
|
||||
|
@ -62,6 +62,7 @@ IS_COMPONENT = 1
|
||||
CPPSRCS = \
|
||||
Function.cpp \
|
||||
Library.cpp \
|
||||
CTypes.cpp \
|
||||
Module.cpp \
|
||||
$(NULL)
|
||||
|
||||
|
@ -39,6 +39,7 @@
|
||||
|
||||
#include "Module.h"
|
||||
#include "Library.h"
|
||||
#include "CTypes.h"
|
||||
#include "nsIGenericFactory.h"
|
||||
#include "nsMemory.h"
|
||||
|
||||
@ -83,74 +84,15 @@ Module::Call(nsIXPConnectWrappedNative* wrapper,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static JSClass sCABIClass = {
|
||||
"CABI",
|
||||
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
|
||||
};
|
||||
#define CTYPESFN_FLAGS \
|
||||
(JSFUN_FAST_NATIVE | JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
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
|
||||
Module::Init(JSContext* cx, JSObject* aGlobal)
|
||||
{
|
||||
@ -163,22 +105,16 @@ Module::Init(JSContext* cx, JSObject* aGlobal)
|
||||
NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
|
||||
return false;
|
||||
|
||||
// attach classes representing ABI and type constants
|
||||
#define DEFINE_ABI(name) \
|
||||
if (!DefineConstant(cx, ctypes, &sCABIClass, #name, ABI_##name)) \
|
||||
if (!InitTypeClasses(cx, ctypes))
|
||||
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
|
||||
if (!JS_DefineFunctions(cx, ctypes, sModuleFunctions))
|
||||
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 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
|
||||
{
|
||||
public:
|
||||
@ -76,9 +55,6 @@ public:
|
||||
// Creates the ctypes object and attaches it to the global object.
|
||||
bool Init(JSContext* aContext, JSObject* aGlobal);
|
||||
|
||||
static ABICode GetABICode(JSContext* cx, jsval val);
|
||||
static TypeCode GetTypeCode(JSContext* cx, jsval val);
|
||||
|
||||
private:
|
||||
~Module();
|
||||
};
|
||||
|
@ -44,123 +44,127 @@
|
||||
#include <math.h>
|
||||
|
||||
void
|
||||
test_v()
|
||||
test_void_t_cdecl()
|
||||
{
|
||||
// do nothing
|
||||
return;
|
||||
}
|
||||
|
||||
PRInt8
|
||||
test_i8()
|
||||
{
|
||||
return 123;
|
||||
#define DEFINE_TYPE(name, type, ffiType) \
|
||||
type \
|
||||
get_##name##_cdecl() \
|
||||
{ \
|
||||
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
|
||||
test_i8_i8(PRInt8 number)
|
||||
{
|
||||
return number;
|
||||
#include "../typedefs.h"
|
||||
|
||||
#if defined(_WIN32) && !defined(__WIN64)
|
||||
|
||||
#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
|
||||
test_i8_i8_sum(PRInt8 number1, PRInt8 number2)
|
||||
#include "../typedefs.h"
|
||||
|
||||
void NS_STDCALL
|
||||
test_void_t_stdcall()
|
||||
{
|
||||
return number1 + number2;
|
||||
// do nothing
|
||||
return;
|
||||
}
|
||||
|
||||
PRInt16
|
||||
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);
|
||||
}
|
||||
#endif /* defined(_WIN32) && !defined(__WIN64) */
|
||||
|
||||
PRInt32
|
||||
test_ansi_len(const char* string)
|
||||
@ -194,8 +198,33 @@ test_ansi_echo(const char* string)
|
||||
}
|
||||
|
||||
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 "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_EXPORT void test_v();
|
||||
EXPORT_CDECL(void) test_void_t_cdecl();
|
||||
|
||||
NS_EXPORT PRInt8 test_i8();
|
||||
NS_EXPORT PRInt8 test_i8_i8(PRInt8);
|
||||
NS_EXPORT PRInt8 test_i8_i8_sum(PRInt8, PRInt8);
|
||||
EXPORT_CDECL(void*) get_voidptr_t_cdecl();
|
||||
EXPORT_CDECL(void*) set_voidptr_t_cdecl(void*);
|
||||
|
||||
NS_EXPORT PRInt16 test_i16();
|
||||
NS_EXPORT PRInt16 test_i16_i16(PRInt16);
|
||||
NS_EXPORT PRInt16 test_i16_i16_sum(PRInt16, PRInt16);
|
||||
#define DEFINE_TYPE(name, type, ffiType) \
|
||||
EXPORT_CDECL(type) get_##name##_cdecl(); \
|
||||
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();
|
||||
NS_EXPORT PRInt32 test_i32_i32(PRInt32);
|
||||
NS_EXPORT PRInt32 test_i32_i32_sum(PRInt32, PRInt32);
|
||||
#include "../typedefs.h"
|
||||
|
||||
NS_EXPORT PRInt64 test_i64();
|
||||
NS_EXPORT PRInt64 test_i64_i64(PRInt64);
|
||||
NS_EXPORT PRInt64 test_i64_i64_sum(PRInt64, PRInt64);
|
||||
#if defined(_WIN32) && !defined(__WIN64)
|
||||
EXPORT_STDCALL(void) test_void_t_stdcall();
|
||||
|
||||
NS_EXPORT float test_f();
|
||||
NS_EXPORT float test_f_f(float);
|
||||
NS_EXPORT float test_f_f_sum(float, float);
|
||||
EXPORT_STDCALL(void*) get_voidptr_t_stdcall();
|
||||
EXPORT_STDCALL(void*) set_voidptr_t_stdcall(void*);
|
||||
|
||||
NS_EXPORT double test_d();
|
||||
NS_EXPORT double test_d_d(double);
|
||||
NS_EXPORT double test_d_d_sum(double, double);
|
||||
#define DEFINE_TYPE(name, type, ffiType) \
|
||||
EXPORT_STDCALL(type) get_##name##_stdcall(); \
|
||||
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_wide_len(const PRUnichar*);
|
||||
@ -75,6 +97,36 @@ NS_EXTERN_C
|
||||
NS_EXPORT const PRUnichar* test_wide_ret();
|
||||
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