Example #1
0
/*
 * Convert string indexes that convert to int jsvals as ints to save memory.
 * Care must be taken to use this macro every time a property name is used, or
 * else double-sets, incorrect property cache misses, or other mistakes could
 * occur.
 */
jsid
js_CheckForStringIndex(jsid id)
{
    if (!JSID_IS_ATOM(id))
        return id;

    JSAtom *atom = JSID_TO_ATOM(id);
    const jschar *s = atom->chars();
    jschar ch = *s;

    JSBool negative = (ch == '-');
    if (negative)
        ch = *++s;

    if (!JS7_ISDEC(ch))
        return id;

    size_t n = atom->length() - negative;
    if (n > sizeof(JSBOXEDWORD_INT_MAX_STRING) - 1)
        return id;

    const jschar *cp = s;
    const jschar *end = s + n;

    jsuint index = JS7_UNDEC(*cp++);
    jsuint oldIndex = 0;
    jsuint c = 0;

    if (index != 0) {
        while (JS7_ISDEC(*cp)) {
            oldIndex = index;
            c = JS7_UNDEC(*cp);
            index = 10 * index + c;
            cp++;
        }
    }

    /*
     * Non-integer indexes can't be represented as integers.  Also, distinguish
     * index "-0" from "0", because JSBOXEDWORD_INT cannot.
     */
    if (cp != end || (negative && index == 0))
        return id;

    if (negative) {
        if (oldIndex < -(JSID_INT_MIN / 10) ||
            (oldIndex == -(JSID_INT_MIN / 10) && c <= (-JSID_INT_MIN % 10)))
        {
            id = INT_TO_JSID(-jsint(index));
        }
    } else {
        if (oldIndex < JSID_INT_MAX / 10 ||
            (oldIndex == JSID_INT_MAX / 10 && c <= (JSID_INT_MAX % 10)))
        {
            id = INT_TO_JSID(jsint(index));
        }
    }

    return id;
}
Example #2
0
Symbol*
Symbol::for_(js::ExclusiveContext* cx, HandleString description)
{
    JSAtom* atom = AtomizeString(cx, description);
    if (!atom)
        return nullptr;

    AutoLockForExclusiveAccess lock(cx);

    SymbolRegistry& registry = cx->symbolRegistry(lock);
    SymbolRegistry::AddPtr p = registry.lookupForAdd(atom);
    if (p)
        return *p;

    AutoCompartment ac(cx, cx->atomsCompartment(lock), &lock);
    Symbol* sym = newInternal(cx, SymbolCode::InSymbolRegistry, atom->hash(), atom, lock);
    if (!sym)
        return nullptr;

    // p is still valid here because we have held the lock since the
    // lookupForAdd call, and newInternal can't GC.
    if (!registry.add(p, sym)) {
        // SystemAllocPolicy does not report OOM.
        ReportOutOfMemory(cx);
        return nullptr;
    }
    return sym;
}
Example #3
0
void
GetDynamicName(JSContext *cx, JSObject *scopeChain, JSString *str, Value *vp)
{
    // Lookup a string on the scope chain, returning either the value found or
    // undefined through rval. This function is infallible, and cannot GC or
    // invalidate.

    JSAtom *atom;
    if (str->isAtom()) {
        atom = &str->asAtom();
    } else {
        atom = AtomizeString(cx, str);
        if (!atom) {
            vp->setUndefined();
            return;
        }
    }

    if (!frontend::IsIdentifier(atom) || frontend::IsKeyword(atom)) {
        vp->setUndefined();
        return;
    }

    Shape *shape = nullptr;
    JSObject *scope = nullptr, *pobj = nullptr;
    if (LookupNameNoGC(cx, atom->asPropertyName(), scopeChain, &scope, &pobj, &shape)) {
        if (FetchNameNoGC(pobj, shape, MutableHandleValue::fromMarkedLocation(vp)))
            return;
    }

    vp->setUndefined();
}
Example #4
0
JSFlatString *
RegExpObject::toString(JSContext *cx) const
{
    JSAtom *src = getSource();
    StringBuffer sb(cx);
    if (size_t len = src->length()) {
        if (!sb.reserve(len + 2))
            return NULL;
        sb.infallibleAppend('/');
        sb.infallibleAppend(src->chars(), len);
        sb.infallibleAppend('/');
    } else {
        if (!sb.append("/(?:)/"))
            return NULL;
    }
    if (global() && !sb.append('g'))
        return NULL;
    if (ignoreCase() && !sb.append('i'))
        return NULL;
    if (multiline() && !sb.append('m'))
        return NULL;
    if (sticky() && !sb.append('y'))
        return NULL;

    return sb.finishString();
}
Example #5
0
/* static */ bool
SavedFrame::HashPolicy::match(SavedFrame *existing, const Lookup &lookup)
{
    if (existing->getLine() != lookup.line)
        return false;

    if (existing->getColumn() != lookup.column)
        return false;

    if (existing->getParent() != lookup.parent)
        return false;

    if (existing->getPrincipals() != lookup.principals)
        return false;

    JSAtom *source = existing->getSource();
    if (source->length() != lookup.source->length())
        return false;
    if (source != lookup.source)
        return false;

    JSAtom *functionDisplayName = existing->getFunctionDisplayName();
    if (functionDisplayName) {
        if (!lookup.functionDisplayName)
            return false;
        if (functionDisplayName->length() != lookup.functionDisplayName->length())
            return false;
        if (0 != CompareAtoms(functionDisplayName, lookup.functionDisplayName))
            return false;
    } else if (lookup.functionDisplayName) {
        return false;
    }

    return true;
}
Example #6
0
/*
 * Serializes the script/function pair into a "descriptive string" which is
 * allowed to fail. This function cannot trigger a GC because it could finalize
 * some scripts, resize the hash table of profile strings, and invalidate the
 * AddPtr held while invoking allocProfileString.
 */
const char*
SPSProfiler::allocProfileString(JSScript* script, JSFunction* maybeFun)
{
    // Note: this profiler string is regexp-matched by
    // browser/devtools/profiler/cleopatra/js/parserWorker.js.

    // Get the function name, if any.
    JSAtom* atom = maybeFun ? maybeFun->displayAtom() : nullptr;

    // Get the script filename, if any, and its length.
    const char* filename = script->filename();
    if (filename == nullptr)
        filename = "<unknown>";
    size_t lenFilename = strlen(filename);

    // Get the line number and its length as a string.
    uint64_t lineno = script->lineno();
    size_t lenLineno = 1;
    for (uint64_t i = lineno; i /= 10; lenLineno++);

    // Determine the required buffer size.
    size_t len = lenFilename + lenLineno + 1; // +1 for the ":" separating them.
    if (atom) {
        len += JS::GetDeflatedUTF8StringLength(atom) + 3; // +3 for the " (" and ")" it adds.
    }

    // Allocate the buffer.
    char* cstr = js_pod_malloc<char>(len + 1);
    if (cstr == nullptr)
        return nullptr;

    // Construct the descriptive string.
    DebugOnly<size_t> ret;
    if (atom) {
        JS::AutoCheckCannotGC nogc;
        auto atomStr = mozilla::UniquePtr<char, JS::FreePolicy>(
            atom->hasLatin1Chars()
            ? JS::CharsToNewUTF8CharsZ(nullptr, atom->latin1Range(nogc)).c_str()
            : JS::CharsToNewUTF8CharsZ(nullptr, atom->twoByteRange(nogc)).c_str());
        if (!atomStr)
            return nullptr;
        ret = JS_snprintf(cstr, len + 1, "%s (%s:%llu)", atomStr.get(), filename, lineno);
    } else {
        ret = JS_snprintf(cstr, len + 1, "%s:%llu", filename, lineno);
    }

    MOZ_ASSERT(ret == len, "Computed length should match actual length!");

    return cstr;
}
Example #7
0
/* static */ bool
ArgumentsObject::obj_mayResolve(const JSAtomState& names, jsid id, JSObject*)
{
    // Arguments might resolve indexes, Symbol.iterator, or length/callee.
    if (JSID_IS_ATOM(id)) {
        JSAtom* atom = JSID_TO_ATOM(id);
        uint32_t index;
        if (atom->isIndex(&index))
            return true;
        return atom == names.length || atom == names.callee;
    }
    if (JSID_IS_SYMBOL(id))
        return JSID_TO_SYMBOL(id)->code() == JS::SymbolCode::iterator;
    return true;
}
Example #8
0
bool
JSRuntime::initializeAtoms(JSContext *cx)
{
    atoms_ = cx->new_<AtomSet>();
    if (!atoms_ || !atoms_->init(JS_STRING_HASH_COUNT))
        return false;

    if (parentRuntime) {
        staticStrings = parentRuntime->staticStrings;
        commonNames = parentRuntime->commonNames;
        emptyString = parentRuntime->emptyString;
        permanentAtoms = parentRuntime->permanentAtoms;
        return true;
    }

    permanentAtoms = cx->new_<AtomSet>();
    if (!permanentAtoms || !permanentAtoms->init(JS_STRING_HASH_COUNT))
        return false;

    staticStrings = cx->new_<StaticStrings>();
    if (!staticStrings || !staticStrings->init(cx))
        return false;

    static const CommonNameInfo cachedNames[] = {
#define COMMON_NAME_INFO(idpart, id, text) { js_##idpart##_str, sizeof(text) - 1 },
        FOR_EACH_COMMON_PROPERTYNAME(COMMON_NAME_INFO)
#undef COMMON_NAME_INFO
#define COMMON_NAME_INFO(name, code, init, clasp) { js_##name##_str, sizeof(#name) - 1 },
        JS_FOR_EACH_PROTOTYPE(COMMON_NAME_INFO)
#undef COMMON_NAME_INFO
    };

    commonNames = cx->new_<JSAtomState>();
    if (!commonNames)
        return false;

    FixedHeapPtr<PropertyName> *names = reinterpret_cast<FixedHeapPtr<PropertyName> *>(commonNames);
    for (size_t i = 0; i < ArrayLength(cachedNames); i++, names++) {
        JSAtom *atom = Atomize(cx, cachedNames[i].str, cachedNames[i].length, InternAtom);
        if (!atom)
            return false;
        names->init(atom->asPropertyName());
    }
    JS_ASSERT(uintptr_t(names) == uintptr_t(commonNames + 1));

    emptyString = commonNames->empty;
    return true;
}
Example #9
0
uint32_t
GetIndexFromString(JSString *str)
{
    // Masks the return value UINT32_MAX as failure to get the index.
    // I.e. it is impossible to distinguish between failing to get the index
    // or the actual index UINT32_MAX.

    if (!str->isAtom())
        return UINT32_MAX;

    uint32_t index;
    JSAtom *atom = &str->asAtom();
    if (!atom->isIndex(&index))
        return UINT32_MAX;

    return index;
}
Example #10
0
bool
js_InitCommonAtoms(JSContext *cx)
{
    JSAtomState *state = &cx->runtime->atomState;
    JSAtom **atoms = state->commonAtomsStart();
    for (size_t i = 0; i < ArrayLength(js_common_atom_names); i++, atoms++) {
        JSAtom *atom = js_Atomize(cx, js_common_atom_names[i], strlen(js_common_atom_names[i]),
                                  InternAtom);
        if (!atom)
            return false;
        *atoms = atom->asPropertyName();
    }

    state->clearLazyAtoms();
    cx->runtime->emptyString = state->emptyAtom;
    return true;
}
Example #11
0
void
js::gc::TraceTypeNewScript(ObjectGroup *group)
{
    const size_t bufLength = 128;
    static char buffer[bufLength];
    MOZ_ASSERT(group->hasNewScript());
    JSAtom *funName = group->newScript()->fun->displayAtom();
    if (!funName)
        return;

    size_t length = funName->length();
    MOZ_ALWAYS_TRUE(length < bufLength);
    CopyChars(reinterpret_cast<Latin1Char *>(buffer), *funName);
    buffer[length] = 0;

    TraceEvent(TraceEventTypeNewScript, uint64_t(group));
    TraceString(buffer);
}
Example #12
0
const StructField *
StructTypeRepresentation::fieldNamed(jsid id) const
{
    if (!JSID_IS_ATOM(id))
        return nullptr;

    uint32_t unused;
    JSAtom *atom = JSID_TO_ATOM(id);

    if (atom->isIndex(&unused))
        return nullptr;

    PropertyName *name = atom->asPropertyName();

    for (size_t i = 0; i < fieldCount(); i++) {
        if (field(i).propertyName.get() == name)
            return &field(i);
    }
    return nullptr;
}
Example #13
0
bool
JSRuntime::transformToPermanentAtoms()
{
    JS_ASSERT(!parentRuntime);

    // All static strings were created as permanent atoms, now move the contents
    // of the atoms table into permanentAtoms and mark each as permanent.

    JS_ASSERT(permanentAtoms && permanentAtoms->empty());

    AtomSet *temp = atoms_;
    atoms_ = permanentAtoms;
    permanentAtoms = temp;

    for (AtomSet::Enum e(*permanentAtoms); !e.empty(); e.popFront()) {
        AtomStateEntry entry = e.front();
        JSAtom *atom = entry.asPtr();
        atom->morphIntoPermanentAtom();
    }

    return true;
}
Example #14
0
bool
JSRuntime::transformToPermanentAtoms(JSContext *cx)
{
    MOZ_ASSERT(!parentRuntime);

    // All static strings were created as permanent atoms, now move the contents
    // of the atoms table into permanentAtoms and mark each as permanent.

    MOZ_ASSERT(!permanentAtoms);
    permanentAtoms = cx->new_<FrozenAtomSet>(atoms_);   // takes ownership of atoms_

    atoms_ = cx->new_<AtomSet>();
    if (!atoms_ || !atoms_->init(JS_STRING_HASH_COUNT))
        return false;

    for (FrozenAtomSet::Range r(permanentAtoms->all()); !r.empty(); r.popFront()) {
        AtomStateEntry entry = r.front();
        JSAtom *atom = entry.asPtr();
        atom->morphIntoPermanentAtom();
    }

    return true;
}
Example #15
0
Symbol*
Symbol::for_(JSContext* cx, HandleString description)
{
    JSAtom* atom = AtomizeString(cx, description);
    if (!atom)
        return nullptr;

    AutoLockForExclusiveAccess lock(cx);

    SymbolRegistry& registry = cx->symbolRegistry(lock);
    SymbolRegistry::AddPtr p = registry.lookupForAdd(atom);
    if (p) {
        cx->markAtom(*p);
        return *p;
    }

    Symbol* sym;
    {
        AutoAtomsCompartment ac(cx, lock);
        // Rehash the hash of the atom to give the corresponding symbol a hash
        // that is different than the hash of the corresponding atom.
        HashNumber hash = mozilla::HashGeneric(atom->hash());
        sym = newInternal(cx, SymbolCode::InSymbolRegistry, hash, atom, lock);
        if (!sym)
            return nullptr;

        // p is still valid here because we have held the lock since the
        // lookupForAdd call, and newInternal can't GC.
        if (!registry.add(p, sym)) {
            // SystemAllocPolicy does not report OOM.
            ReportOutOfMemory(cx);
            return nullptr;
        }
    }
    cx->markAtom(sym);
    return sym;
}
Example #16
0
bool
js::InitCommonNames(JSContext *cx)
{
    static const CommonNameInfo cachedNames[] = {
#define COMMON_NAME_INFO(idpart, id, text) { js_##idpart##_str, sizeof(text) - 1 },
        FOR_EACH_COMMON_PROPERTYNAME(COMMON_NAME_INFO)
#undef COMMON_NAME_INFO
#define COMMON_NAME_INFO(name, code, init) { js_##name##_str, sizeof(#name) - 1 },
        JS_FOR_EACH_PROTOTYPE(COMMON_NAME_INFO)
#undef COMMON_NAME_INFO
    };

    FixedHeapPtr<PropertyName> *names = &cx->runtime->firstCachedName;
    for (size_t i = 0; i < ArrayLength(cachedNames); i++, names++) {
        JSAtom *atom = Atomize(cx, cachedNames[i].str, cachedNames[i].length, InternAtom);
        if (!atom)
            return false;
        names->init(atom->asPropertyName());
    }
    JS_ASSERT(uintptr_t(names) == uintptr_t(&cx->runtime->atomState + 1));

    cx->runtime->emptyString = cx->names().empty;
    return true;
}
JSObject *
ParallelArrayObject::initClass(JSContext *cx, HandleObject obj)
{
    JS_ASSERT(obj->isNative());

    // Cache constructor names.
    {
        const char *ctorStrs[NumCtors] = { "ParallelArrayConstructEmpty",
                                           "ParallelArrayConstructFromArray",
                                           "ParallelArrayConstructFromFunction",
                                           "ParallelArrayConstructFromFunctionMode" };
        for (uint32_t i = 0; i < NumCtors; i++) {
            JSAtom *atom = Atomize(cx, ctorStrs[i], strlen(ctorStrs[i]), InternAtom);
            if (!atom)
                return NULL;
            ctorNames[i].init(atom->asPropertyName());
        }
    }

    Rooted<GlobalObject *> global(cx, &obj->asGlobal());

    RootedObject proto(cx, global->createBlankPrototype(cx, &protoClass));
    if (!proto)
        return NULL;

    JSProtoKey key = JSProto_ParallelArray;
    RootedFunction ctor(cx, global->createConstructor(cx, construct,
                                                      cx->names().ParallelArray, 0));
    if (!ctor ||
        !LinkConstructorAndPrototype(cx, ctor, proto) ||
        !DefinePropertiesAndBrand(cx, proto, NULL, methods) ||
        !DefineConstructorAndPrototype(cx, global, key, ctor, proto))
    {
        return NULL;
    }

    // Define the length getter.
    {
        const char lengthStr[] = "ParallelArrayLength";
        JSAtom *atom = Atomize(cx, lengthStr, strlen(lengthStr));
        if (!atom)
            return NULL;
        Rooted<PropertyName *> lengthProp(cx, atom->asPropertyName());
        RootedValue lengthValue(cx);
        if (!cx->global()->getIntrinsicValue(cx, lengthProp, &lengthValue))
            return NULL;
        RootedObject lengthGetter(cx, &lengthValue.toObject());
        if (!lengthGetter)
            return NULL;

        RootedId lengthId(cx, AtomToId(cx->names().length));
        unsigned flags = JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_GETTER;
        RootedValue value(cx, UndefinedValue());
        if (!DefineNativeProperty(cx, proto, lengthId, value,
                                  JS_DATA_TO_FUNC_PTR(PropertyOp, lengthGetter.get()), NULL,
                                  flags, 0, 0))
        {
            return NULL;
        }
    }

    return proto;
}
Example #18
0
bool
JSRuntime::initializeAtoms(JSContext *cx)
{
    atoms_ = cx->new_<AtomSet>();
    if (!atoms_ || !atoms_->init(JS_STRING_HASH_COUNT))
        return false;

    // |permanentAtoms| hasn't been created yet.
    MOZ_ASSERT(!permanentAtoms);

    if (parentRuntime) {
        staticStrings = parentRuntime->staticStrings;
        commonNames = parentRuntime->commonNames;
        emptyString = parentRuntime->emptyString;
        permanentAtoms = parentRuntime->permanentAtoms;
        wellKnownSymbols = parentRuntime->wellKnownSymbols;
        return true;
    }

    staticStrings = cx->new_<StaticStrings>();
    if (!staticStrings || !staticStrings->init(cx))
        return false;

    static const CommonNameInfo cachedNames[] = {
#define COMMON_NAME_INFO(idpart, id, text) { js_##idpart##_str, sizeof(text) - 1 },
        FOR_EACH_COMMON_PROPERTYNAME(COMMON_NAME_INFO)
#undef COMMON_NAME_INFO
#define COMMON_NAME_INFO(name, code, init, clasp) { js_##name##_str, sizeof(#name) - 1 },
        JS_FOR_EACH_PROTOTYPE(COMMON_NAME_INFO)
#undef COMMON_NAME_INFO
    };

    commonNames = cx->new_<JSAtomState>();
    if (!commonNames)
        return false;

    ImmutablePropertyNamePtr *names = reinterpret_cast<ImmutablePropertyNamePtr *>(commonNames);
    for (size_t i = 0; i < ArrayLength(cachedNames); i++, names++) {
        JSAtom *atom = Atomize(cx, cachedNames[i].str, cachedNames[i].length, InternAtom);
        if (!atom)
            return false;
        names->init(atom->asPropertyName());
    }
    MOZ_ASSERT(uintptr_t(names) == uintptr_t(commonNames + 1));

    emptyString = commonNames->empty;

    // Create the well-known symbols.
    wellKnownSymbols = cx->new_<WellKnownSymbols>();
    if (!wellKnownSymbols)
        return false;

    ImmutablePropertyNamePtr *descriptions = commonNames->wellKnownSymbolDescriptions();
    ImmutableSymbolPtr *symbols = reinterpret_cast<ImmutableSymbolPtr *>(wellKnownSymbols);
    for (size_t i = 0; i < JS::WellKnownSymbolLimit; i++) {
        JS::Symbol *symbol = JS::Symbol::new_(cx, JS::SymbolCode(i), descriptions[i]);
        if (!symbol) {
            ReportOutOfMemory(cx);
            return false;
        }
        symbols[i].init(symbol);
    }

    return true;
}