diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2012-10-22 15:40:17 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@digia.com> | 2012-10-22 15:40:17 +0200 |
commit | 43a42f108af6bcbd91f2672731c3047c26213af1 (patch) | |
tree | 7fa092e5f5d873c72f2486a70e26be26f7a38bec /Source/JavaScriptCore/runtime | |
parent | d9cf437c840c6eb7417bdd97e6c40979255d3158 (diff) | |
download | qtwebkit-43a42f108af6bcbd91f2672731c3047c26213af1.tar.gz |
Imported WebKit commit 302e7806bff028bd1167a1ec7c86a1ee00ecfb49 (http://svn.webkit.org/repository/webkit/trunk@132067)
New snapshot that fixes build without QtWidgets
Diffstat (limited to 'Source/JavaScriptCore/runtime')
-rw-r--r-- | Source/JavaScriptCore/runtime/JSScope.cpp | 597 | ||||
-rw-r--r-- | Source/JavaScriptCore/runtime/JSScope.h | 36 | ||||
-rw-r--r-- | Source/JavaScriptCore/runtime/JSValue.cpp | 2 | ||||
-rw-r--r-- | Source/JavaScriptCore/runtime/JSValue.h | 8 | ||||
-rw-r--r-- | Source/JavaScriptCore/runtime/JSValueInlineMethods.h | 33 | ||||
-rw-r--r-- | Source/JavaScriptCore/runtime/JSVariableObject.cpp | 2 | ||||
-rw-r--r-- | Source/JavaScriptCore/runtime/JSVariableObject.h | 2 | ||||
-rw-r--r-- | Source/JavaScriptCore/runtime/RegExpKey.h | 19 | ||||
-rw-r--r-- | Source/JavaScriptCore/runtime/StringRecursionChecker.h | 3 | ||||
-rw-r--r-- | Source/JavaScriptCore/runtime/Structure.h | 2 |
10 files changed, 532 insertions, 172 deletions
diff --git a/Source/JavaScriptCore/runtime/JSScope.cpp b/Source/JavaScriptCore/runtime/JSScope.cpp index 8fd49b861..508a90540 100644 --- a/Source/JavaScriptCore/runtime/JSScope.cpp +++ b/Source/JavaScriptCore/runtime/JSScope.cpp @@ -86,126 +86,388 @@ int JSScope::localDepth() return scopeDepth; } -JSValue JSScope::resolve(CallFrame* callFrame, const Identifier& identifier) -{ - JSScope* scope = callFrame->scope(); - ASSERT(scope); +struct LookupResult { + JSValue base() const { return m_base; } + JSValue value() const { return m_value; } + void setBase(JSValue base) { ASSERT(base); m_base = base; } + void setValue(JSValue value) { ASSERT(value); m_value = value; } - do { - JSObject* object = JSScope::objectAtScope(scope); - PropertySlot slot(object); - if (object->getPropertySlot(callFrame, identifier, slot)) - return slot.getValue(callFrame, identifier); - } while ((scope = scope->next())); +private: + JSValue m_base; + JSValue m_value; +}; - return throwError(callFrame, createUndefinedVariableError(callFrame, identifier)); + +static void setPutPropertyAccessOffset(PutToBaseOperation* operation, PropertyOffset offset) +{ + ASSERT(isOutOfLineOffset(offset)); + operation->m_offset = offset; + operation->m_offsetInButterfly = offsetInButterfly(offset); +} + +static bool executeResolveOperations(CallFrame* callFrame, JSScope* scope, const Identifier& propertyName, ResolveOperation* pc, LookupResult& result) +{ + while (true) { + switch (pc->m_operation) { + case ResolveOperation::Fail: + return false; + case ResolveOperation::CheckForDynamicEntriesBeforeGlobalScope: { + while (JSScope* nextScope = scope->next()) { + if (scope->isActivationObject() && scope->structure() != scope->globalObject()->activationStructure()) + return false; + ASSERT(scope->isNameScopeObject() || scope->isVariableObject() || scope->isGlobalObject()); + scope = nextScope; + } + pc++; + break; + } + case ResolveOperation::SetBaseToUndefined: + result.setBase(jsUndefined()); + pc++; + continue; + case ResolveOperation::SetBaseToScope: + result.setBase(scope); + pc++; + continue; + case ResolveOperation::ReturnScopeAsBase: + result.setBase(scope); + return true; + case ResolveOperation::SetBaseToGlobal: + result.setBase(scope->globalObject()); + pc++; + continue; + case ResolveOperation::SkipScopes: { + int count = pc->m_scopesToSkip; + while (count--) + scope = scope->next(); + ASSERT(scope); + pc++; + continue; + } + case ResolveOperation::SkipTopScopeNode: + if (callFrame->r(pc->m_activationRegister).jsValue()) + scope = scope->next(); + ASSERT(scope); + pc++; + continue; + case ResolveOperation::GetAndReturnScopedVar: + ASSERT(jsCast<JSVariableObject*>(scope)->registerAt(pc->m_offset).get()); + result.setValue(jsCast<JSVariableObject*>(scope)->registerAt(pc->m_offset).get()); + return true; + case ResolveOperation::GetAndReturnGlobalVar: + result.setValue(pc->m_registerAddress->get()); + return true; + case ResolveOperation::GetAndReturnGlobalVarWatchable: + result.setValue(pc->m_registerAddress->get()); + return true; + case ResolveOperation::ReturnGlobalObjectAsBase: + result.setBase(callFrame->lexicalGlobalObject()); + return true; + case ResolveOperation::GetAndReturnGlobalProperty: { + JSGlobalObject* globalObject = scope->globalObject(); + if (globalObject->structure() == pc->m_structure.get()) { + result.setValue(globalObject->getDirectOffset(pc->m_offset)); + return true; + } + + PropertySlot slot(globalObject); + if (!globalObject->getPropertySlot(callFrame, propertyName, slot)) + return false; + + JSValue value = slot.getValue(callFrame, propertyName); + if (callFrame->hadException()) + return false; + + Structure* structure = globalObject->structure(); + + // Don't try to cache prototype lookups + if (globalObject != slot.slotBase() || !slot.isCacheableValue() || !structure->propertyAccessesAreCacheable()) { + result.setValue(value); + return true; + } + + pc->m_structure.set(callFrame->globalData(), callFrame->codeBlock()->ownerExecutable(), structure); + pc->m_offset = slot.cachedOffset(); + result.setValue(value); + return true; + } + } + } } -JSValue JSScope::resolveSkip(CallFrame* callFrame, const Identifier& identifier, int skip) +template <JSScope::LookupMode mode, JSScope::ReturnValues returnValues> JSObject* JSScope::resolveContainingScopeInternal(CallFrame* callFrame, const Identifier& identifier, PropertySlot& slot, Vector<ResolveOperation>* operations, PutToBaseOperation* putToBaseOperation, bool ) { JSScope* scope = callFrame->scope(); ASSERT(scope); - + int scopeCount = 0; + bool seenGenericObjectScope = false; + bool requiresDynamicChecks = false; + bool skipTopScopeNode = false; + int activationRegister = 0; CodeBlock* codeBlock = callFrame->codeBlock(); - - bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain(); - ASSERT(skip || !checkTopLevel); - if (checkTopLevel && skip--) { - if (callFrame->uncheckedR(codeBlock->activationRegister()).jsValue()) - scope = scope->next(); - } - while (skip--) { - scope = scope->next(); - ASSERT(scope); - } + if (mode == UnknownResolve) { + ASSERT(operations->isEmpty()); + if (codeBlock->codeType() == FunctionCode && codeBlock->needsActivation()) { + activationRegister = codeBlock->activationRegister(); + JSValue activation = callFrame->r(activationRegister).jsValue(); + + // If the activation register doesn't match our actual scope, a dynamic + // scope has been inserted so we shouldn't skip the top scope node. + if (activation == scope) { + jsCast<JSActivation*>(activation.asCell())->isDynamicScope(requiresDynamicChecks); + if (!requiresDynamicChecks) { + ASSERT(jsCast<JSActivation*>(activation.asCell())->symbolTable()->get(identifier.impl()).isNull()); + scope = scope->next(); + ASSERT(scope); + skipTopScopeNode = true; + } + } else if (!activation) + skipTopScopeNode = true; + } + } else + ASSERT(operations->size()); + + if (codeBlock->codeType() == EvalCode && scope->next()) + requiresDynamicChecks = true; + + if (mode == UnknownResolve && putToBaseOperation) + putToBaseOperation->m_kind = PutToBaseOperation::Generic; do { JSObject* object = JSScope::objectAtScope(scope); - PropertySlot slot(object); - if (object->getPropertySlot(callFrame, identifier, slot)) - return slot.getValue(callFrame, identifier); + slot = PropertySlot(object); + + bool currentScopeNeedsDynamicChecks = false; + if (!(scope->isVariableObject() || scope->isNameScopeObject()) || (scope->next() && scope->isDynamicScope(currentScopeNeedsDynamicChecks))) + seenGenericObjectScope = true; + + requiresDynamicChecks = requiresDynamicChecks || currentScopeNeedsDynamicChecks; + + if (object->getPropertySlot(callFrame, identifier, slot)) { + if (mode == UnknownResolve) { + if (seenGenericObjectScope) + goto fail; + if (putToBaseOperation) + putToBaseOperation->m_isDynamic = requiresDynamicChecks; + if (!scope->next()) { + // Global lookup of some kind + JSGlobalObject* globalObject = jsCast<JSGlobalObject*>(scope); + SymbolTableEntry entry = globalObject->symbolTable()->get(identifier.impl()); + if (!entry.isNull()) { + if (requiresDynamicChecks) + operations->append(ResolveOperation::checkForDynamicEntriesBeforeGlobalScope()); + + if (putToBaseOperation) { + putToBaseOperation->m_isDynamic = requiresDynamicChecks; + if (entry.isReadOnly()) + putToBaseOperation->m_kind = PutToBaseOperation::Readonly; + else if (entry.couldBeWatched()) { + putToBaseOperation->m_kind = PutToBaseOperation::GlobalVariablePutChecked; + putToBaseOperation->m_predicatePointer = entry.addressOfIsWatched(); + } else + putToBaseOperation->m_kind = PutToBaseOperation::GlobalVariablePut; + putToBaseOperation->m_registerAddress = &globalObject->registerAt(entry.getIndex()); + } + // Override custom accessor behaviour that the DOM introduces for some + // event handlers declared on function declarations. + if (!requiresDynamicChecks) + slot.setValue(globalObject, globalObject->registerAt(entry.getIndex()).get()); + switch (returnValues) { + case ReturnValue: + ASSERT(!putToBaseOperation); + operations->append(ResolveOperation::getAndReturnGlobalVar(&globalObject->registerAt(entry.getIndex()), entry.couldBeWatched())); + break; + case ReturnBase: + ASSERT(putToBaseOperation); + operations->append(ResolveOperation::returnGlobalObjectAsBase()); + break; + case ReturnBaseAndValue: + ASSERT(putToBaseOperation); + operations->append(ResolveOperation::setBaseToGlobal()); + operations->append(ResolveOperation::getAndReturnGlobalVar(&globalObject->registerAt(entry.getIndex()), entry.couldBeWatched())); + break; + case ReturnThisAndValue: + ASSERT(!putToBaseOperation); + operations->append(ResolveOperation::setBaseToUndefined()); + operations->append(ResolveOperation::getAndReturnGlobalVar(&globalObject->registerAt(entry.getIndex()), entry.couldBeWatched())); + break; + } + } else { + if (!slot.isCacheableValue() || slot.slotBase() != globalObject) + goto fail; + + if (requiresDynamicChecks) + operations->append(ResolveOperation::checkForDynamicEntriesBeforeGlobalScope()); + + if (putToBaseOperation) { + putToBaseOperation->m_isDynamic = requiresDynamicChecks; + putToBaseOperation->m_kind = PutToBaseOperation::GlobalPropertyPut; + putToBaseOperation->m_structure.set(callFrame->globalData(), callFrame->codeBlock()->ownerExecutable(), globalObject->structure()); + setPutPropertyAccessOffset(putToBaseOperation, slot.cachedOffset()); + } + switch (returnValues) { + case ReturnValue: + ASSERT(!putToBaseOperation); + operations->append(ResolveOperation::getAndReturnGlobalProperty()); + break; + case ReturnBase: + ASSERT(putToBaseOperation); + operations->append(ResolveOperation::returnGlobalObjectAsBase()); + break; + case ReturnBaseAndValue: + ASSERT(putToBaseOperation); + operations->append(ResolveOperation::setBaseToGlobal()); + operations->append(ResolveOperation::getAndReturnGlobalProperty()); + break; + case ReturnThisAndValue: + ASSERT(!putToBaseOperation); + operations->append(ResolveOperation::setBaseToUndefined()); + operations->append(ResolveOperation::getAndReturnGlobalProperty()); + break; + } + } + return object; + } + if (!requiresDynamicChecks) { + // Normal lexical lookup + JSVariableObject* variableObject = jsCast<JSVariableObject*>(scope); + ASSERT(variableObject); + ASSERT(variableObject->symbolTable()); + SymbolTableEntry entry = variableObject->symbolTable()->get(identifier.impl()); + // Variable was actually inserted by eval + if (entry.isNull()) { + ASSERT(!jsDynamicCast<JSNameScope*>(variableObject)); + goto fail; + } + + if (putToBaseOperation) { + putToBaseOperation->m_kind = entry.isReadOnly() ? PutToBaseOperation::Readonly : PutToBaseOperation::VariablePut; + putToBaseOperation->m_structure.set(callFrame->globalData(), callFrame->codeBlock()->ownerExecutable(), callFrame->lexicalGlobalObject()->activationStructure()); + putToBaseOperation->m_offset = entry.getIndex(); + putToBaseOperation->m_scopeDepth = (skipTopScopeNode ? 1 : 0) + scopeCount; + } + + if (skipTopScopeNode) + operations->append(ResolveOperation::skipTopScopeNode(activationRegister)); + + operations->append(ResolveOperation::skipScopes(scopeCount)); + switch (returnValues) { + case ReturnBaseAndValue: + operations->append(ResolveOperation::setBaseToScope()); + operations->append(ResolveOperation::getAndReturnScopedVar(entry.getIndex())); + break; + + case ReturnBase: + operations->append(ResolveOperation::returnScopeAsBase()); + break; + + case ReturnThisAndValue: + operations->append(ResolveOperation::setBaseToUndefined()); + // fallthrough + case ReturnValue: + operations->append(ResolveOperation::getAndReturnScopedVar(entry.getIndex())); + break; + } + return object; + } + fail: + if (!operations->size()) + operations->append(ResolveOperation::resolveFail()); + } + return object; + } + scopeCount++; } while ((scope = scope->next())); - - return throwError(callFrame, createUndefinedVariableError(callFrame, identifier)); + + if (mode == UnknownResolve) { + ASSERT(operations->isEmpty()); + if (seenGenericObjectScope) { + operations->append(ResolveOperation::resolveFail()); + return 0; + } + if (putToBaseOperation) { + putToBaseOperation->m_isDynamic = requiresDynamicChecks; + putToBaseOperation->m_kind = PutToBaseOperation::GlobalPropertyPut; + putToBaseOperation->m_structure.clear(); + putToBaseOperation->m_offset = -1; + } + if (requiresDynamicChecks) + operations->append(ResolveOperation::checkForDynamicEntriesBeforeGlobalScope()); + switch (returnValues) { + case ReturnValue: + ASSERT(!putToBaseOperation); + operations->append(ResolveOperation::getAndReturnGlobalProperty()); + break; + case ReturnBase: + ASSERT(putToBaseOperation); + operations->append(ResolveOperation::returnGlobalObjectAsBase()); + break; + case ReturnBaseAndValue: + ASSERT(putToBaseOperation); + operations->append(ResolveOperation::setBaseToGlobal()); + operations->append(ResolveOperation::getAndReturnGlobalProperty()); + break; + case ReturnThisAndValue: + ASSERT(!putToBaseOperation); + operations->append(ResolveOperation::setBaseToUndefined()); + operations->append(ResolveOperation::getAndReturnGlobalProperty()); + break; + } + } + return 0; } -JSValue JSScope::resolveGlobal( - CallFrame* callFrame, - const Identifier& identifier, - JSGlobalObject* globalObject, - WriteBarrierBase<Structure>* cachedStructure, - PropertyOffset* cachedOffset -) +template <JSScope::ReturnValues returnValues> JSObject* JSScope::resolveContainingScope(CallFrame* callFrame, const Identifier& identifier, PropertySlot& slot, Vector<ResolveOperation>* operations, PutToBaseOperation* putToBaseOperation, bool isStrict) { - if (globalObject->structure() == cachedStructure->get()) - return globalObject->getDirectOffset(*cachedOffset); - - PropertySlot slot(globalObject); - if (!globalObject->getPropertySlot(callFrame, identifier, slot)) - return throwError(callFrame, createUndefinedVariableError(callFrame, identifier)); - - JSValue result = slot.getValue(callFrame, identifier); - if (callFrame->globalData().exception) - return JSValue(); - - if (slot.isCacheableValue() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) { - cachedStructure->set(callFrame->globalData(), callFrame->codeBlock()->ownerExecutable(), globalObject->structure()); - *cachedOffset = slot.cachedOffset(); - } + if (operations->size()) + return resolveContainingScopeInternal<KnownResolve, returnValues>(callFrame, identifier, slot, operations, putToBaseOperation, isStrict); + JSObject* result = resolveContainingScopeInternal<UnknownResolve, returnValues>(callFrame, identifier, slot, operations, putToBaseOperation, isStrict); + operations->shrinkToFit(); return result; } -JSValue JSScope::resolveGlobalDynamic( - CallFrame* callFrame, - const Identifier& identifier, - int skip, - WriteBarrierBase<Structure>* cachedStructure, - PropertyOffset* cachedOffset -) +JSValue JSScope::resolve(CallFrame* callFrame, const Identifier& identifier, ResolveOperations* operations) { - JSScope* scope = callFrame->scope(); - ASSERT(scope); - - CodeBlock* codeBlock = callFrame->codeBlock(); - - bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain(); - ASSERT(skip || !checkTopLevel); - if (checkTopLevel && skip--) { - if (callFrame->uncheckedR(codeBlock->activationRegister()).jsValue()) - scope = scope->next(); + ASSERT(operations); + LookupResult fastResult; + if (operations->size() && executeResolveOperations(callFrame, callFrame->scope(), identifier, operations->data(), fastResult)) { + ASSERT(fastResult.value()); + ASSERT(!callFrame->hadException()); + return fastResult.value(); } - while (skip--) { - JSObject* object = JSScope::objectAtScope(scope); - if (!object->hasCustomProperties()) - continue; - PropertySlot slot(object); - if (!object->getPropertySlot(callFrame, identifier, slot)) - continue; + if (callFrame->hadException()) + return JSValue(); - JSValue result = slot.getValue(callFrame, identifier); - if (callFrame->globalData().exception) - return JSValue(); - return result; + PropertySlot slot; + if (JSScope::resolveContainingScope<ReturnValue>(callFrame, identifier, slot, operations, 0, false)) { + ASSERT(operations->size()); + return slot.getValue(callFrame, identifier); } + ASSERT(operations->size()); - return resolveGlobal(callFrame, identifier, callFrame->lexicalGlobalObject(), cachedStructure, cachedOffset); + return throwError(callFrame, createUndefinedVariableError(callFrame, identifier)); } -JSValue JSScope::resolveBase(CallFrame* callFrame, const Identifier& identifier, bool isStrict) +JSValue JSScope::resolveBase(CallFrame* callFrame, const Identifier& identifier, bool isStrict, ResolveOperations* operations, PutToBaseOperation* putToBaseOperations) { - JSScope* scope = callFrame->scope(); - ASSERT(scope); - - do { - JSObject* object = JSScope::objectAtScope(scope); + ASSERT(operations); + ASSERT_UNUSED(putToBaseOperations, putToBaseOperations); + LookupResult fastResult; + if (operations->size() && executeResolveOperations(callFrame, callFrame->scope(), identifier, operations->data(), fastResult)) { + ASSERT(fastResult.base()); + ASSERT(!callFrame->hadException()); + return fastResult.base(); + } - PropertySlot slot(object); - if (!object->getPropertySlot(callFrame, identifier, slot)) - continue; + if (callFrame->hadException()) + return JSValue(); - return JSValue(object); - } while ((scope = scope->next())); + PropertySlot slot; + if (JSObject* base = JSScope::resolveContainingScope<ReturnBase>(callFrame, identifier, slot, operations, putToBaseOperations, isStrict)) { + ASSERT(operations->size()); + return base; + } if (!isStrict) return callFrame->lexicalGlobalObject(); @@ -213,50 +475,157 @@ JSValue JSScope::resolveBase(CallFrame* callFrame, const Identifier& identifier, return throwError(callFrame, createErrorForInvalidGlobalAssignment(callFrame, identifier.string())); } -JSValue JSScope::resolveWithBase(CallFrame* callFrame, const Identifier& identifier, Register* base) +JSValue JSScope::resolveWithBase(CallFrame* callFrame, const Identifier& identifier, Register* base, ResolveOperations* operations, PutToBaseOperation* putToBaseOperations) { - JSScope* scope = callFrame->scope(); - ASSERT(scope); - - do { - JSObject* object = JSScope::objectAtScope(scope); + ASSERT(operations); + ASSERT_UNUSED(putToBaseOperations, putToBaseOperations); + LookupResult fastResult; + if (operations->size() && executeResolveOperations(callFrame, callFrame->scope(), identifier, operations->data(), fastResult)) { + ASSERT(fastResult.base()); + ASSERT(fastResult.value()); + ASSERT(!callFrame->hadException()); + *base = fastResult.base(); + return fastResult.value(); + } - PropertySlot slot(object); - if (!object->getPropertySlot(callFrame, identifier, slot)) - continue; + if (callFrame->hadException()) + return JSValue(); + PropertySlot slot; + if (JSObject* propertyBase = JSScope::resolveContainingScope<ReturnBaseAndValue>(callFrame, identifier, slot, operations, putToBaseOperations, false)) { + ASSERT(operations->size()); JSValue value = slot.getValue(callFrame, identifier); if (callFrame->globalData().exception) return JSValue(); - *base = JSValue(object); + *base = propertyBase; return value; - } while ((scope = scope->next())); + } + ASSERT(operations->size()); return throwError(callFrame, createUndefinedVariableError(callFrame, identifier)); } -JSValue JSScope::resolveWithThis(CallFrame* callFrame, const Identifier& identifier, Register* base) +JSValue JSScope::resolveWithThis(CallFrame* callFrame, const Identifier& identifier, Register* base, ResolveOperations* operations) { - JSScope* scope = callFrame->scope(); - ASSERT(scope); - - do { - JSObject* object = JSScope::objectAtScope(scope); + ASSERT(operations); + LookupResult fastResult; + if (operations->size() && executeResolveOperations(callFrame, callFrame->scope(), identifier, operations->data(), fastResult)) { + ASSERT(fastResult.base()); + ASSERT(fastResult.value()); + ASSERT(!callFrame->hadException()); + *base = fastResult.base(); + return fastResult.value(); + } - PropertySlot slot(object); - if (!object->getPropertySlot(callFrame, identifier, slot)) - continue; + if (callFrame->hadException()) + return JSValue(); + PropertySlot slot; + if (JSObject* propertyBase = JSScope::resolveContainingScope<ReturnThisAndValue>(callFrame, identifier, slot, operations, 0, false)) { + ASSERT(operations->size()); JSValue value = slot.getValue(callFrame, identifier); if (callFrame->globalData().exception) return JSValue(); - - *base = object->structure()->typeInfo().isEnvironmentRecord() ? jsUndefined() : JSValue(object); + ASSERT(value); + *base = propertyBase->structure()->typeInfo().isEnvironmentRecord() ? jsUndefined() : JSValue(propertyBase); return value; - } while ((scope = scope->next())); + } + ASSERT(operations->size()); + + return throwError(callFrame, createUndefinedVariableError(callFrame, identifier)); +} + +void JSScope::resolvePut(CallFrame* callFrame, JSValue base, const Identifier& property, JSValue value, PutToBaseOperation* operation) +{ + ASSERT_UNUSED(operation, operation); + ASSERT(base); + ASSERT(value); + switch (operation->m_kind) { + case PutToBaseOperation::Uninitialised: + CRASH(); + + case PutToBaseOperation::Readonly: + return; + + case PutToBaseOperation::GlobalVariablePutChecked: + if (*operation->m_predicatePointer) + goto genericHandler; + case PutToBaseOperation::GlobalVariablePut: + if (operation->m_isDynamic) { + JSObject* baseObject = jsCast<JSObject*>(base); + if (baseObject != callFrame->lexicalGlobalObject()) { + if (baseObject->isGlobalObject()) + ASSERT(!jsCast<JSGlobalObject*>(baseObject)->assertRegisterIsInThisObject(operation->m_registerAddress)); + goto genericHandler; + } + } + operation->m_registerAddress->set(callFrame->globalData(), base.asCell(), value); + return; + + case PutToBaseOperation::VariablePut: { + if (operation->m_isDynamic) { + JSObject* baseObject = jsCast<JSObject*>(base); + if (baseObject->structure() != operation->m_structure.get()) + goto genericHandler; + } + JSVariableObject* variableObject = jsCast<JSVariableObject*>(base); + variableObject->registerAt(operation->m_offset).set(callFrame->globalData(), variableObject, value); + return; + } + + case PutToBaseOperation::GlobalPropertyPut: { + JSObject* object = jsCast<JSObject*>(base); + if (operation->m_structure.get() != object->structure()) + break; + object->putDirectOffset(callFrame->globalData(), operation->m_offset, value); + return; + } + + genericHandler: + case PutToBaseOperation::Generic: + PutPropertySlot slot(operation->m_isStrict); + base.put(callFrame, property, value, slot); + return; + } + ASSERT(operation->m_kind == PutToBaseOperation::GlobalPropertyPut); + PutPropertySlot slot(operation->m_isStrict); + base.put(callFrame, property, value, slot); + if (!slot.isCacheable()) + return; + if (callFrame->hadException()) + return; + JSObject* baseObject = jsCast<JSObject*>(base); + if (!baseObject->structure()->propertyAccessesAreCacheable()) + return; + if (slot.base() != callFrame->lexicalGlobalObject()) + return; + if (slot.base() != baseObject) + return; + ASSERT(!baseObject->hasInlineStorage()); + operation->m_structure.set(callFrame->globalData(), callFrame->codeBlock()->ownerExecutable(), baseObject->structure()); + setPutPropertyAccessOffset(operation, slot.cachedOffset()); + return; +} + +JSValue JSScope::resolveGlobal(CallFrame* callFrame, const Identifier& identifier, JSGlobalObject* globalObject, ResolveOperation* resolveOperation) +{ + ASSERT(resolveOperation); + ASSERT(resolveOperation->m_operation == ResolveOperation::GetAndReturnGlobalProperty); + ASSERT_UNUSED(globalObject, callFrame->lexicalGlobalObject() == globalObject); + + LookupResult fastResult; + if (executeResolveOperations(callFrame, callFrame->scope(), identifier, resolveOperation, fastResult)) { + ASSERT(fastResult.value()); + ASSERT(!callFrame->hadException()); + return fastResult.value(); + } + + if (callFrame->hadException()) + return JSValue(); return throwError(callFrame, createUndefinedVariableError(callFrame, identifier)); } + } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSScope.h b/Source/JavaScriptCore/runtime/JSScope.h index 011aff57e..a9a9dd8d8 100644 --- a/Source/JavaScriptCore/runtime/JSScope.h +++ b/Source/JavaScriptCore/runtime/JSScope.h @@ -27,6 +27,7 @@ #define JSScope_h #include "JSObject.h" +#include "ResolveOperation.h" namespace JSC { @@ -41,25 +42,12 @@ public: JS_EXPORT_PRIVATE static JSObject* objectAtScope(JSScope*); - static JSValue resolve(CallFrame*, const Identifier&); - static JSValue resolveSkip(CallFrame*, const Identifier&, int skip); - static JSValue resolveGlobal( - CallFrame*, - const Identifier&, - JSGlobalObject* globalObject, - WriteBarrierBase<Structure>* cachedStructure, - PropertyOffset* cachedOffset - ); - static JSValue resolveGlobalDynamic( - CallFrame*, - const Identifier&, - int skip, - WriteBarrierBase<Structure>* cachedStructure, - PropertyOffset* cachedOffset - ); - static JSValue resolveBase(CallFrame*, const Identifier&, bool isStrict); - static JSValue resolveWithBase(CallFrame*, const Identifier&, Register* base); - static JSValue resolveWithThis(CallFrame*, const Identifier&, Register* base); + static JSValue resolve(CallFrame*, const Identifier&, ResolveOperations*); + static JSValue resolveBase(CallFrame*, const Identifier&, bool isStrict, ResolveOperations*, PutToBaseOperation*); + static JSValue resolveWithBase(CallFrame*, const Identifier&, Register* base, ResolveOperations*, PutToBaseOperation*); + static JSValue resolveWithThis(CallFrame*, const Identifier&, Register* base, ResolveOperations*); + static JSValue resolveGlobal(CallFrame*, const Identifier&, JSGlobalObject*, ResolveOperation*); + static void resolvePut(CallFrame*, JSValue base, const Identifier&, JSValue, PutToBaseOperation*); static void visitChildren(JSCell*, SlotVisitor&); @@ -80,6 +68,16 @@ protected: private: WriteBarrier<JSScope> m_next; + enum ReturnValues { + ReturnValue = 1, + ReturnBase = 2, + ReturnThis = 4, + ReturnBaseAndValue = ReturnValue | ReturnBase, + ReturnThisAndValue = ReturnValue | ReturnThis, + }; + enum LookupMode { UnknownResolve, KnownResolve }; + template <LookupMode, ReturnValues> static JSObject* resolveContainingScopeInternal(CallFrame*, const Identifier&, PropertySlot&, ResolveOperations*, PutToBaseOperation*, bool isStrict); + template <ReturnValues> static JSObject* resolveContainingScope(CallFrame*, const Identifier&, PropertySlot&, ResolveOperations*, PutToBaseOperation*, bool isStrict); }; inline JSScope::JSScope(JSGlobalData& globalData, Structure* structure, JSScope* next) diff --git a/Source/JavaScriptCore/runtime/JSValue.cpp b/Source/JavaScriptCore/runtime/JSValue.cpp index 651e50cec..a5cdf700b 100644 --- a/Source/JavaScriptCore/runtime/JSValue.cpp +++ b/Source/JavaScriptCore/runtime/JSValue.cpp @@ -204,7 +204,7 @@ char* JSValue::description() const snprintf(description, size, "Int32: %d", asInt32()); else if (isDouble()) { #if USE(JSVALUE64) - snprintf(description, size, "Double: %lx, %lf", reinterpretDoubleToIntptr(asDouble()), asDouble()); + snprintf(description, size, "Double: %lld, %lf", (long long)reinterpretDoubleToInt64(asDouble()), asDouble()); #else union { double asDouble; diff --git a/Source/JavaScriptCore/runtime/JSValue.h b/Source/JavaScriptCore/runtime/JSValue.h index 6e01d8d2d..7b5c81aa9 100644 --- a/Source/JavaScriptCore/runtime/JSValue.h +++ b/Source/JavaScriptCore/runtime/JSValue.h @@ -69,11 +69,7 @@ namespace JSC { enum PreferredPrimitiveType { NoPreference, PreferNumber, PreferString }; -#if USE(JSVALUE32_64) typedef int64_t EncodedJSValue; -#else - typedef void* EncodedJSValue; -#endif union EncodedValueDescriptor { int64_t asInt64; @@ -390,9 +386,9 @@ namespace JSC { EncodedValueDescriptor u; }; -#if USE(JSVALUE32_64) typedef IntHash<EncodedJSValue> EncodedJSValueHash; +#if USE(JSVALUE32_64) struct EncodedJSValueHashTraits : HashTraits<EncodedJSValue> { static const bool emptyValueIsZero = false; static EncodedJSValue emptyValue() { return JSValue::encode(JSValue()); } @@ -400,8 +396,6 @@ namespace JSC { static bool isDeletedValue(EncodedJSValue value) { return value == JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); } }; #else - typedef PtrHash<EncodedJSValue> EncodedJSValueHash; - struct EncodedJSValueHashTraits : HashTraits<EncodedJSValue> { static void constructDeletedValue(EncodedJSValue& slot) { slot = JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); } static bool isDeletedValue(EncodedJSValue value) { return value == JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); } diff --git a/Source/JavaScriptCore/runtime/JSValueInlineMethods.h b/Source/JavaScriptCore/runtime/JSValueInlineMethods.h index 4c582ab2a..52b747890 100644 --- a/Source/JavaScriptCore/runtime/JSValueInlineMethods.h +++ b/Source/JavaScriptCore/runtime/JSValueInlineMethods.h @@ -140,7 +140,6 @@ namespace JSC { *this = JSValue(static_cast<int32_t>(d)); } -#if USE(JSVALUE32_64) inline EncodedJSValue JSValue::encode(JSValue value) { return value.u.asInt64; @@ -153,6 +152,7 @@ namespace JSC { return v; } +#if USE(JSVALUE32_64) inline JSValue::JSValue() { u.asBits.tag = EmptyValueTag; @@ -333,17 +333,6 @@ namespace JSC { #else // !USE(JSVALUE32_64) i.e. USE(JSVALUE64) - // JSValue member functions. - inline EncodedJSValue JSValue::encode(JSValue value) - { - return value.u.ptr; - } - - inline JSValue JSValue::decode(EncodedJSValue ptr) - { - return JSValue(reinterpret_cast<JSCell*>(ptr)); - } - // 0x0 can never occur naturally because it has a tag of 00, indicating a pointer value, but a payload of 0x0, which is in the (invalid) zero page. inline JSValue::JSValue() { @@ -358,27 +347,27 @@ namespace JSC { inline JSValue::JSValue(JSCell* ptr) { - u.ptr = ptr; + u.asInt64 = reinterpret_cast<uintptr_t>(ptr); } inline JSValue::JSValue(const JSCell* ptr) { - u.ptr = const_cast<JSCell*>(ptr); + u.asInt64 = reinterpret_cast<uintptr_t>(const_cast<JSCell*>(ptr)); } inline JSValue::operator bool() const { - return u.ptr; + return u.asInt64; } inline bool JSValue::operator==(const JSValue& other) const { - return u.ptr == other.u.ptr; + return u.asInt64 == other.u.asInt64; } inline bool JSValue::operator!=(const JSValue& other) const { - return u.ptr != other.u.ptr; + return u.asInt64 != other.u.asInt64; } inline bool JSValue::isEmpty() const @@ -464,18 +453,18 @@ namespace JSC { return (u.asInt64 & TagTypeNumber) == TagTypeNumber; } - inline intptr_t reinterpretDoubleToIntptr(double value) + inline int64_t reinterpretDoubleToInt64(double value) { - return bitwise_cast<intptr_t>(value); + return bitwise_cast<int64_t>(value); } - inline double reinterpretIntptrToDouble(intptr_t value) + inline double reinterpretInt64ToDouble(int64_t value) { return bitwise_cast<double>(value); } ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d) { - u.asInt64 = reinterpretDoubleToIntptr(d) + DoubleEncodeOffset; + u.asInt64 = reinterpretDoubleToInt64(d) + DoubleEncodeOffset; } inline JSValue::JSValue(int i) @@ -486,7 +475,7 @@ namespace JSC { inline double JSValue::asDouble() const { ASSERT(isDouble()); - return reinterpretIntptrToDouble(u.asInt64 - DoubleEncodeOffset); + return reinterpretInt64ToDouble(u.asInt64 - DoubleEncodeOffset); } inline bool JSValue::isNumber() const diff --git a/Source/JavaScriptCore/runtime/JSVariableObject.cpp b/Source/JavaScriptCore/runtime/JSVariableObject.cpp index c815dcd11..9b03a2c64 100644 --- a/Source/JavaScriptCore/runtime/JSVariableObject.cpp +++ b/Source/JavaScriptCore/runtime/JSVariableObject.cpp @@ -31,4 +31,6 @@ namespace JSC { +const ClassInfo JSVariableObject::s_info = { "VariableObject", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSVariableObject) }; + } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSVariableObject.h b/Source/JavaScriptCore/runtime/JSVariableObject.h index 25961dc09..3ff7aa841 100644 --- a/Source/JavaScriptCore/runtime/JSVariableObject.h +++ b/Source/JavaScriptCore/runtime/JSVariableObject.h @@ -53,6 +53,8 @@ namespace JSC { WriteBarrierBase<Unknown>* const * addressOfRegisters() const { return &m_registers; } static size_t offsetOfRegisters() { return OBJECT_OFFSETOF(JSVariableObject, m_registers); } + static const ClassInfo s_info; + protected: static const unsigned StructureFlags = Base::StructureFlags; diff --git a/Source/JavaScriptCore/runtime/RegExpKey.h b/Source/JavaScriptCore/runtime/RegExpKey.h index f93fbbc1d..58fa38725 100644 --- a/Source/JavaScriptCore/runtime/RegExpKey.h +++ b/Source/JavaScriptCore/runtime/RegExpKey.h @@ -73,9 +73,17 @@ struct RegExpKey { , pattern(pattern) { } + + friend inline bool operator==(const RegExpKey& a, const RegExpKey& b); + + struct Hash { + static unsigned hash(const RegExpKey& key) { return key.pattern->hash(); } + static bool equal(const RegExpKey& a, const RegExpKey& b) { return a == b; } + static const bool safeToCompareToEmptyOrDeleted = false; + }; }; -inline bool operator==(const RegExpKey& a, const RegExpKey& b) +inline bool operator==(const RegExpKey& a, const RegExpKey& b) { if (a.flagsValue != b.flagsValue) return false; @@ -90,16 +98,9 @@ inline bool operator==(const RegExpKey& a, const RegExpKey& b) namespace WTF { template<typename T> struct DefaultHash; -template<typename T> struct RegExpHash; - -template<> struct RegExpHash<JSC::RegExpKey> { - static unsigned hash(const JSC::RegExpKey& key) { return key.pattern->hash(); } - static bool equal(const JSC::RegExpKey& a, const JSC::RegExpKey& b) { return a == b; } - static const bool safeToCompareToEmptyOrDeleted = false; -}; template<> struct DefaultHash<JSC::RegExpKey> { - typedef RegExpHash<JSC::RegExpKey> Hash; + typedef JSC::RegExpKey::Hash Hash; }; template<> struct HashTraits<JSC::RegExpKey> : GenericHashTraits<JSC::RegExpKey> { diff --git a/Source/JavaScriptCore/runtime/StringRecursionChecker.h b/Source/JavaScriptCore/runtime/StringRecursionChecker.h index 127d028e0..831e25b46 100644 --- a/Source/JavaScriptCore/runtime/StringRecursionChecker.h +++ b/Source/JavaScriptCore/runtime/StringRecursionChecker.h @@ -21,6 +21,7 @@ #define StringRecursionChecker_h #include "Interpreter.h" +#include <wtf/StackStats.h> namespace JSC { @@ -41,6 +42,8 @@ private: ExecState* m_exec; JSObject* m_thisObject; JSValue m_earlyReturnValue; + + StackStats::CheckPoint stackCheckpoint; }; inline JSValue StringRecursionChecker::performCheck() diff --git a/Source/JavaScriptCore/runtime/Structure.h b/Source/JavaScriptCore/runtime/Structure.h index f45e9f1d9..5f1299766 100644 --- a/Source/JavaScriptCore/runtime/Structure.h +++ b/Source/JavaScriptCore/runtime/Structure.h @@ -140,6 +140,8 @@ namespace JSC { bool isDictionary() const { return m_dictionaryKind != NoneDictionaryKind; } bool isUncacheableDictionary() const { return m_dictionaryKind == UncachedDictionaryKind; } + bool propertyAccessesAreCacheable() { return m_dictionaryKind != UncachedDictionaryKind && !typeInfo().prohibitsPropertyCaching(); } + // Type accessors. const TypeInfo& typeInfo() const { ASSERT(structure()->classInfo() == &s_info); return m_typeInfo; } bool isObject() const { return typeInfo().isObject(); } |