bool CrossCompartmentWrapper::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs srcArgs) { RootedObject wrapper(cx, &srcArgs.thisv().toObject()); JS_ASSERT(srcArgs.thisv().isMagic(JS_IS_CONSTRUCTING) || !UncheckedUnwrap(wrapper)->isCrossCompartmentWrapper()); RootedObject wrapped(cx, wrappedObject(wrapper)); { AutoCompartment call(cx, wrapped); InvokeArgsGuard dstArgs; if (!cx->stack.pushInvokeArgs(cx, srcArgs.length(), &dstArgs)) return false; Value *src = srcArgs.base(); Value *srcend = srcArgs.array() + srcArgs.length(); Value *dst = dstArgs.base(); RootedValue source(cx); for (; src < srcend; ++src, ++dst) { source = *src; if (!cx->compartment->wrap(cx, &source)) return false; *dst = source.get(); // Handle |this| specially. When we rewrap on the other side of the // membrane, we might apply a same-compartment security wrapper that // will stymie this whole process. If that happens, unwrap the wrapper. // This logic can go away when same-compartment security wrappers go away. if ((src == srcArgs.base() + 1) && dst->isObject()) { RootedObject thisObj(cx, &dst->toObject()); if (thisObj->isWrapper() && !Wrapper::wrapperHandler(thisObj)->isSafeToUnwrap()) { JS_ASSERT(!IsCrossCompartmentWrapper(thisObj)); *dst = ObjectValue(*Wrapper::wrappedObject(thisObj)); } } } if (!CallNonGenericMethod(cx, test, impl, dstArgs)) return false; srcArgs.rval().set(dstArgs.rval()); dstArgs.pop(); } return cx->compartment->wrap(cx, srcArgs.rval()); }
bool CrossCompartmentWrapper::nativeCall(JSContext *cx, JSObject *wrapper, Class *clasp, Native native, CallArgs srcArgs) { JS_ASSERT_IF(!srcArgs.calleev().isUndefined(), srcArgs.callee().toFunction()->native() == native || srcArgs.callee().toFunction()->native() == js_generic_native_method_dispatcher); JS_ASSERT(&srcArgs.thisv().toObject() == wrapper); JS_ASSERT(!UnwrapObject(wrapper)->isCrossCompartmentWrapper()); JSObject *wrapped = wrappedObject(wrapper); AutoCompartment call(cx, wrapped); if (!call.enter()) return false; InvokeArgsGuard dstArgs; if (!cx->stack.pushInvokeArgs(cx, srcArgs.length(), &dstArgs)) return false; Value *src = srcArgs.base(); Value *srcend = srcArgs.array() + srcArgs.length(); Value *dst = dstArgs.base(); for (; src != srcend; ++src, ++dst) { *dst = *src; if (!call.destination->wrap(cx, dst)) return false; } if (!Wrapper::nativeCall(cx, wrapper, clasp, native, dstArgs)) return false; dstArgs.pop(); call.leave(); srcArgs.rval() = dstArgs.rval(); return call.origin->wrap(cx, &srcArgs.rval()); }
bool CrossCompartmentWrapper::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs srcArgs) { Rooted<JSObject*> wrapper(cx, &srcArgs.thisv().toObject()); JS_ASSERT(srcArgs.thisv().isMagic(JS_IS_CONSTRUCTING) || !UnwrapObject(wrapper)->isCrossCompartmentWrapper()); RootedObject wrapped(cx, wrappedObject(wrapper)); { AutoCompartment call(cx, wrapped); InvokeArgsGuard dstArgs; if (!cx->stack.pushInvokeArgs(cx, srcArgs.length(), &dstArgs)) return false; Value *src = srcArgs.base(); Value *srcend = srcArgs.array() + srcArgs.length(); Value *dst = dstArgs.base(); for (; src < srcend; ++src, ++dst) { *dst = *src; if (!cx->compartment->wrap(cx, dst)) return false; } if (!CallNonGenericMethod(cx, test, impl, dstArgs)) return false; srcArgs.rval().set(dstArgs.rval()); dstArgs.pop(); } return cx->compartment->wrap(cx, srcArgs.rval().address()); }
bool CrossCompartmentWrapper::nativeCall(JSContext *cx, JSObject *wrapper, Class *clasp, Native native, CallArgs srcArgs) { JS_ASSERT(srcArgs.thisv().isMagic(JS_IS_CONSTRUCTING) || &srcArgs.thisv().toObject() == wrapper); JS_ASSERT(!UnwrapObject(wrapper)->isCrossCompartmentWrapper()); JSObject *wrapped = wrappedObject(wrapper); AutoCompartment call(cx, wrapped); if (!call.enter()) return false; InvokeArgsGuard dstArgs; if (!cx->stack.pushInvokeArgs(cx, srcArgs.length(), &dstArgs)) return false; Value *src = srcArgs.base(); Value *srcend = srcArgs.array() + srcArgs.length(); Value *dst = dstArgs.base(); for (; src != srcend; ++src, ++dst) { *dst = *src; if (!call.destination->wrap(cx, dst)) return false; } if (!CallJSNative(cx, native, dstArgs)) return false; srcArgs.rval() = dstArgs.rval(); dstArgs.pop(); call.leave(); return cx->compartment->wrap(cx, &srcArgs.rval()); }
bool ArrayBufferObject::createDataViewForThisImpl(JSContext *cx, CallArgs args) { JS_ASSERT(IsArrayBuffer(args.thisv())); /* * This method is only called for |DataView(alienBuf, ...)| which calls * this as |createDataViewForThis.call(alienBuf, ..., DataView.prototype)|, * ergo there must be at least two arguments. */ JS_ASSERT(args.length() >= 2); Rooted<JSObject*> proto(cx, &args[args.length() - 1].toObject()); Rooted<JSObject*> buffer(cx, &args.thisv().toObject()); /* * Pop off the passed-along prototype and delegate to normal DataViewObject * construction. */ CallArgs frobbedArgs = CallArgsFromVp(args.length() - 1, args.base()); return DataViewObject::construct(cx, buffer, frobbedArgs, proto); }
bool WrapperOwner::callOrConstruct(JSContext* cx, HandleObject proxy, const CallArgs& args, bool construct) { ObjectId objId = idOf(proxy); InfallibleTArray<JSParam> vals; AutoValueVector outobjects(cx); RootedValue v(cx); for (size_t i = 0; i < args.length() + 2; i++) { // The |this| value for constructors is a magic value that we won't be // able to convert, so skip it. if (i == 1 && construct) v = UndefinedValue(); else v = args.base()[i]; if (v.isObject()) { RootedObject obj(cx, &v.toObject()); if (xpc::IsOutObject(cx, obj)) { // Make sure it is not an in-out object. bool found; if (!JS_HasProperty(cx, obj, "value", &found)) return false; if (found) { JS_ReportErrorASCII(cx, "in-out objects cannot be sent via CPOWs yet"); return false; } vals.AppendElement(JSParam(void_t())); if (!outobjects.append(ObjectValue(*obj))) return false; continue; } } JSVariant val; if (!toVariant(cx, v, &val)) return false; vals.AppendElement(JSParam(val)); } JSVariant result; ReturnStatus status; InfallibleTArray<JSParam> outparams; if (!SendCallOrConstruct(objId, vals, construct, &status, &result, &outparams)) return ipcfail(cx); LOG_STACK(); if (!ok(cx, status)) return false; if (outparams.Length() != outobjects.length()) return ipcfail(cx); RootedObject obj(cx); for (size_t i = 0; i < outparams.Length(); i++) { // Don't bother doing anything for outparams that weren't set. if (outparams[i].type() == JSParam::Tvoid_t) continue; // Take the value the child process returned, and set it on the XPC // object. if (!fromVariant(cx, outparams[i], &v)) return false; obj = &outobjects[i].toObject(); if (!JS_SetProperty(cx, obj, "value", v)) return false; } if (!fromVariant(cx, result, args.rval())) return false; return true; }
js::ForwardToNative(JSContext *cx, JSNative native, const CallArgs &args) { return native(cx, args.length(), args.base()); }