From 846b9a06a618b615b065183950854d389c390177 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Tue, 14 Feb 2012 16:26:05 -0500 Subject: [PATCH] Bug 704147 - Make ctypes function pointers callable via call and apply. r=bholley --- js/src/ctypes/CTypes.cpp | 20 ++++++++++------ .../ctypes/tests/unit/test_jsctypes.js.in | 23 +++++++++++++++++-- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/js/src/ctypes/CTypes.cpp b/js/src/ctypes/CTypes.cpp index b1f014c3470f..c638fd579b30 100644 --- a/js/src/ctypes/CTypes.cpp +++ b/js/src/ctypes/CTypes.cpp @@ -411,6 +411,12 @@ static JSPropertySpec sFunctionProps[] = { { 0, 0, 0, NULL, NULL } }; +static JSFunctionSpec sFunctionInstanceFunctions[] = { + JS_FN("call", js_fun_call, 1, CDATAFN_FLAGS), + JS_FN("apply", js_fun_apply, 2, CDATAFN_FLAGS), + JS_FS_END +}; + static JSClass sInt64ProtoClass = { "Int64", 0, @@ -857,8 +863,8 @@ InitTypeClasses(JSContext* cx, JSObject* parent) return false; js::AutoObjectRooter sroot(cx, protos[SLOT_STRUCTDATAPROTO]); - if (!InitTypeConstructor(cx, parent, CTypeProto, CDataProto, - sFunctionFunction, NULL, sFunctionProps, NULL, NULL, + if (!InitTypeConstructor(cx, parent, CTypeProto, protos[SLOT_POINTERDATAPROTO], + sFunctionFunction, NULL, sFunctionProps, sFunctionInstanceFunctions, NULL, protos[SLOT_FUNCTIONPROTO], protos[SLOT_FUNCTIONDATAPROTO])) return false; js::AutoObjectRooter froot(cx, protos[SLOT_FUNCTIONDATAPROTO]); @@ -3319,11 +3325,11 @@ PointerType::CreateInternal(JSContext* cx, JSObject* baseType) return JSVAL_TO_OBJECT(slot); // Get ctypes.PointerType.prototype and the common prototype for CData objects - // of this type. - JSObject* typeProto; - JSObject* dataProto; - typeProto = CType::GetProtoFromType(baseType, SLOT_POINTERPROTO); - dataProto = CType::GetProtoFromType(baseType, SLOT_POINTERDATAPROTO); + // of this type, or ctypes.FunctionType.prototype for function pointers. + CTypeProtoSlot slotId = CType::GetTypeCode(cx, baseType) == TYPE_function ? + SLOT_FUNCTIONDATAPROTO : SLOT_POINTERDATAPROTO; + JSObject* dataProto = CType::GetProtoFromType(cx, baseType, slotId); + JSObject* typeProto = CType::GetProtoFromType(cx, baseType, SLOT_POINTERPROTO); // Create a new CType object with the common properties and slots. JSObject* typeObj = CType::Create(cx, typeProto, dataProto, TYPE_pointer, diff --git a/toolkit/components/ctypes/tests/unit/test_jsctypes.js.in b/toolkit/components/ctypes/tests/unit/test_jsctypes.js.in index 3a9ae7f8e657..01bb6a99aab9 100644 --- a/toolkit/components/ctypes/tests/unit/test_jsctypes.js.in +++ b/toolkit/components/ctypes/tests/unit/test_jsctypes.js.in @@ -1328,7 +1328,10 @@ function run_type_ctor_class_tests(c, t, t2, props, fns, instanceProps, instance // equal to 't2.prototype.__proto__' where 't2' is a different CType // constructed from 'c'. do_check_true(t.prototype.__proto__ === t2.prototype.__proto__); - do_check_true(t.prototype.__proto__.__proto__ === ctypes.CData.prototype); + if (t instanceof ctypes.FunctionType) + do_check_true(t.prototype.__proto__.__proto__ === ctypes.PointerType.prototype.prototype); + else + do_check_true(t.prototype.__proto__.__proto__ === ctypes.CData.prototype); do_check_true(t.prototype instanceof ctypes.CData); do_check_true(t.prototype.constructor === t); @@ -1359,7 +1362,10 @@ function run_type_ctor_class_tests(c, t, t2, props, fns, instanceProps, instance do_check_throws(function() { t.prototype[p]; }, Error); // Make sure we can access 'prototype' on a CTypeProto. - do_check_true(Object.getPrototypeOf(c.prototype.prototype) === ctypes.CType.prototype.prototype); + if (t instanceof ctypes.FunctionType) + do_check_true(Object.getPrototypeOf(c.prototype.prototype) === ctypes.PointerType.prototype.prototype); + else + do_check_true(Object.getPrototypeOf(c.prototype.prototype) === ctypes.CType.prototype.prototype); // Test that an instance 'd' of 't' is a CData. if (t.__proto__ != ctypes.FunctionType.prototype) { @@ -2289,6 +2295,19 @@ function run_function_tests(library) // Test that we can call ptr(). do_check_eq(ptr("function pointers rule!"), 23); + // Test that we can call via call and apply + do_check_eq(ptr.call(null, "function pointers rule!"), 23); + do_check_eq(ptr.apply(null, ["function pointers rule!"]), 23); + + // Test that we cannot call non-function pointers via call and apply + let p_t = ctypes.PointerType(ctypes.int32_t); + let p = p_t(); + do_check_throws(function() { p.call(null, "woo"); }, Error); + do_check_throws(function() { p.apply(null, ["woo"]); }, Error); + + // Test the function pointers still behave as regular pointers + do_check_false(ptr.isNull(), "PointerType methods should still be valid"); + // Test that library.declare() returns data of type FunctionType.ptr, and that // it is immutable. do_check_true(test_ansi_len.constructor.targetType.__proto__ ===