static bool CloneValue(JSContext *cx, HandleValue selfHostedValue, MutableHandleValue vp) { if (selfHostedValue.isObject()) { RootedObject selfHostedObject(cx, &selfHostedValue.toObject()); JSObject *clone = CloneObject(cx, selfHostedObject); if (!clone) return false; vp.setObject(*clone); } else if (selfHostedValue.isBoolean() || selfHostedValue.isNumber() || selfHostedValue.isNullOrUndefined()) { // Nothing to do here: these are represented inline in the value. vp.set(selfHostedValue); } else if (selfHostedValue.isString()) { if (!selfHostedValue.toString()->isFlat()) MOZ_CRASH(); JSFlatString *selfHostedString = &selfHostedValue.toString()->asFlat(); JSString *clone = js_NewStringCopyN<CanGC>(cx, selfHostedString->chars(), selfHostedString->length()); if (!clone) return false; vp.setString(clone); } else { MOZ_CRASH("Self-hosting CloneValue can't clone given value."); } return true; }
bool CreateThis(JSContext *cx, HandleObject callee, MutableHandleValue rval) { rval.set(MagicValue(JS_IS_CONSTRUCTING)); if (callee->isFunction()) { JSFunction *fun = callee->toFunction(); if (fun->isInterpreted()) { JSScript *script = fun->getOrCreateScript(cx); if (!script || !script->ensureHasTypes(cx)) return false; rval.set(ObjectValue(*CreateThisForFunction(cx, callee, false))); } } return true; }
/* * Wrapper forwards this call directly to the wrapped object for efficiency * and transparency. In particular, the hint is needed to properly stringify * Date objects in certain cases - see bug 646129. Note also the * SecurityWrapper overrides this trap to avoid information leaks. See bug * 720619. */ bool Wrapper::defaultValue(JSContext *cx, HandleObject proxy, JSType hint, MutableHandleValue vp) { vp.set(ObjectValue(*proxy->as<ProxyObject>().target())); if (hint == JSTYPE_VOID) return ToPrimitive(cx, vp); return ToPrimitive(cx, hint, vp); }
bool JavaScriptShared::toValue(JSContext *cx, const JSVariant &from, MutableHandleValue to) { switch (from.type()) { case JSVariant::Tvoid_t: to.set(UndefinedValue()); return true; case JSVariant::Tuint64_t: { ObjectId id = from.get_uint64_t(); if (id) { JSObject *obj = unwrap(cx, id); if (!obj) return false; to.set(ObjectValue(*obj)); } else { to.set(JSVAL_NULL); } return true; } case JSVariant::Tdouble: to.set(JS_NumberValue(from.get_double())); return true; case JSVariant::Tbool: to.set(BOOLEAN_TO_JSVAL(from.get_bool())); return true; case JSVariant::TnsString: { const nsString &old = from.get_nsString(); JSString *str = JS_NewUCStringCopyN(cx, old.BeginReading(), old.Length()); if (!str) return false; to.set(StringValue(str)); return true; } case JSVariant::TJSIID: { nsID iid; const JSIID &id = from.get_JSIID(); ConvertID(id, &iid); JSCompartment *compartment = GetContextCompartment(cx); RootedObject global(cx, JS_GetGlobalForCompartmentOrNull(cx, compartment)); JSObject *obj = xpc_NewIDObject(cx, global, iid); if (!obj) return false; to.set(ObjectValue(*obj)); return true; } default: return false; } }
static int32_t CoerceInPlace_ToInt32(JSContext *cx, MutableHandleValue val) { int32_t i32; if (!ToInt32(cx, val, &i32)) return false; val.set(Int32Value(i32)); return true; }
bool DebugState::getGlobal(Instance& instance, uint32_t globalIndex, MutableHandleValue vp) { const GlobalDesc& global = metadata().globals[globalIndex]; if (global.isConstant()) { Val value = global.constantValue(); switch (value.type()) { case ValType::I32: vp.set(Int32Value(value.i32())); break; case ValType::I64: // Just display as a Number; it's ok if we lose some precision vp.set(NumberValue((double)value.i64())); break; case ValType::F32: vp.set(NumberValue(JS::CanonicalizeNaN(value.f32()))); break; case ValType::F64: vp.set(NumberValue(JS::CanonicalizeNaN(value.f64()))); break; default: MOZ_CRASH("Global constant type"); } return true; } uint8_t* globalData = instance.globalData(); void* dataPtr = globalData + global.offset(); switch (global.type()) { case ValType::I32: { vp.set(Int32Value(*static_cast<int32_t*>(dataPtr))); break; } case ValType::I64: { // Just display as a Number; it's ok if we lose some precision vp.set(NumberValue((double)*static_cast<int64_t*>(dataPtr))); break; } case ValType::F32: { vp.set(NumberValue(JS::CanonicalizeNaN(*static_cast<float*>(dataPtr)))); break; } case ValType::F64: { vp.set(NumberValue(JS::CanonicalizeNaN(*static_cast<double*>(dataPtr)))); break; } default: MOZ_CRASH("Global variable type"); break; } return true; }
static int32_t CoerceInPlace_ToNumber(JSContext *cx, MutableHandleValue val) { double dbl; if (!ToNumber(cx, val, &dbl)) return false; val.set(DoubleValue(dbl)); return true; }
bool BaseProxyHandler::get(JSContext* cx, HandleObject proxy, HandleValue receiver, HandleId id, MutableHandleValue vp) const { assertEnteredPolicy(cx, proxy, id, GET); // This method is not covered by any spec, but we follow ES 2016 // (January 21, 2016) 9.1.8 fairly closely. // Step 2. (Step 1 is a superfluous assertion.) Rooted<PropertyDescriptor> desc(cx); if (!getOwnPropertyDescriptor(cx, proxy, id, &desc)) { return false; } desc.assertCompleteIfFound(); // Step 3. if (!desc.object()) { // The spec calls this variable "parent", but that word has weird // connotations in SpiderMonkey, so let's go with "proto". // Step 3.a. RootedObject proto(cx); if (!GetPrototype(cx, proxy, &proto)) { return false; } // Step 3.b. if (!proto) { vp.setUndefined(); return true; } // Step 3.c. return GetProperty(cx, proto, receiver, id, vp); } // Step 4. if (desc.isDataDescriptor()) { vp.set(desc.value()); return true; } // Step 5. MOZ_ASSERT(desc.isAccessorDescriptor()); RootedObject getter(cx, desc.getterObject()); // Step 6. if (!getter) { vp.setUndefined(); return true; } // Step 7. RootedValue getterFunc(cx, ObjectValue(*getter)); return CallGetter(cx, receiver, getterFunc, vp); }
bool CreateThis(JSContext *cx, HandleObject callee, MutableHandleValue rval) { rval.set(MagicValue(JS_IS_CONSTRUCTING)); if (callee->is<JSFunction>()) { JSFunction *fun = &callee->as<JSFunction>(); if (fun->isInterpretedConstructor()) { JSScript *script = fun->getOrCreateScript(cx); if (!script || !script->ensureHasTypes(cx)) return false; JSObject *thisObj = CreateThisForFunction(cx, callee, GenericObject); if (!thisObj) return false; rval.set(ObjectValue(*thisObj)); } } return true; }
bool FilteringWrapper<CrossCompartmentSecurityWrapper, GentlyOpaque> ::defaultValue(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp) { JSString *str = JS_NewStringCopyZ(cx, "[Opaque]"); if (!str) return false; vp.set(JS::StringValue(str)); return true; }
static bool ExportGlobalValue(JSContext* cx, const GlobalDescVector& globals, uint32_t globalIndex, const ValVector& globalImports, MutableHandleValue jsval) { const GlobalDesc& global = globals[globalIndex]; // Imports are located upfront in the globals array. Val val; switch (global.kind()) { case GlobalKind::Import: val = globalImports[globalIndex]; break; case GlobalKind::Variable: MOZ_CRASH("mutable variables can't be exported"); case GlobalKind::Constant: val = global.constantValue(); break; } switch (global.type()) { case ValType::I32: { jsval.set(Int32Value(val.i32())); return true; } case ValType::I64: { MOZ_ASSERT(JitOptions.wasmTestMode, "no int64 in asm.js/wasm"); RootedObject obj(cx, CreateI64Object(cx, val.i64())); if (!obj) return false; jsval.set(ObjectValue(*obj)); return true; } case ValType::F32: { jsval.set(DoubleValue(double(val.f32()))); return true; } case ValType::F64: { jsval.set(DoubleValue(val.f64())); return true; } default: { break; } } MOZ_CRASH("unexpected type when creating global exports"); }
static int32_t CoerceInPlace_ToNumber(MutableHandleValue val) { JSContext* cx = JSRuntime::innermostWasmActivation()->cx(); double dbl; if (!ToNumber(cx, val, &dbl)) return false; val.set(DoubleValue(dbl)); return true; }
static int32_t CoerceInPlace_ToInt32(MutableHandleValue val) { JSContext* cx = JSRuntime::innermostWasmActivation()->cx(); int32_t i32; if (!ToInt32(cx, val, &i32)) return false; val.set(Int32Value(i32)); return true; }
static bool env_setProperty(JSContext* cx, HandleObject obj, HandleId id, bool strict, MutableHandleValue vp) { /* XXX porting may be easy, but these don't seem to supply setenv by default */ #if !defined XP_OS2 && !defined SOLARIS JSString* valstr; JS::Rooted<JSString*> idstr(cx); int rv; RootedValue idval(cx); if (!JS_IdToValue(cx, id, &idval)) return false; idstr = ToString(cx, idval); valstr = ToString(cx, vp); if (!idstr || !valstr) return false; JSAutoByteString name(cx, idstr); if (!name) return false; JSAutoByteString value(cx, valstr); if (!value) return false; #if defined XP_WIN || defined HPUX || defined OSF1 || defined SCO { char* waste = JS_smprintf("%s=%s", name.ptr(), value.ptr()); if (!waste) { JS_ReportOutOfMemory(cx); return false; } rv = putenv(waste); #ifdef XP_WIN /* * HPUX9 at least still has the bad old non-copying putenv. * * Per mail from <*****@*****.**>, OSF1 also has a putenv * that will crash if you pass it an auto char array (so it must place * its argument directly in the char* environ[] array). */ free(waste); #endif } #else rv = setenv(name.ptr(), value.ptr(), 1); #endif if (rv < 0) { JS_ReportError(cx, "can't set envariable %s to %s", name.ptr(), value.ptr()); return false; } vp.set(STRING_TO_JSVAL(valstr)); #endif /* !defined XP_OS2 && !defined SOLARIS */ return true; }
bool JSAbstractFramePtr::getThisValue(JSContext *cx, MutableHandleValue thisv) { AbstractFramePtr frame(*this); RootedObject scopeChain(cx, frame.scopeChain()); js::AutoCompartment ac(cx, scopeChain); if (!ComputeThis(cx, frame)) return false; thisv.set(frame.thisValue()); return true; }
static bool MappedArgGetter(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp) { MappedArgumentsObject& argsobj = obj->as<MappedArgumentsObject>(); if (JSID_IS_INT(id)) { /* * arg can exceed the number of arguments if a script changed the * prototype to point to another Arguments object with a bigger argc. */ unsigned arg = unsigned(JSID_TO_INT(id)); if (arg < argsobj.initialLength() && !argsobj.isElementDeleted(arg)) vp.set(argsobj.element(arg)); } else if (JSID_IS_ATOM(id, cx->names().length)) { if (!argsobj.hasOverriddenLength()) vp.setInt32(argsobj.initialLength()); } else { MOZ_ASSERT(JSID_IS_ATOM(id, cx->names().callee)); if (!argsobj.callee().isMagic(JS_OVERWRITTEN_CALLEE)) vp.set(argsobj.callee()); } return true; }
static bool GetUnclonedValue(JSContext *cx, HandleNativeObject selfHostedObject, HandleId id, MutableHandleValue vp) { vp.setUndefined(); if (JSID_IS_INT(id)) { size_t index = JSID_TO_INT(id); if (index < selfHostedObject->getDenseInitializedLength() && !selfHostedObject->getDenseElement(index).isMagic(JS_ELEMENTS_HOLE)) { vp.set(selfHostedObject->getDenseElement(JSID_TO_INT(id))); return true; } } // Since all atoms used by self hosting are marked as permanent, any // attempt to look up a non-permanent atom will fail. We should only // see such atoms when code is looking for properties on the self // hosted global which aren't present. if (JSID_IS_STRING(id) && !JSID_TO_STRING(id)->isPermanentAtom()) { MOZ_ASSERT(selfHostedObject->is<GlobalObject>()); RootedValue value(cx, IdToValue(id)); return js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_NO_SUCH_SELF_HOSTED_PROP, JSDVG_IGNORE_STACK, value, NullPtr(), nullptr, nullptr); } RootedShape shape(cx, selfHostedObject->lookupPure(id)); if (!shape) { RootedValue value(cx, IdToValue(id)); return js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_NO_SUCH_SELF_HOSTED_PROP, JSDVG_IGNORE_STACK, value, NullPtr(), nullptr, nullptr); } MOZ_ASSERT(shape->hasSlot() && shape->hasDefaultGetter()); vp.set(selfHostedObject->getSlot(shape->slot())); return true; }
bool js::DirectEvalValueFromIon(JSContext *cx, HandleObject scopeobj, HandleScript callerScript, HandleValue thisValue, HandleValue evalArg, jsbytecode *pc, MutableHandleValue vp) { // Act as identity on non-strings per ES5 15.1.2.1 step 1. if (!evalArg.isString()) { vp.set(evalArg); return true; } RootedString string(cx, evalArg.toString()); return DirectEvalStringFromIon(cx, scopeobj, callerScript, thisValue, string, pc, vp); }
bool NonVoidStringToJsval(JSContext *cx, nsAString &str, MutableHandleValue rval) { nsStringBuffer* sharedBuffer; jsval jsstr = XPCStringConvert::ReadableToJSVal(cx, str, &sharedBuffer); if (JSVAL_IS_NULL(jsstr)) return false; rval.set(jsstr); if (sharedBuffer) { // The string was shared but ReadableToJSVal didn't addref it. // Move the ownership from str to jsstr. str.ForgetSharedBuffer(); } return true; }
bool MapObject::get(JSContext* cx, HandleObject obj, HandleValue key, MutableHandleValue rval) { ValueMap& map = extract(obj); Rooted<HashableValue> k(cx); if (!k.setValue(cx, key)) return false; if (ValueMap::Entry* p = map.get(k)) rval.set(p->value); else rval.setUndefined(); return true; }
bool Compare(JSContext *cx, HandleString src1, HandleString src2, MutableHandleValue rval) { nsresult rv; if (!mCollation) { nsCOMPtr<nsILocaleService> localeService = do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv); if (NS_SUCCEEDED(rv)) { nsCOMPtr<nsILocale> locale; rv = localeService->GetApplicationLocale(getter_AddRefs(locale)); if (NS_SUCCEEDED(rv)) { nsCOMPtr<nsICollationFactory> colFactory = do_CreateInstance(NS_COLLATIONFACTORY_CONTRACTID, &rv); if (NS_SUCCEEDED(rv)) { rv = colFactory->CreateCollation(locale, getter_AddRefs(mCollation)); } } } if (NS_FAILED(rv)) { xpc::Throw(cx, rv); return false; } } nsDependentJSString depStr1, depStr2; if (!depStr1.init(cx, src1) || !depStr2.init(cx, src2)) { return false; } int32_t result; rv = mCollation->CompareString(nsICollation::kCollationStrengthDefault, depStr1, depStr2, &result); if (NS_FAILED(rv)) { xpc::Throw(cx, rv); return false; } rval.set(INT_TO_JSVAL(result)); return true; }
JS::GetWeakMapEntry(JSContext *cx, HandleObject mapObj, HandleObject key, MutableHandleValue rval) { CHECK_REQUEST(cx); assertSameCompartment(cx, key); rval.setUndefined(); ObjectValueMap *map = mapObj->as<WeakMapObject>().getMap(); if (!map) return true; if (ObjectValueMap::Ptr ptr = map->lookup(key)) { // Read barrier to prevent an incorrectly gray value from escaping the // weak map. See the comment before UnmarkGrayChildren in gc/Marking.cpp ExposeValueToActiveJS(ptr->value().get()); rval.set(ptr->value()); } return true; }
NS_IMETHODIMP nsJSCID::GetService(HandleValue iidval, JSContext* cx, uint8_t optionalArgc, MutableHandleValue retval) { if (!mDetails->IsValid()) return NS_ERROR_XPC_BAD_CID; if (NS_FAILED(nsXPConnect::SecurityManager()->CanCreateInstance(cx, mDetails->ID()))) { MOZ_ASSERT(JS_IsExceptionPending(cx), "security manager vetoed GetService without setting exception"); return NS_OK; } // If an IID was passed in then use it const nsID* iid = GetIIDArg(optionalArgc, iidval, cx); if (!iid) return NS_ERROR_XPC_BAD_IID; nsCOMPtr<nsIServiceManager> svcMgr; nsresult rv = NS_GetServiceManager(getter_AddRefs(svcMgr)); if (NS_FAILED(rv)) return rv; nsCOMPtr<nsISupports> srvc; rv = svcMgr->GetService(mDetails->ID(), *iid, getter_AddRefs(srvc)); MOZ_ASSERT(NS_FAILED(rv) || srvc, "service manager returned success, but service is null!"); #ifdef DEBUG if (NS_FAILED(rv)) { nsAutoCString details; mDetails->ToString (getter_Copies(details)); NS_WARNING(nsPrintfCString("service manager returned %X from GetService for class '%s' (%s)", rv, details.get(), mDetails->ID().ToString()).get()); } #endif if (NS_FAILED(rv) || !srvc) return NS_ERROR_XPC_GS_RETURNED_FAILURE; RootedValue v(cx); rv = nsContentUtils::WrapNative(cx, srvc, iid, &v); if (NS_FAILED(rv) || !v.isObject()) return NS_ERROR_XPC_CANT_CREATE_WN; retval.set(v); return NS_OK; }
static EvalJSONResult TryEvalJSON(JSContext *cx, JSScript *callerScript, ConstTwoByteChars chars, size_t length, MutableHandleValue rval) { // If the eval string starts with '(' or '[' and ends with ')' or ']', it may be JSON. // Try the JSON parser first because it's much faster. If the eval string // isn't JSON, JSON parsing will probably fail quickly, so little time // will be lost. // // Don't use the JSON parser if the caller is strict mode code, because in // strict mode object literals must not have repeated properties, and the // JSON parser cheerfully (and correctly) accepts them. If you're parsing // JSON with eval and using strict mode, you deserve to be slow. if (length > 2 && ((chars[0] == '[' && chars[length - 1] == ']') || (chars[0] == '(' && chars[length - 1] == ')')) && (!callerScript || !callerScript->strict())) { // Remarkably, JavaScript syntax is not a superset of JSON syntax: // strings in JavaScript cannot contain the Unicode line and paragraph // terminator characters U+2028 and U+2029, but strings in JSON can. // Rather than force the JSON parser to handle this quirk when used by // eval, we simply don't use the JSON parser when either character // appears in the provided string. See bug 657367. for (const jschar *cp = &chars[1], *end = &chars[length - 2]; ; cp++) { if (*cp == 0x2028 || *cp == 0x2029) break; if (cp == end) { bool isArray = (chars[0] == '['); JSONParser parser(cx, isArray ? chars : chars + 1U, isArray ? length : length - 2, JSONParser::NoError); RootedValue tmp(cx); if (!parser.parse(&tmp)) return EvalJSON_Failure; if (tmp.isUndefined()) return EvalJSON_NotJSON; rval.set(tmp); return EvalJSON_Success; } } } return EvalJSON_NotJSON; }
static bool GetDataProperty(JSContext *cx, const Value &objVal, HandlePropertyName field, MutableHandleValue v) { if (!objVal.isObject()) return LinkFail(cx, "accessing property of non-object"); JSPropertyDescriptor desc; if (!JS_GetPropertyDescriptorById(cx, &objVal.toObject(), NameToId(field), 0, &desc)) return false; if (!desc.obj) return LinkFail(cx, "property not present on object"); if (desc.attrs & (JSPROP_GETTER | JSPROP_SETTER)) return LinkFail(cx, "property is not a data property"); v.set(desc.value); return true; }
static bool GetDataProperty(JSContext *cx, const Value &objVal, HandlePropertyName field, MutableHandleValue v) { if (!objVal.isObject()) return LinkFail(cx, "accessing property of non-object"); Rooted<JSPropertyDescriptor> desc(cx); if (!JS_GetPropertyDescriptorById(cx, &objVal.toObject(), NameToId(field), 0, &desc)) return false; if (!desc.object()) return LinkFail(cx, "property not present on object"); if (desc.hasGetterOrSetterObject()) return LinkFail(cx, "property is not a data property"); v.set(desc.value()); return true; }
bool ArrayShiftDense(JSContext *cx, HandleObject obj, MutableHandleValue rval) { JS_ASSERT(obj->is<ArrayObject>()); AutoDetectInvalidation adi(cx, rval.address()); Value argv[] = { UndefinedValue(), ObjectValue(*obj) }; AutoValueArray ava(cx, argv, 2); if (!js::array_shift(cx, 0, argv)) return false; // If the result is |undefined|, the array was probably empty and we // have to monitor the return value. rval.set(argv[0]); if (rval.isUndefined()) types::TypeScript::Monitor(cx, rval); return true; }
void JS_FASTCALL stubs::ToId(VMFrame &f) { HandleValue objval = HandleValue::fromMarkedLocation(&f.regs.sp[-2]); MutableHandleValue idval = MutableHandleValue::fromMarkedLocation(&f.regs.sp[-1]); JSObject *obj = ToObjectFromStack(f.cx, objval); if (!obj) THROW(); RootedId id(f.cx); if (!ValueToId<CanGC>(f.cx, idval, &id)) THROW(); idval.set(IdToValue(id)); if (!idval.isInt32()) { RootedScript fscript(f.cx, f.script()); TypeScript::MonitorUnknown(f.cx, fscript, f.pc()); } }
bool JSRuntime::cloneSelfHostedValue(JSContext *cx, HandlePropertyName name, MutableHandleValue vp) { RootedId id(cx, NameToId(name)); RootedValue selfHostedValue(cx); if (!GetUnclonedValue(cx, HandleObject::fromMarkedLocation(&selfHostingGlobal_), id, &selfHostedValue)) return false; /* * We don't clone if we're operating in the self-hosting global, as that * means we're currently executing the self-hosting script while * initializing the runtime (see JSRuntime::initSelfHosting). */ if (cx->global() == selfHostingGlobal_) { vp.set(selfHostedValue); return true; } return CloneValue(cx, selfHostedValue, vp); }
bool ArrayPopDense(JSContext *cx, HandleObject obj, MutableHandleValue rval) { JS_ASSERT(obj->is<ArrayObject>()); AutoDetectInvalidation adi(cx, rval.address()); JS::AutoValueArray<2> argv(cx); argv[0].setUndefined(); argv[1].setObject(*obj); if (!js::array_pop(cx, 0, argv.begin())) return false; // If the result is |undefined|, the array was probably empty and we // have to monitor the return value. rval.set(argv[0]); if (rval.isUndefined()) types::TypeScript::Monitor(cx, rval); return true; }