示例#1
0
MethodList EAClass::methodsNamed(const Identifier& identifier, Instance* instance) const
{
    MethodList methodList;

    // Check to see if the method has been cached first.
    Method* method = mMethods.get(identifier.impl());
    if (method) 
    {
        methodList.append(method);
        return methodList;
    }

    // Method hasn't been called before, see if the object supports it.
    // Rather than doing identifier.ascii().data(), we need to create CString separately otherwise it goes out of scope.
	CString identStr = identifier.ascii();
	const char *ident = identStr.data(); 

    const EAInstance *inst = static_cast<const EAInstance*>(instance);
    EA::WebKit::IJSBoundObject *obj = inst->getObject();
    if (obj->hasMethod(ident)) 
    {
        // The object says it has this method, cache it so that the string
        // lookup can be avoided in the future.
        EAMethod* aMethod = new EAMethod(ident);
        {
            JSLock lock(SilenceAssertionsOnly);
            mMethods.set(identifier.impl(), aMethod);
        }
        methodList.append(aMethod);
    }

    return methodList;
}
示例#2
0
// Returns true if we found enough information to terminate optimization.
static inline bool abstractAccess(ExecState* exec, JSScope* scope, const Identifier& ident, GetOrPut getOrPut, size_t depth, bool& needsVarInjectionChecks, ResolveOp& op)
{
    if (JSActivation* activation = jsDynamicCast<JSActivation*>(scope)) {
        if (ident == exec->propertyNames().arguments) {
            // We know the property will be at this activation scope, but we don't know how to cache it.
            op = ResolveOp(Dynamic, 0, 0, 0, 0);
            return true;
        }

        SymbolTableEntry entry = activation->symbolTable()->get(ident.impl());
        if (entry.isReadOnly() && getOrPut == Put) {
            // We know the property will be at this activation scope, but we don't know how to cache it.
            op = ResolveOp(Dynamic, 0, 0, 0, 0);
            return true;
        }

        if (!entry.isNull()) {
            op = ResolveOp(makeType(ClosureVar, needsVarInjectionChecks), depth, activation->structure(), 0, entry.getIndex());
            return true;
        }

        if (activation->symbolTable()->usesNonStrictEval())
            needsVarInjectionChecks = true;
        return false;
    }

    if (JSGlobalObject* globalObject = jsDynamicCast<JSGlobalObject*>(scope)) {
        SymbolTableEntry entry = globalObject->symbolTable()->get(ident.impl());
        if (!entry.isNull()) {
            if (getOrPut == Put && entry.isReadOnly()) {
                // We know the property will be at global scope, but we don't know how to cache it.
                op = ResolveOp(Dynamic, 0, 0, 0, 0);
                return true;
            }

            op = ResolveOp(
                makeType(GlobalVar, needsVarInjectionChecks), depth, 0, entry.watchpointSet(),
                reinterpret_cast<uintptr_t>(globalObject->registerAt(entry.getIndex()).slot()));
            return true;
        }

        PropertySlot slot(globalObject);
        if (!globalObject->getOwnPropertySlot(globalObject, exec, ident, slot)
            || !slot.isCacheableValue()
            || !globalObject->structure()->propertyAccessesAreCacheable()
            || (globalObject->structure()->hasReadOnlyOrGetterSetterPropertiesExcludingProto() && getOrPut == Put)) {
            // We know the property will be at global scope, but we don't know how to cache it.
            ASSERT(!scope->next());
            op = ResolveOp(makeType(GlobalProperty, needsVarInjectionChecks), depth, 0, 0, 0);
            return true;
        }

        op = ResolveOp(makeType(GlobalProperty, needsVarInjectionChecks), depth, globalObject->structure(), 0, slot.cachedOffset());
        return true;
    }

    op = ResolveOp(Dynamic, 0, 0, 0, 0);
    return true;
}
示例#3
0
PassRefPtr<Structure> Structure::addPropertyTransition(Structure* structure, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset)
{
    ASSERT(!structure->isDictionary());
    ASSERT(structure->typeInfo().type() == ObjectType);
    ASSERT(!Structure::addPropertyTransitionToExistingStructure(structure, propertyName, attributes, specificValue, offset));
    
    if (structure->m_specificFunctionThrashCount == maxSpecificFunctionThrashCount)
        specificValue = 0;

    if (structure->transitionCount() > s_maxTransitionLength) {
        RefPtr<Structure> transition = toCacheableDictionaryTransition(structure);
        ASSERT(structure != transition);
        offset = transition->put(propertyName, attributes, specificValue);
        ASSERT(offset >= structure->m_anonymousSlotCount);
        ASSERT(structure->m_anonymousSlotCount == transition->m_anonymousSlotCount);
        if (transition->propertyStorageSize() > transition->propertyStorageCapacity())
            transition->growPropertyStorageCapacity();
        return transition.release();
    }

    RefPtr<Structure> transition = create(structure->m_prototype.get(), structure->typeInfo(), structure->anonymousSlotCount());

    transition->m_cachedPrototypeChain = structure->m_cachedPrototypeChain;
    transition->m_previous = structure;
    transition->m_nameInPrevious = propertyName.impl();
    transition->m_attributesInPrevious = attributes;
    transition->m_specificValueInPrevious = specificValue;
    transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity;
    transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties;
    transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties;
    transition->m_specificFunctionThrashCount = structure->m_specificFunctionThrashCount;

    if (structure->m_propertyTable) {
        if (structure->m_isPinnedPropertyTable)
            transition->m_propertyTable = structure->copyPropertyTable();
        else {
            transition->m_propertyTable = structure->m_propertyTable;
            structure->m_propertyTable = 0;
        }
    } else {
        if (structure->m_previous)
            transition->materializePropertyMap();
        else
            transition->createPropertyMapHashTable();
    }

    offset = transition->put(propertyName, attributes, specificValue);
    ASSERT(offset >= structure->m_anonymousSlotCount);
    ASSERT(structure->m_anonymousSlotCount == transition->m_anonymousSlotCount);
    if (transition->propertyStorageSize() > transition->propertyStorageCapacity())
        transition->growPropertyStorageCapacity();

    transition->m_offset = offset - structure->m_anonymousSlotCount;
    ASSERT(structure->anonymousSlotCount() == transition->anonymousSlotCount());
    structure->transitionTableAdd(make_pair(propertyName.impl(), attributes), transition.get(), specificValue);
    return transition.release();
}
示例#4
0
EncodedJSValue JSC_HOST_CALL moduleLoaderObjectParseModule(ExecState* exec)
{
    VM& vm = exec->vm();
    const Identifier moduleKey = exec->argument(0).toPropertyKey(exec);
    if (exec->hadException())
        return JSValue::encode(jsUndefined());

    String source = exec->argument(1).toString(exec)->value(exec);
    if (exec->hadException())
        return JSValue::encode(jsUndefined());

    SourceCode sourceCode = makeSource(source, moduleKey.impl());

    CodeProfiling profile(sourceCode);

    ParserError error;
    std::unique_ptr<ModuleProgramNode> moduleProgramNode = parse<ModuleProgramNode>(
        &vm, sourceCode, Identifier(), JSParserBuiltinMode::NotBuiltin,
        JSParserStrictMode::Strict, SourceParseMode::ModuleAnalyzeMode, error);

    if (error.isValid()) {
        throwVMError(exec, error.toErrorObject(exec->lexicalGlobalObject(), sourceCode));
        return JSValue::encode(jsUndefined());
    }
    ASSERT(moduleProgramNode);

    ModuleAnalyzer moduleAnalyzer(exec, moduleKey, sourceCode, moduleProgramNode->varDeclarations(), moduleProgramNode->lexicalVariables());
    JSModuleRecord* moduleRecord = moduleAnalyzer.analyze(*moduleProgramNode);

    return JSValue::encode(moduleRecord);
}
bool JSVariableObject::deleteProperty(ExecState* exec, const Identifier& propertyName)
{
    if (symbolTable().contains(propertyName.impl()))
        return false;

    return JSObject::deleteProperty(exec, propertyName);
}
示例#6
0
size_t Structure::putSpecificValue(JSGlobalData& globalData, const Identifier& propertyName, unsigned attributes, JSCell* specificValue)
{
    ASSERT(!propertyName.isNull());
    ASSERT(get(globalData, propertyName) == notFound);

    checkConsistency();
    if (attributes & DontEnum)
        m_hasNonEnumerableProperties = true;

    StringImpl* rep = propertyName.impl();

    if (!m_propertyTable)
        createPropertyMap();

    unsigned newOffset;

    if (m_propertyTable->hasDeletedOffset())
        newOffset = m_propertyTable->getDeletedOffset();
    else
        newOffset = m_propertyTable->size();

    m_propertyTable->add(PropertyMapEntry(globalData, this, rep, newOffset, attributes, specificValue));

    checkConsistency();
    return newOffset;
}
    Storage storageForGeneratorLocal(unsigned index)
    {
        // We assign a symbol to a register. There is one-on-one corresponding between a register and a symbol.
        // By doing so, we allocate the specific storage to save the given register.
        // This allow us not to save all the live registers even if the registers are not overwritten from the previous resuming time.
        // It means that, the register can be retrieved even if the immediate previous op_save does not save it.

        if (m_storages.size() <= index)
            m_storages.resize(index + 1);
        if (Optional<Storage> storage = m_storages[index])
            return *storage;

        Identifier identifier = Identifier::fromUid(PrivateName());
        unsigned identifierIndex = m_codeBlock->numberOfIdentifiers();
        m_codeBlock->addIdentifier(identifier);
        ScopeOffset scopeOffset = m_generatorFrameSymbolTable->takeNextScopeOffset(NoLockingNecessary);
        m_generatorFrameSymbolTable->set(NoLockingNecessary, identifier.impl(), SymbolTableEntry(VarOffset(scopeOffset)));

        Storage storage = {
            identifier,
            identifierIndex,
            scopeOffset
        };
        m_storages[index] = storage;
        return storage;
    }
BytecodeIntrinsicNode::EmitterType BytecodeIntrinsicRegistry::lookup(const Identifier& ident) const
{
    if (!m_vm.propertyNames->isPrivateName(ident))
        return nullptr;
    auto iterator = m_bytecodeIntrinsicMap.find(ident.impl());
    if (iterator == m_bytecodeIntrinsicMap.end())
        return nullptr;
    return iterator->value;
}
bool JSVariableObject::symbolTableGet(const Identifier& propertyName, PropertyDescriptor& descriptor)
{
    SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl());
    if (!entry.isNull()) {
        descriptor.setDescriptor(registerAt(entry.getIndex()).jsValue(), entry.getAttributes() | DontDelete);
        return true;
    }
    return false;
}
static String cssPropertyName(const Identifier& propertyName, bool* hadPixelOrPosPrefix = 0)
{
    if (hadPixelOrPosPrefix)
        *hadPixelOrPosPrefix = false;

    unsigned length = propertyName.length();
    if (!length)
        return String();

    StringImpl* propertyNameString = propertyName.impl();
    // If there is no uppercase character in the propertyName, there can
    // be no prefix, nor extension and we can return the same string.
    if (!containsASCIIUpperChar(*propertyNameString))
        return String(propertyNameString);

    StringBuilder builder;
    builder.reserveCapacity(length);

    unsigned i = 0;
    switch (getCSSPropertyNamePrefix(*propertyNameString)) {
    case PropertyNamePrefixNone:
        if (isASCIIUpper((*propertyNameString)[0]))
            return String();
        break;
    case PropertyNamePrefixCSS:
        i += 3;
        break;
    case PropertyNamePrefixPixel:
        i += 5;
        if (hadPixelOrPosPrefix)
            *hadPixelOrPosPrefix = true;
        break;
    case PropertyNamePrefixPos:
        i += 3;
        if (hadPixelOrPosPrefix)
            *hadPixelOrPosPrefix = true;
        break;
    case PropertyNamePrefixApple:
    case PropertyNamePrefixEpub:
    case PropertyNamePrefixKHTML:
    case PropertyNamePrefixWebKit:
        builder.append('-');
    }

    builder.append(toASCIILower((*propertyNameString)[i++]));

    for (; i < length; ++i) {
        UChar c = (*propertyNameString)[i];
        if (!isASCIIUpper(c))
            builder.append(c);
        else
            builder.append(makeString('-', toASCIILower(c)));
    }

    return builder.toString();
}
示例#11
0
inline bool JSActivation::symbolTableGet(const Identifier& propertyName, PropertySlot& slot)
{
    SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl());
    if (!entry.isNull()) {
        ASSERT(entry.getIndex() < static_cast<int>(d()->functionExecutable->capturedVariableCount()));
        slot.setRegisterSlot(&registerAt(entry.getIndex()));
        return true;
    }
    return false;
}
示例#12
0
inline bool JSActivation::symbolTableGet(const Identifier& propertyName, PropertySlot& slot)
{
    SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl());
    if (entry.isNull())
        return false;
    if (entry.getIndex() >= m_numCapturedVars)
        return false;

    slot.setValue(registerAt(entry.getIndex()).get());
    return true;
}
示例#13
0
inline bool JSActivation::symbolTablePut(const Identifier& propertyName, JSValue value)
{
    ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
    
    SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl());
    if (entry.isNull())
        return false;
    if (entry.isReadOnly())
        return true;
    ASSERT(entry.getIndex() < static_cast<int>(d()->functionExecutable->capturedVariableCount()));
    registerAt(entry.getIndex()) = value;
    return true;
}
示例#14
0
void Structure::despecifyDictionaryFunction(JSGlobalData& globalData, const Identifier& propertyName)
{
    StringImpl* rep = propertyName.impl();

    materializePropertyMapIfNecessary(globalData);

    ASSERT(isDictionary());
    ASSERT(m_propertyTable);

    PropertyMapEntry* entry = m_propertyTable->find(rep).first;
    ASSERT(entry);
    entry->specificValue.clear();
}
示例#15
0
bool Structure::despecifyFunction(const Identifier& propertyName)
{
    ASSERT(!propertyName.isNull());

    materializePropertyMapIfNecessary();
    if (!m_propertyTable)
        return false;

    StringImpl* rep = propertyName.impl();

    unsigned i = rep->existingHash();

#if DUMP_PROPERTYMAP_STATS
    ++numProbes;
#endif

    unsigned entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
    if (entryIndex == emptyEntryIndex)
        return false;

    if (rep == m_propertyTable->entries()[entryIndex - 1].key) {
        ASSERT(m_propertyTable->entries()[entryIndex - 1].specificValue);
        m_propertyTable->entries()[entryIndex - 1].specificValue = 0;
        return true;
    }

#if DUMP_PROPERTYMAP_STATS
    ++numCollisions;
#endif

    unsigned k = 1 | doubleHash(rep->existingHash());

    while (1) {
        i += k;

#if DUMP_PROPERTYMAP_STATS
        ++numRehashes;
#endif

        entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
        if (entryIndex == emptyEntryIndex)
            return false;

        if (rep == m_propertyTable->entries()[entryIndex - 1].key) {
            ASSERT(m_propertyTable->entries()[entryIndex - 1].specificValue);
            m_propertyTable->entries()[entryIndex - 1].specificValue = 0;
            return true;
        }
    }
}
示例#16
0
PassRefPtr<Structure> Structure::addPropertyTransitionToExistingStructure(Structure* structure, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset)
{
    ASSERT(!structure->isDictionary());
    ASSERT(structure->typeInfo().type() == ObjectType);

    if (Structure* existingTransition = structure->transitionTableGet(make_pair(propertyName.impl(), attributes), specificValue)) {
        ASSERT(existingTransition->m_offset != noOffset);
        offset = existingTransition->m_offset + existingTransition->m_anonymousSlotCount;
        ASSERT(offset >= structure->m_anonymousSlotCount);
        ASSERT(structure->m_anonymousSlotCount == existingTransition->m_anonymousSlotCount);
        return existingTransition;
    }

    return 0;
}
示例#17
0
inline bool JSActivation::symbolTablePutWithAttributes(const Identifier& propertyName, JSValue value, unsigned attributes)
{
    ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
    
    SymbolTable::iterator iter = symbolTable().find(propertyName.impl());
    if (iter == symbolTable().end())
        return false;
    SymbolTableEntry& entry = iter->second;
    ASSERT(!entry.isNull());
    if (entry.getIndex() >= static_cast<int>(d()->functionExecutable->capturedVariableCount()))
        return false;
    entry.setAttributes(attributes);
    registerAt(entry.getIndex()) = value;
    return true;
}
示例#18
0
inline bool JSActivation::symbolTablePut(JSGlobalData& globalData, const Identifier& propertyName, JSValue value)
{
    ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
    
    SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl());
    if (entry.isNull())
        return false;
    if (entry.isReadOnly())
        return true;
    if (entry.getIndex() >= m_numCapturedVars)
        return false;

    registerAt(entry.getIndex()).set(globalData, this, value);
    return true;
}
示例#19
0
bool Structure::despecifyFunction(JSGlobalData& globalData, const Identifier& propertyName)
{
    materializePropertyMapIfNecessary(globalData);
    if (!m_propertyTable)
        return false;

    ASSERT(!propertyName.isNull());
    PropertyMapEntry* entry = m_propertyTable->find(propertyName.impl()).first;
    if (!entry)
        return false;

    ASSERT(entry->specificValue);
    entry->specificValue.clear();
    return true;
}
示例#20
0
inline bool JSActivation::symbolTablePutWithAttributes(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
{
    ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
    
    SymbolTable::iterator iter = symbolTable().find(propertyName.impl());
    if (iter == symbolTable().end())
        return false;
    SymbolTableEntry& entry = iter->second;
    ASSERT(!entry.isNull());
    if (entry.getIndex() >= m_numCapturedVars)
        return false;

    entry.setAttributes(attributes);
    registerAt(entry.getIndex()).set(globalData, this, value);
    return true;
}
示例#21
0
int ProgramExecutable::addGlobalVar(JSGlobalObject* globalObject, const Identifier& ident, ConstantMode constantMode, FunctionMode functionMode)
{
    // Try to share the symbolTable if possible
    SharedSymbolTable* symbolTable = globalObject->symbolTable();
    UNUSED_PARAM(functionMode);
    int index = symbolTable->size();
    SymbolTableEntry newEntry(index, (constantMode == IsConstant) ? ReadOnly : 0);
    if (functionMode == IsFunctionToSpecialize)
        newEntry.attemptToWatch();
    SymbolTable::AddResult result = symbolTable->add(ident.impl(), newEntry);
    if (!result.isNewEntry) {
        result.iterator->value.notifyWrite();
        index = result.iterator->value.getIndex();
    }
    return index;
}
示例#22
0
JSGlobalObject::NewGlobalVar JSGlobalObject::addGlobalVar(const Identifier& ident, ConstantMode constantMode)
{
    ConcurrentJITLocker locker(symbolTable()->m_lock);
    int index = symbolTable()->size(locker);
    SymbolTableEntry newEntry(index, (constantMode == IsConstant) ? ReadOnly : 0);
    if (constantMode == IsVariable)
        newEntry.prepareToWatch();
    SymbolTable::Map::AddResult result = symbolTable()->add(locker, ident.impl(), newEntry);
    if (result.isNewEntry)
        addRegisters(1);
    else
        index = result.iterator->value.getIndex();
    NewGlobalVar var;
    var.registerNumber = index;
    var.set = result.iterator->value.watchpointSet();
    return var;
}
示例#23
0
inline bool JSActivation::symbolTablePut(ExecState* exec, const Identifier& propertyName, JSValue value, bool shouldThrow)
{
    JSGlobalData& globalData = exec->globalData();
    ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
    
    SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl());
    if (entry.isNull())
        return false;
    if (entry.isReadOnly()) {
        if (shouldThrow)
            throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
        return true;
    }
    if (entry.getIndex() >= m_numCapturedVars)
        return false;

    registerAt(entry.getIndex()).set(globalData, this, value);
    return true;
}
示例#24
0
size_t Structure::remove(const Identifier& propertyName)
{
    ASSERT(!propertyName.isNull());

    checkConsistency();

    StringImpl* rep = propertyName.impl();

    if (!m_propertyTable)
        return notFound;

    PropertyTable::find_iterator position = m_propertyTable->find(rep);
    if (!position.first)
        return notFound;

    size_t offset = position.first->offset;

    m_propertyTable->remove(position);
    m_propertyTable->addDeletedOffset(offset);

    checkConsistency();
    return offset;
}
void AbstractModuleRecord::addStarExportEntry(const Identifier& moduleName)
{
    m_starExportEntries.add(moduleName.impl());
}
示例#26
0
// Returns true if we found enough information to terminate optimization.
static inline bool abstractAccess(ExecState* exec, JSScope* scope, const Identifier& ident, GetOrPut getOrPut, size_t depth, bool& needsVarInjectionChecks, ResolveOp& op, InitializationMode initializationMode)
{
    if (scope->isJSLexicalEnvironment()) {
        JSLexicalEnvironment* lexicalEnvironment = jsCast<JSLexicalEnvironment*>(scope);
        if (ident == exec->propertyNames().arguments) {
            // We know the property will be at this lexical environment scope, but we don't know how to cache it.
            op = ResolveOp(Dynamic, 0, 0, 0, 0, 0);
            return true;
        }

        SymbolTable* symbolTable = lexicalEnvironment->symbolTable();
        {
            ConcurrentJSLocker locker(symbolTable->m_lock);
            auto iter = symbolTable->find(locker, ident.impl());
            if (iter != symbolTable->end(locker)) {
                SymbolTableEntry& entry = iter->value;
                ASSERT(!entry.isNull());
                if (entry.isReadOnly() && getOrPut == Put) {
                    // We know the property will be at this lexical environment scope, but we don't know how to cache it.
                    op = ResolveOp(Dynamic, 0, 0, 0, 0, 0);
                    return true;
                }

                op = ResolveOp(makeType(ClosureVar, needsVarInjectionChecks), depth, 0, lexicalEnvironment, entry.watchpointSet(), entry.scopeOffset().offset());
                return true;
            }
        }

        if (scope->type() == ModuleEnvironmentType) {
            JSModuleEnvironment* moduleEnvironment = jsCast<JSModuleEnvironment*>(scope);
            AbstractModuleRecord* moduleRecord = moduleEnvironment->moduleRecord();
            AbstractModuleRecord::Resolution resolution = moduleRecord->resolveImport(exec, ident);
            if (resolution.type == AbstractModuleRecord::Resolution::Type::Resolved) {
                AbstractModuleRecord* importedRecord = resolution.moduleRecord;
                JSModuleEnvironment* importedEnvironment = importedRecord->moduleEnvironment();
                SymbolTable* symbolTable = importedEnvironment->symbolTable();
                ConcurrentJSLocker locker(symbolTable->m_lock);
                auto iter = symbolTable->find(locker, resolution.localName.impl());
                ASSERT(iter != symbolTable->end(locker));
                SymbolTableEntry& entry = iter->value;
                ASSERT(!entry.isNull());
                op = ResolveOp(makeType(ModuleVar, needsVarInjectionChecks), depth, 0, importedEnvironment, entry.watchpointSet(), entry.scopeOffset().offset(), resolution.localName.impl());
                return true;
            }
        }

        if (symbolTable->usesNonStrictEval())
            needsVarInjectionChecks = true;
        return false;
    }

    if (scope->isGlobalLexicalEnvironment()) {
        JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsCast<JSGlobalLexicalEnvironment*>(scope);
        SymbolTable* symbolTable = globalLexicalEnvironment->symbolTable();
        ConcurrentJSLocker locker(symbolTable->m_lock);
        auto iter = symbolTable->find(locker, ident.impl());
        if (iter != symbolTable->end(locker)) {
            SymbolTableEntry& entry = iter->value;
            ASSERT(!entry.isNull());
            if (getOrPut == Put && entry.isReadOnly() && !isInitialization(initializationMode)) {
                // We know the property will be at global lexical environment, but we don't know how to cache it.
                op = ResolveOp(Dynamic, 0, 0, 0, 0, 0);
                return true;
            }

            // We can force const Initialization to always go down the fast path. It is provably impossible to construct
            // a program that needs a var injection check here. You can convince yourself of this as follows:
            // Any other let/const/class would be a duplicate of this in the global scope, so we would never get here in that situation.
            // Also, if we had an eval in the global scope that defined a const, it would also be a duplicate of this const, and so it would
            // also throw an error. Therefore, we're *the only* thing that can assign to this "const" slot for the first (and only) time. Also, 
            // we will never have a Dynamic ResolveType here because if we were inside a "with" statement, that would mean the "const" definition 
            // isn't a global, it would be a local to the "with" block. 
            // We still need to make the slow path correct for when we need to fire a watchpoint.
            ResolveType resolveType = initializationMode == InitializationMode::ConstInitialization ? GlobalLexicalVar : makeType(GlobalLexicalVar, needsVarInjectionChecks);
            op = ResolveOp(
                resolveType, depth, 0, 0, entry.watchpointSet(),
                reinterpret_cast<uintptr_t>(globalLexicalEnvironment->variableAt(entry.scopeOffset()).slot()));
            return true;
        }

        return false;
    }

    if (scope->isGlobalObject()) {
        JSGlobalObject* globalObject = jsCast<JSGlobalObject*>(scope);
        {
            SymbolTable* symbolTable = globalObject->symbolTable();
            ConcurrentJSLocker locker(symbolTable->m_lock);
            auto iter = symbolTable->find(locker, ident.impl());
            if (iter != symbolTable->end(locker)) {
                SymbolTableEntry& entry = iter->value;
                ASSERT(!entry.isNull());
                if (getOrPut == Put && entry.isReadOnly()) {
                    // We know the property will be at global scope, but we don't know how to cache it.
                    op = ResolveOp(Dynamic, 0, 0, 0, 0, 0);
                    return true;
                }

                op = ResolveOp(
                    makeType(GlobalVar, needsVarInjectionChecks), depth, 0, 0, entry.watchpointSet(),
                    reinterpret_cast<uintptr_t>(globalObject->variableAt(entry.scopeOffset()).slot()));
                return true;
            }
        }

        PropertySlot slot(globalObject, PropertySlot::InternalMethodType::VMInquiry);
        bool hasOwnProperty = globalObject->getOwnPropertySlot(globalObject, exec, ident, slot);
        if (!hasOwnProperty) {
            op = ResolveOp(makeType(UnresolvedProperty, needsVarInjectionChecks), 0, 0, 0, 0, 0);
            return true;
        }

        if (!slot.isCacheableValue()
            || !globalObject->structure()->propertyAccessesAreCacheable()
            || (globalObject->structure()->hasReadOnlyOrGetterSetterPropertiesExcludingProto() && getOrPut == Put)) {
            // We know the property will be at global scope, but we don't know how to cache it.
            ASSERT(!scope->next());
            op = ResolveOp(makeType(GlobalProperty, needsVarInjectionChecks), 0, 0, 0, 0, 0);
            return true;
        }

        
        WatchpointState state = globalObject->structure()->ensurePropertyReplacementWatchpointSet(exec->vm(), slot.cachedOffset())->state();
        if (state == IsWatched && getOrPut == Put) {
            // The field exists, but because the replacement watchpoint is still intact. This is
            // kind of dangerous. We have two options:
            // 1) Invalidate the watchpoint set. That would work, but it's possible that this code
            //    path never executes - in which case this would be unwise.
            // 2) Have the invalidation happen at run-time. All we have to do is leave the code
            //    uncached. The only downside is slightly more work when this does execute.
            // We go with option (2) here because it seems less evil.
            op = ResolveOp(makeType(GlobalProperty, needsVarInjectionChecks), depth, 0, 0, 0, 0);
        } else
            op = ResolveOp(makeType(GlobalProperty, needsVarInjectionChecks), depth, globalObject->structure(), 0, 0, slot.cachedOffset());
        return true;
    }

    op = ResolveOp(Dynamic, 0, 0, 0, 0, 0);
    return true;
}
示例#27
0
void ModuleAnalyzer::declareExportAlias(const Identifier& localName, const Identifier& exportName)
{
    m_aliasMap.add(localName.impl(), exportName);
}
示例#28
0
static JSValue identifierToJSValue(VM& vm, const Identifier& identifier)
{
    if (identifier.isSymbol())
        return Symbol::create(vm, static_cast<SymbolImpl&>(*identifier.impl()));
    return jsString(&vm, identifier.impl());
}
示例#29
0
size_t Structure::put(const Identifier& propertyName, unsigned attributes, JSCell* specificValue)
{
    ASSERT(!propertyName.isNull());
    ASSERT(get(propertyName) == notFound);

    checkConsistency();

    if (attributes & DontEnum)
        m_hasNonEnumerableProperties = true;

    StringImpl* rep = propertyName.impl();

    if (!m_propertyTable)
        createPropertyMapHashTable();

    // FIXME: Consider a fast case for tables with no deleted sentinels.

    unsigned i = rep->existingHash();
    unsigned k = 0;
    bool foundDeletedElement = false;
    unsigned deletedElementIndex = 0; // initialize to make the compiler happy

#if DUMP_PROPERTYMAP_STATS
    ++numProbes;
#endif

    while (1) {
        unsigned entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
        if (entryIndex == emptyEntryIndex)
            break;

        if (entryIndex == deletedSentinelIndex) {
            // If we find a deleted-element sentinel, remember it for use later.
            if (!foundDeletedElement) {
                foundDeletedElement = true;
                deletedElementIndex = i;
            }
        }

        if (k == 0) {
            k = 1 | doubleHash(rep->existingHash());
#if DUMP_PROPERTYMAP_STATS
            ++numCollisions;
#endif
        }

        i += k;

#if DUMP_PROPERTYMAP_STATS
        ++numRehashes;
#endif
    }

    // Figure out which entry to use.
    unsigned entryIndex = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount + 2;
    if (foundDeletedElement) {
        i = deletedElementIndex;
        --m_propertyTable->deletedSentinelCount;

        // Since we're not making the table bigger, we can't use the entry one past
        // the end that we were planning on using, so search backwards for the empty
        // slot that we can use. We know it will be there because we did at least one
        // deletion in the past that left an entry empty.
        while (m_propertyTable->entries()[--entryIndex - 1].key) { }
    }

    // Create a new hash table entry.
    m_propertyTable->entryIndices[i & m_propertyTable->sizeMask] = entryIndex;

    // Create a new hash table entry.
    rep->ref();
    m_propertyTable->entries()[entryIndex - 1].key = rep;
    m_propertyTable->entries()[entryIndex - 1].attributes = attributes;
    m_propertyTable->entries()[entryIndex - 1].specificValue = specificValue;
    m_propertyTable->entries()[entryIndex - 1].index = ++m_propertyTable->lastIndexUsed;

    unsigned newOffset;
    if (m_propertyTable->deletedOffsets && !m_propertyTable->deletedOffsets->isEmpty()) {
        newOffset = m_propertyTable->deletedOffsets->last();
        m_propertyTable->deletedOffsets->removeLast();
    } else
        newOffset = m_propertyTable->keyCount + m_anonymousSlotCount;
    m_propertyTable->entries()[entryIndex - 1].offset = newOffset;
    
    ASSERT(newOffset >= m_anonymousSlotCount);
    ++m_propertyTable->keyCount;

    if ((m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount) * 2 >= m_propertyTable->size)
        expandPropertyMapHashTable();

    checkConsistency();
    return newOffset;
}
示例#30
0
size_t Structure::remove(const Identifier& propertyName)
{
    ASSERT(!propertyName.isNull());

    checkConsistency();

    StringImpl* rep = propertyName.impl();

    if (!m_propertyTable)
        return notFound;

#if DUMP_PROPERTYMAP_STATS
    ++numProbes;
    ++numRemoves;
#endif

    // Find the thing to remove.
    unsigned i = rep->existingHash();
    unsigned k = 0;
    unsigned entryIndex;
    StringImpl* key = 0;
    while (1) {
        entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
        if (entryIndex == emptyEntryIndex)
            return notFound;

        key = m_propertyTable->entries()[entryIndex - 1].key;
        if (rep == key)
            break;

        if (k == 0) {
            k = 1 | doubleHash(rep->existingHash());
#if DUMP_PROPERTYMAP_STATS
            ++numCollisions;
#endif
        }

        i += k;

#if DUMP_PROPERTYMAP_STATS
        ++numRehashes;
#endif
    }

    // Replace this one element with the deleted sentinel. Also clear out
    // the entry so we can iterate all the entries as needed.
    m_propertyTable->entryIndices[i & m_propertyTable->sizeMask] = deletedSentinelIndex;

    size_t offset = m_propertyTable->entries()[entryIndex - 1].offset;
    ASSERT(offset >= m_anonymousSlotCount);

    key->deref();
    m_propertyTable->entries()[entryIndex - 1].key = 0;
    m_propertyTable->entries()[entryIndex - 1].attributes = 0;
    m_propertyTable->entries()[entryIndex - 1].specificValue = 0;
    m_propertyTable->entries()[entryIndex - 1].offset = 0;

    if (!m_propertyTable->deletedOffsets)
        m_propertyTable->deletedOffsets = new Vector<unsigned>;
    m_propertyTable->deletedOffsets->append(offset);

    ASSERT(m_propertyTable->keyCount >= 1);
    --m_propertyTable->keyCount;
    ++m_propertyTable->deletedSentinelCount;

    if (m_propertyTable->deletedSentinelCount * 4 >= m_propertyTable->size)
        rehashPropertyMapHashTable();

    checkConsistency();
    return offset;
}