michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "jsapi-tests/tests.h" michael@0: michael@0: using namespace JS; michael@0: michael@0: static const JSClass CustomClass = { michael@0: "CustomClass", michael@0: JSCLASS_HAS_RESERVED_SLOTS(1), michael@0: JS_PropertyStub, michael@0: JS_DeletePropertyStub, michael@0: JS_PropertyStub, michael@0: JS_StrictPropertyStub, michael@0: JS_EnumerateStub, michael@0: JS_ResolveStub, michael@0: JS_ConvertStub michael@0: }; michael@0: michael@0: static const uint32_t CUSTOM_SLOT = 0; michael@0: michael@0: static bool michael@0: IsCustomClass(JS::Handle v) michael@0: { michael@0: return v.isObject() && JS_GetClass(&v.toObject()) == &CustomClass; michael@0: } michael@0: michael@0: static bool michael@0: CustomMethodImpl(JSContext *cx, CallArgs args) michael@0: { michael@0: JS_ASSERT(IsCustomClass(args.thisv())); michael@0: args.rval().set(JS_GetReservedSlot(&args.thisv().toObject(), CUSTOM_SLOT)); michael@0: return true; michael@0: } michael@0: michael@0: static bool michael@0: CustomMethod(JSContext *cx, unsigned argc, Value *vp) michael@0: { michael@0: CallArgs args = CallArgsFromVp(argc, vp); michael@0: return CallNonGenericMethod(cx, IsCustomClass, CustomMethodImpl, args); michael@0: } michael@0: michael@0: BEGIN_TEST(test_CallNonGenericMethodOnProxy) michael@0: { michael@0: // Create the first global object and compartment michael@0: JS::RootedObject globalA(cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr, JS::FireOnNewGlobalHook)); michael@0: CHECK(globalA); michael@0: michael@0: JS::RootedObject customA(cx, JS_NewObject(cx, &CustomClass, JS::NullPtr(), JS::NullPtr())); michael@0: CHECK(customA); michael@0: JS_SetReservedSlot(customA, CUSTOM_SLOT, Int32Value(17)); michael@0: michael@0: JS::RootedFunction customMethodA(cx, JS_NewFunction(cx, CustomMethod, 0, 0, michael@0: customA, "customMethodA")); michael@0: CHECK(customMethodA); michael@0: michael@0: JS::RootedValue rval(cx); michael@0: CHECK(JS_CallFunction(cx, customA, customMethodA, JS::HandleValueArray::empty(), michael@0: &rval)); michael@0: CHECK_SAME(rval, Int32Value(17)); michael@0: michael@0: // Now create the second global object and compartment... michael@0: { michael@0: JS::RootedObject globalB(cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr, JS::FireOnNewGlobalHook)); michael@0: CHECK(globalB); michael@0: michael@0: // ...and enter it. michael@0: JSAutoCompartment enter(cx, globalB); michael@0: JS::RootedObject customB(cx, JS_NewObject(cx, &CustomClass, JS::NullPtr(), JS::NullPtr())); michael@0: CHECK(customB); michael@0: JS_SetReservedSlot(customB, CUSTOM_SLOT, Int32Value(42)); michael@0: michael@0: JS::RootedFunction customMethodB(cx, JS_NewFunction(cx, CustomMethod, 0, 0, customB, "customMethodB")); michael@0: CHECK(customMethodB); michael@0: michael@0: JS::RootedValue rval(cx); michael@0: CHECK(JS_CallFunction(cx, customB, customMethodB, JS::HandleValueArray::empty(), michael@0: &rval)); michael@0: CHECK_SAME(rval, Int32Value(42)); michael@0: michael@0: JS::RootedObject wrappedCustomA(cx, customA); michael@0: CHECK(JS_WrapObject(cx, &wrappedCustomA)); michael@0: michael@0: JS::RootedValue rval2(cx); michael@0: CHECK(JS_CallFunction(cx, wrappedCustomA, customMethodB, JS::HandleValueArray::empty(), michael@0: &rval2)); michael@0: CHECK_SAME(rval, Int32Value(42)); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: END_TEST(test_CallNonGenericMethodOnProxy)