JSBool EvalScriptVersion16(JSContext *cx, unsigned argc, jsval *vp) { JS_ASSERT(argc == 1); jsval *argv = JS_ARGV(cx, vp); JS_ASSERT(JSVAL_IS_STRING(argv[0])); JSStableString *str = JSVAL_TO_STRING(argv[0])->ensureStable(cx); JS_ASSERT(str); return callbackData->evalVersion(str->chars().get(), str->length(), JSVERSION_1_6); }
/* ES5 15.12.2. */ JSBool js_json_parse(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); /* Step 1. */ JSString *str = (argc >= 1) ? ToString(cx, args[0]) : cx->names().undefined; if (!str) return false; JSStableString *stable = str->ensureStable(cx); if (!stable) return false; JS::Anchor<JSString *> anchor(stable); RootedValue reviver(cx, (argc >= 2) ? args[1] : UndefinedValue()); /* Steps 2-5. */ return ParseJSONWithReviver(cx, stable->chars(), stable->length(), reviver, args.rval()); }
bool JSCompartment::wrap(JSContext *cx, Value *vp, JSObject *existing) { JS_ASSERT(cx->compartment == this); JS_ASSERT_IF(existing, existing->compartment() == cx->compartment); JS_ASSERT_IF(existing, vp->isObject()); JS_ASSERT_IF(existing, IsDeadProxyObject(existing)); unsigned flags = 0; JS_CHECK_CHROME_RECURSION(cx, return false); #ifdef DEBUG struct AutoDisableProxyCheck { JSRuntime *runtime; AutoDisableProxyCheck(JSRuntime *rt) : runtime(rt) { runtime->gcDisableStrictProxyCheckingCount++; } ~AutoDisableProxyCheck() { runtime->gcDisableStrictProxyCheckingCount--; } } adpc(rt); #endif /* Only GC things have to be wrapped or copied. */ if (!vp->isMarkable()) return true; if (vp->isString()) { JSString *str = vp->toString(); /* If the string is already in this compartment, we are done. */ if (str->compartment() == this) return true; /* If the string is an atom, we don't have to copy. */ if (str->isAtom()) { JS_ASSERT(str->compartment() == cx->runtime->atomsCompartment); return true; } } /* * Wrappers should really be parented to the wrapped parent of the wrapped * object, but in that case a wrapped global object would have a NULL * parent without being a proper global object (JSCLASS_IS_GLOBAL). Instead, * we parent all wrappers to the global object in their home compartment. * This loses us some transparency, and is generally very cheesy. */ HandleObject global = cx->global(); /* Unwrap incoming objects. */ if (vp->isObject()) { Rooted<JSObject*> obj(cx, &vp->toObject()); if (obj->compartment() == this) return WrapForSameCompartment(cx, obj, vp); /* Translate StopIteration singleton. */ if (obj->isStopIteration()) { RootedValue vvp(cx, *vp); bool result = js_FindClassObject(cx, JSProto_StopIteration, &vvp); *vp = vvp; return result; } /* Unwrap the object, but don't unwrap outer windows. */ obj = UnwrapObject(&vp->toObject(), /* stopAtOuter = */ true, &flags); if (obj->compartment() == this) return WrapForSameCompartment(cx, obj, vp); if (cx->runtime->preWrapObjectCallback) { obj = cx->runtime->preWrapObjectCallback(cx, global, obj, flags); if (!obj) return false; } if (obj->compartment() == this) return WrapForSameCompartment(cx, obj, vp); vp->setObject(*obj); #ifdef DEBUG { JSObject *outer = GetOuterObject(cx, obj); JS_ASSERT(outer && outer == obj); } #endif } RootedValue key(cx, *vp); /* If we already have a wrapper for this value, use it. */ if (WrapperMap::Ptr p = crossCompartmentWrappers.lookup(key)) { *vp = p->value; if (vp->isObject()) { RootedObject obj(cx, &vp->toObject()); JS_ASSERT(obj->isCrossCompartmentWrapper()); JS_ASSERT(obj->getParent() == global); } return true; } if (vp->isString()) { RootedValue orig(cx, *vp); JSStableString *str = vp->toString()->ensureStable(cx); if (!str) return false; JSString *wrapped = js_NewStringCopyN(cx, str->chars().get(), str->length()); if (!wrapped) return false; vp->setString(wrapped); return crossCompartmentWrappers.put(orig, *vp); } RootedObject obj(cx, &vp->toObject()); JSObject *proto = Proxy::LazyProto; if (existing) { /* Is it possible to reuse |existing|? */ if (!existing->getTaggedProto().isLazy() || existing->getClass() != &ObjectProxyClass || existing->getParent() != global || obj->isCallable()) { existing = NULL; } } /* * We hand in the original wrapped object into the wrap hook to allow * the wrap hook to reason over what wrappers are currently applied * to the object. */ RootedObject wrapper(cx); wrapper = cx->runtime->wrapObjectCallback(cx, existing, obj, proto, global, flags); if (!wrapper) return false; // We maintain the invariant that the key in the cross-compartment wrapper // map is always directly wrapped by the value. JS_ASSERT(Wrapper::wrappedObject(wrapper) == &key.get().toObject()); vp->setObject(*wrapper); if (!crossCompartmentWrappers.put(key, *vp)) return false; return true; }
bool JSStructuredCloneReader::startRead(Value *vp) { uint32_t tag, data; if (!in.readPair(&tag, &data)) return false; switch (tag) { case SCTAG_NULL: vp->setNull(); break; case SCTAG_UNDEFINED: vp->setUndefined(); break; case SCTAG_BOOLEAN: case SCTAG_BOOLEAN_OBJECT: vp->setBoolean(!!data); if (tag == SCTAG_BOOLEAN_OBJECT && !js_PrimitiveToObject(context(), vp)) return false; break; case SCTAG_STRING: case SCTAG_STRING_OBJECT: { JSString *str = readString(data); if (!str) return false; vp->setString(str); if (tag == SCTAG_STRING_OBJECT && !js_PrimitiveToObject(context(), vp)) return false; break; } case SCTAG_NUMBER_OBJECT: { double d; if (!in.readDouble(&d) || !checkDouble(d)) return false; vp->setDouble(d); if (!js_PrimitiveToObject(context(), vp)) return false; break; } case SCTAG_DATE_OBJECT: { double d; if (!in.readDouble(&d) || !checkDouble(d)) return false; if (!IsNaN(d) && d != TimeClip(d)) { JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, JSMSG_SC_BAD_SERIALIZED_DATA, "date"); return false; } JSObject *obj = js_NewDateObjectMsec(context(), d); if (!obj) return false; vp->setObject(*obj); break; } case SCTAG_REGEXP_OBJECT: { RegExpFlag flags = RegExpFlag(data); uint32_t tag2, nchars; if (!in.readPair(&tag2, &nchars)) return false; if (tag2 != SCTAG_STRING) { JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, JSMSG_SC_BAD_SERIALIZED_DATA, "regexp"); return false; } JSString *str = readString(nchars); if (!str) return false; JSStableString *stable = str->ensureStable(context()); if (!stable) return false; size_t length = stable->length(); const StableCharPtr chars = stable->chars(); RegExpObject *reobj = RegExpObject::createNoStatics(context(), chars.get(), length, flags, NULL); if (!reobj) return false; vp->setObject(*reobj); break; } case SCTAG_ARRAY_OBJECT: case SCTAG_OBJECT_OBJECT: { JSObject *obj = (tag == SCTAG_ARRAY_OBJECT) ? NewDenseEmptyArray(context()) : NewBuiltinClassInstance(context(), &ObjectClass); if (!obj || !objs.append(ObjectValue(*obj))) return false; vp->setObject(*obj); break; } case SCTAG_BACK_REFERENCE_OBJECT: { if (data >= allObjs.length()) { JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, JSMSG_SC_BAD_SERIALIZED_DATA, "invalid back reference in input"); return false; } *vp = allObjs[data]; return true; } case SCTAG_TRANSFER_MAP_HEADER: // A map header cannot be here but just at the beginning of the buffer. JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, JSMSG_SC_BAD_SERIALIZED_DATA, "invalid input"); return false; case SCTAG_TRANSFER_MAP: // A map cannot be here but just at the beginning of the buffer. JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, JSMSG_SC_BAD_SERIALIZED_DATA, "invalid input"); return false; case SCTAG_ARRAY_BUFFER_OBJECT: if (!readArrayBuffer(data, vp)) return false; break; case SCTAG_TYPED_ARRAY_OBJECT: // readTypedArray adds the array to allObjs uint64_t arrayType; if (!in.read(&arrayType)) return false; return readTypedArray(arrayType, data, vp); break; default: { if (tag <= SCTAG_FLOAT_MAX) { double d = ReinterpretPairAsDouble(tag, data); if (!checkDouble(d)) return false; vp->setNumber(d); break; } if (SCTAG_TYPED_ARRAY_V1_MIN <= tag && tag <= SCTAG_TYPED_ARRAY_V1_MAX) { // A v1-format typed array // readTypedArray adds the array to allObjs return readTypedArray(TagToV1ArrayType(tag), data, vp, true); } if (!callbacks || !callbacks->read) { JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, JSMSG_SC_BAD_SERIALIZED_DATA, "unsupported type"); return false; } JSObject *obj = callbacks->read(context(), this, tag, data, closure); if (!obj) return false; vp->setObject(*obj); } } if (vp->isObject() && !allObjs.append(*vp)) return false; return true; }
bool JSCompartment::wrap(JSContext *cx, Value *vp) { JS_ASSERT(cx->compartment == this); unsigned flags = 0; JS_CHECK_RECURSION(cx, return false); #ifdef DEBUG struct AutoDisableProxyCheck { JSRuntime *runtime; AutoDisableProxyCheck(JSRuntime *rt) : runtime(rt) { runtime->gcDisableStrictProxyCheckingCount++; } ~AutoDisableProxyCheck() { runtime->gcDisableStrictProxyCheckingCount--; } } adpc(rt); #endif /* Only GC things have to be wrapped or copied. */ if (!vp->isMarkable()) return true; if (vp->isString()) { JSString *str = vp->toString(); /* If the string is already in this compartment, we are done. */ if (str->compartment() == this) return true; /* If the string is an atom, we don't have to copy. */ if (str->isAtom()) { JS_ASSERT(str->compartment() == cx->runtime->atomsCompartment); return true; } } /* * Wrappers should really be parented to the wrapped parent of the wrapped * object, but in that case a wrapped global object would have a NULL * parent without being a proper global object (JSCLASS_IS_GLOBAL). Instead, * we parent all wrappers to the global object in their home compartment. * This loses us some transparency, and is generally very cheesy. */ HandleObject global = cx->global(); /* Unwrap incoming objects. */ if (vp->isObject()) { Rooted<JSObject*> obj(cx, &vp->toObject()); if (obj->compartment() == this) return WrapForSameCompartment(cx, obj, vp); /* Translate StopIteration singleton. */ if (obj->isStopIteration()) { RootedValue vvp(cx, *vp); bool result = js_FindClassObject(cx, JSProto_StopIteration, &vvp); *vp = vvp; return result; } /* Unwrap the object, but don't unwrap outer windows. */ obj = UnwrapObject(&vp->toObject(), /* stopAtOuter = */ true, &flags); if (obj->compartment() == this) return WrapForSameCompartment(cx, obj, vp); if (cx->runtime->preWrapObjectCallback) { obj = cx->runtime->preWrapObjectCallback(cx, global, obj, flags); if (!obj) return false; } if (obj->compartment() == this) return WrapForSameCompartment(cx, obj, vp); vp->setObject(*obj); #ifdef DEBUG { JSObject *outer = GetOuterObject(cx, obj); JS_ASSERT(outer && outer == obj); } #endif } RootedValue key(cx, *vp); /* If we already have a wrapper for this value, use it. */ if (WrapperMap::Ptr p = crossCompartmentWrappers.lookup(key)) { *vp = p->value; if (vp->isObject()) { RootedObject obj(cx, &vp->toObject()); JS_ASSERT(obj->isCrossCompartmentWrapper()); if (obj->getParent() != global) { do { if (!JSObject::setParent(cx, obj, global)) return false; obj = obj->getProto(); } while (obj && obj->isCrossCompartmentWrapper()); } } return true; } if (vp->isString()) { RootedValue orig(cx, *vp); JSStableString *str = vp->toString()->ensureStable(cx); if (!str) return false; JSString *wrapped = js_NewStringCopyN(cx, str->chars(), str->length()); if (!wrapped) return false; vp->setString(wrapped); return crossCompartmentWrappers.put(orig, *vp); } RootedObject obj(cx, &vp->toObject()); /* * Recurse to wrap the prototype. Long prototype chains will run out of * stack, causing an error in CHECK_RECURSE. * * Wrapping the proto before creating the new wrapper and adding it to the * cache helps avoid leaving a bad entry in the cache on OOM. But note that * if we wrapped both proto and parent, we would get infinite recursion * here (since Object.prototype->parent->proto leads to Object.prototype * itself). */ RootedObject proto(cx, obj->getProto()); if (!wrap(cx, proto.address())) return false; /* * We hand in the original wrapped object into the wrap hook to allow * the wrap hook to reason over what wrappers are currently applied * to the object. */ RootedObject wrapper(cx, cx->runtime->wrapObjectCallback(cx, obj, proto, global, flags)); if (!wrapper) return false; // We maintain the invariant that the key in the cross-compartment wrapper // map is always directly wrapped by the value. JS_ASSERT(Wrapper::wrappedObject(wrapper) == &key.get().toObject()); vp->setObject(*wrapper); if (!crossCompartmentWrappers.put(key, *vp)) return false; return true; }