MOZ_ALWAYS_INLINE bool bool_toSource_impl(JSContext *cx, CallArgs args) { HandleValue thisv = args.thisv(); JS_ASSERT(IsBoolean(thisv)); bool b = thisv.isBoolean() ? thisv.toBoolean() : thisv.toObject().as<BooleanObject>().unbox(); StringBuffer sb(cx); if (!sb.append("(new Boolean(") || !BooleanToStringBuffer(b, sb) || !sb.append("))")) return false; JSString *str = sb.finishString(); if (!str) return false; args.rval().setString(str); return true; }
bool SetIteratorObject::next_impl(JSContext* cx, const CallArgs& args) { SetIteratorObject& thisobj = args.thisv().toObject().as<SetIteratorObject>(); ValueSet::Range* range = thisobj.range(); RootedValue value(cx); bool done; if (!range || range->empty()) { js_delete(range); thisobj.setReservedSlot(RangeSlot, PrivateValue(nullptr)); value.setUndefined(); done = true; } else { switch (thisobj.kind()) { case SetObject::Values: value = range->front().get(); break; case SetObject::Entries: { JS::AutoValueArray<2> pair(cx); pair[0].set(range->front().get()); pair[1].set(range->front().get()); JSObject* pairObj = NewDenseCopiedArray(cx, 2, pair.begin()); if (!pairObj) return false; value.setObject(*pairObj); break; } } range->popFront(); done = false; } RootedObject result(cx, CreateItrResultObject(cx, value, done)); if (!result) return false; args.rval().setObject(*result); return true; }
/* ES5 15.2.4.7. */ static bool obj_propertyIsEnumerable(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); /* Step 1. */ RootedId id(cx); if (!ValueToId<CanGC>(cx, args.get(0), &id)) return false; /* Step 2. */ RootedObject obj(cx, ToObject(cx, args.thisv())); if (!obj) return false; /* Steps 3. */ RootedObject pobj(cx); RootedShape prop(cx); if (!JSObject::lookupGeneric(cx, obj, id, &pobj, &prop)) return false; /* Step 4. */ if (!prop) { args.rval().setBoolean(false); return true; } if (pobj != obj) { vp->setBoolean(false); return true; } /* Step 5. */ unsigned attrs; if (!JSObject::getGenericAttributes(cx, pobj, id, &attrs)) return false; args.rval().setBoolean((attrs & JSPROP_ENUMERATE) != 0); return true; }
static JSBool WeakMap_set(JSContext *cx, uintN argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); bool ok; JSObject *obj = NonGenericMethodGuard(cx, args, WeakMap_set, &WeakMapClass, &ok); if (!obj) return ok; if (args.length() < 1) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED, "WeakMap.set", "0", "s"); return false; } JSObject *key = NonNullObject(cx, &args[0]); if (!key) return false; Value value = (args.length() > 1) ? args[1] : UndefinedValue(); ObjectValueMap *map = GetObjectMap(obj); if (!map) { map = cx->new_<ObjectValueMap>(cx); if (!map->init()) { cx->delete_(map); goto out_of_memory; } obj->setPrivate(map); } args.thisv() = UndefinedValue(); if (!map->put(key, value)) goto out_of_memory; return true; out_of_memory: JS_ReportOutOfMemory(cx); return false; }
/* ES5 15.2.4.6. */ static bool obj_isPrototypeOf(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); /* Step 1. */ if (args.length() < 1 || !args[0].isObject()) { args.rval().setBoolean(false); return true; } /* Step 2. */ RootedObject obj(cx, ToObject(cx, args.thisv())); if (!obj) return false; /* Step 3. */ bool isDelegate; if (!IsDelegate(cx, obj, args[0], &isDelegate)) return false; args.rval().setBoolean(isDelegate); return true; }
static bool XPC_WN_Shared_toPrimitive(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); RootedObject obj(cx); if (!JS_ValueToObject(cx, args.thisv(), &obj)) return false; XPCCallContext ccx(cx, obj); XPCWrappedNative* wrapper = ccx.GetWrapper(); THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); JSType hint; if (!GetFirstArgumentAsTypeHint(cx, args, &hint)) return false; if (hint == JSTYPE_NUMBER) { args.rval().set(JS_GetNaNValue(cx)); return true; } MOZ_ASSERT(hint == JSTYPE_STRING || hint == JSTYPE_VOID); ccx.SetName(ccx.GetContext()->GetStringID(XPCJSContext::IDX_TO_STRING)); ccx.SetArgsAndResultPtr(0, nullptr, args.rval().address()); XPCNativeMember* member = ccx.GetMember(); if (member && member->IsMethod()) { if (!XPCWrappedNative::CallMethod(ccx)) return false; if (args.rval().isPrimitive()) return true; } // else... return ToStringGuts(ccx); }
bool MapObject::delete_impl(JSContext *cx, const CallArgs& args) { // MapObject::mark does not mark deleted entries. Incremental GC therefore // requires that no HeapPtr<Value> objects pointing to heap values be left // alive in the ValueMap. // // OrderedHashMap::remove() doesn't destroy the removed entry. It merely // calls OrderedHashMap::MapOps::makeEmpty. But that is sufficient, because // makeEmpty clears the value by doing e->value = Value(), and in the case // of a ValueMap, Value() means HeapPtr<Value>(), which is the same as // HeapPtr<Value>(UndefinedValue()). MOZ_ASSERT(MapObject::is(args.thisv())); ValueMap& map = extract(args); ARG0_KEY(cx, args, key); bool found; if (!map.remove(key, &found)) { ReportOutOfMemory(cx); return false; } args.rval().setBoolean(found); return true; }
static bool ModuleValueGetterImpl(JSContext* cx, CallArgs args) { args.rval().set(ValueGetter(&args.thisv().toObject().as<T>())); return true; }
if (!str) return false; args.rval().setString(str); return true; } /* ES5 15.2.4.3. */ static bool obj_toLocaleString(JSContext *cx, unsigned argc, Value *vp) { JS_CHECK_RECURSION(cx, return false); CallArgs args = CallArgsFromVp(argc, vp); /* Step 1. */ RootedObject obj(cx, ToObject(cx, args.thisv())); if (!obj) return false; /* Steps 2-4. */ RootedId id(cx, NameToId(cx->names().toString)); return obj->callMethod(cx, id, 0, nullptr, args.rval()); } static bool obj_valueOf(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); RootedObject obj(cx, ToObject(cx, args.thisv())); if (!obj) return false;
bool MapObject::iterator_impl(JSContext* cx, const CallArgs& args, IteratorKind kind) { RootedObject obj(cx, &args.thisv().toObject()); return iterator(cx, kind, obj, args.rval()); }
bool MapObject::get_impl(JSContext* cx, const CallArgs& args) { RootedObject obj(cx, &args.thisv().toObject()); return get(cx, obj, args.get(0), args.rval()); }
/* * Return a string that may eval to something similar to the original object. */ static bool exn_toSource(JSContext* cx, unsigned argc, Value* vp) { if (!CheckRecursionLimit(cx)) return false; CallArgs args = CallArgsFromVp(argc, vp); RootedObject obj(cx, ToObject(cx, args.thisv())); if (!obj) return false; RootedValue nameVal(cx); RootedString name(cx); if (!GetProperty(cx, obj, obj, cx->names().name, &nameVal) || !(name = ToString<CanGC>(cx, nameVal))) { return false; } RootedValue messageVal(cx); RootedString message(cx); if (!GetProperty(cx, obj, obj, cx->names().message, &messageVal) || !(message = ValueToSource(cx, messageVal))) { return false; } RootedValue filenameVal(cx); RootedString filename(cx); if (!GetProperty(cx, obj, obj, cx->names().fileName, &filenameVal) || !(filename = ValueToSource(cx, filenameVal))) { return false; } RootedValue linenoVal(cx); uint32_t lineno; if (!GetProperty(cx, obj, obj, cx->names().lineNumber, &linenoVal) || !ToUint32(cx, linenoVal, &lineno)) { return false; } StringBuffer sb(cx); if (!sb.append("(new ") || !sb.append(name) || !sb.append("(")) return false; if (!sb.append(message)) return false; if (!filename->empty()) { if (!sb.append(", ") || !sb.append(filename)) return false; } if (lineno != 0) { /* We have a line, but no filename, add empty string */ if (filename->empty() && !sb.append(", \"\"")) return false; JSString* linenumber = ToString<CanGC>(cx, linenoVal); if (!linenumber) return false; if (!sb.append(", ") || !sb.append(linenumber)) return false; } if (!sb.append("))")) return false; JSString* str = sb.finishString(); if (!str) return false; args.rval().setString(str); return true; }
static bool ProtoSetterImpl(JSContext *cx, CallArgs args) { JS_ASSERT(TestProtoSetterThis(args.thisv())); HandleValue thisv = args.thisv(); if (thisv.isPrimitive()) { JS_ASSERT(!thisv.isNullOrUndefined()); // Mutating a boxed primitive's [[Prototype]] has no side effects. args.rval().setUndefined(); return true; } if (!cx->runningWithTrustedPrincipals()) ++sSetProtoCalled; Rooted<JSObject*> obj(cx, &args.thisv().toObject()); /* ES5 8.6.2 forbids changing [[Prototype]] if not [[Extensible]]. */ bool extensible; if (!JSObject::isExtensible(cx, obj, &extensible)) return false; if (!extensible) { obj->reportNotExtensible(cx); return false; } /* * Disallow mutating the [[Prototype]] of a proxy that wasn't simply * wrapping some other object. Also disallow it on ArrayBuffer objects, * which due to their complicated delegate-object shenanigans can't easily * have a mutable [[Prototype]]. */ if (obj->is<ProxyObject>() || obj->is<ArrayBufferObject>()) { JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO, "Object", "__proto__ setter", obj->is<ProxyObject>() ? "Proxy" : "ArrayBuffer"); return false; } /* Do nothing if __proto__ isn't being set to an object or null. */ if (args.length() == 0 || !args[0].isObjectOrNull()) { args.rval().setUndefined(); return true; } Rooted<JSObject*> newProto(cx, args[0].toObjectOrNull()); unsigned dummy; RootedId nid(cx, NameToId(cx->names().proto)); RootedValue v(cx); if (!CheckAccess(cx, obj, nid, JSAccessMode(JSACC_PROTO | JSACC_WRITE), &v, &dummy)) return false; if (!SetClassAndProto(cx, obj, obj->getClass(), newProto, true)) return false; args.rval().setUndefined(); return true; }
static bool obj_toSource(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); JS_CHECK_RECURSION(cx, return false); RootedObject obj(cx, ToObject(cx, args.thisv())); if (!obj) return false; /* If outermost, we need parentheses to be an expression, not a block. */ bool outermost = (cx->cycleDetectorSet.count() == 0); AutoCycleDetector detector(cx, obj); if (!detector.init()) return false; if (detector.foundCycle()) { JSString *str = js_NewStringCopyZ<CanGC>(cx, "{}"); if (!str) return false; args.rval().setString(str); return true; } StringBuffer buf(cx); if (outermost && !buf.append('(')) return false; if (!buf.append('{')) return false; RootedValue v0(cx), v1(cx); MutableHandleValue val[2] = {&v0, &v1}; RootedString str0(cx), str1(cx); MutableHandleString gsop[2] = {&str0, &str1}; AutoIdVector idv(cx); if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, &idv)) return false; bool comma = false; for (size_t i = 0; i < idv.length(); ++i) { RootedId id(cx, idv[i]); RootedObject obj2(cx); RootedShape shape(cx); if (!JSObject::lookupGeneric(cx, obj, id, &obj2, &shape)) return false; /* Decide early whether we prefer get/set or old getter/setter syntax. */ int valcnt = 0; if (shape) { bool doGet = true; if (obj2->isNative() && !IsImplicitDenseElement(shape)) { unsigned attrs = shape->attributes(); if (attrs & JSPROP_GETTER) { doGet = false; val[valcnt].set(shape->getterValue()); gsop[valcnt].set(cx->names().get); valcnt++; } if (attrs & JSPROP_SETTER) { doGet = false; val[valcnt].set(shape->setterValue()); gsop[valcnt].set(cx->names().set); valcnt++; } } if (doGet) { valcnt = 1; gsop[0].set(NULL); if (!JSObject::getGeneric(cx, obj, obj, id, val[0])) return false; } } /* Convert id to a linear string. */ RootedValue idv(cx, IdToValue(id)); JSString *s = ToString<CanGC>(cx, idv); if (!s) return false; Rooted<JSLinearString*> idstr(cx, s->ensureLinear(cx)); if (!idstr) return false; /* * If id is a string that's not an identifier, or if it's a negative * integer, then it must be quoted. */ if (JSID_IS_ATOM(id) ? !IsIdentifier(idstr) : (!JSID_IS_INT(id) || JSID_TO_INT(id) < 0)) { s = js_QuoteString(cx, idstr, jschar('\'')); if (!s || !(idstr = s->ensureLinear(cx))) return false; } for (int j = 0; j < valcnt; j++) { /* * Censor an accessor descriptor getter or setter part if it's * undefined. */ if (gsop[j] && val[j].isUndefined()) continue; /* Convert val[j] to its canonical source form. */ RootedString valstr(cx, ValueToSource(cx, val[j])); if (!valstr) return false; const jschar *vchars = valstr->getChars(cx); if (!vchars) return false; size_t vlength = valstr->length(); /* * Remove '(function ' from the beginning of valstr and ')' from the * end so that we can put "get" in front of the function definition. */ if (gsop[j] && IsFunctionObject(val[j])) { const jschar *start = vchars; const jschar *end = vchars + vlength; uint8_t parenChomp = 0; if (vchars[0] == '(') { vchars++; parenChomp = 1; } /* Try to jump "function" keyword. */ if (vchars) vchars = js_strchr_limit(vchars, ' ', end); /* * Jump over the function's name: it can't be encoded as part * of an ECMA getter or setter. */ if (vchars) vchars = js_strchr_limit(vchars, '(', end); if (vchars) { if (*vchars == ' ') vchars++; vlength = end - vchars - parenChomp; } else { gsop[j].set(NULL); vchars = start; } } if (comma && !buf.append(", ")) return false; comma = true; if (gsop[j]) if (!buf.append(gsop[j]) || !buf.append(' ')) return false; if (!buf.append(idstr)) return false; if (!buf.append(gsop[j] ? ' ' : ':')) return false; if (!buf.append(vchars, vlength)) return false; } } if (!buf.append('}')) return false; if (outermost && !buf.append(')')) return false; JSString *str = buf.finishString(); if (!str) return false; args.rval().setString(str); return true; }
static bool GetLocationProperty(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); if (!args.thisv().isObject()) { JS_ReportError(cx, "Unexpected this value for GetLocationProperty"); return false; } #if !defined(XP_WIN) && !defined(XP_UNIX) //XXX: your platform should really implement this return false; #else JS::AutoFilename filename; if (JS::DescribeScriptedCaller(cx, &filename) && filename.get()) { nsresult rv; nsCOMPtr<nsIXPConnect> xpc = do_GetService(kXPConnectServiceContractID, &rv); #if defined(XP_WIN) // convert from the system codepage to UTF-16 int bufferSize = MultiByteToWideChar(CP_ACP, 0, filename.get(), -1, nullptr, 0); nsAutoString filenameString; filenameString.SetLength(bufferSize); MultiByteToWideChar(CP_ACP, 0, filename.get(), -1, (LPWSTR)filenameString.BeginWriting(), filenameString.Length()); // remove the null terminator filenameString.SetLength(bufferSize - 1); // replace forward slashes with backslashes, // since nsLocalFileWin chokes on them char16_t* start = filenameString.BeginWriting(); char16_t* end = filenameString.EndWriting(); while (start != end) { if (*start == L'/') *start = L'\\'; start++; } #elif defined(XP_UNIX) NS_ConvertUTF8toUTF16 filenameString(filename.get()); #endif nsCOMPtr<nsIFile> location; if (NS_SUCCEEDED(rv)) { rv = NS_NewLocalFile(filenameString, false, getter_AddRefs(location)); } if (!location && gWorkingDirectory) { // could be a relative path, try appending it to the cwd // and then normalize nsAutoString absolutePath(*gWorkingDirectory); absolutePath.Append(filenameString); rv = NS_NewLocalFile(absolutePath, false, getter_AddRefs(location)); } if (location) { nsCOMPtr<nsIXPConnectJSObjectHolder> locationHolder; bool symlink; // don't normalize symlinks, because that's kind of confusing if (NS_SUCCEEDED(location->IsSymlink(&symlink)) && !symlink) location->Normalize(); rv = xpc->WrapNative(cx, &args.thisv().toObject(), location, NS_GET_IID(nsIFile), getter_AddRefs(locationHolder)); if (NS_SUCCEEDED(rv) && locationHolder->GetJSObject()) { args.rval().setObject(*locationHolder->GetJSObject()); } } } return true; #endif }
if (!str) return false; args.rval().setString(str); return true; } /* ES5 15.2.4.3. */ static JSBool obj_toLocaleString(JSContext *cx, unsigned argc, Value *vp) { JS_CHECK_RECURSION(cx, return false); CallArgs args = CallArgsFromVp(argc, vp); /* Step 1. */ JSObject *obj = ToObject(cx, args.thisv()); if (!obj) return false; /* Steps 2-4. */ RootedId id(cx, NameToId(cx->names().toString)); return obj->callMethod(cx, id, 0, NULL, args.rval()); } static JSBool obj_valueOf(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); JSObject *obj = ToObject(cx, args.thisv()); if (!obj) return false;