summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/runtime
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2012-10-22 15:40:17 +0200
committerSimon Hausmann <simon.hausmann@digia.com>2012-10-22 15:40:17 +0200
commit43a42f108af6bcbd91f2672731c3047c26213af1 (patch)
tree7fa092e5f5d873c72f2486a70e26be26f7a38bec /Source/JavaScriptCore/runtime
parentd9cf437c840c6eb7417bdd97e6c40979255d3158 (diff)
downloadqtwebkit-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.cpp597
-rw-r--r--Source/JavaScriptCore/runtime/JSScope.h36
-rw-r--r--Source/JavaScriptCore/runtime/JSValue.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/JSValue.h8
-rw-r--r--Source/JavaScriptCore/runtime/JSValueInlineMethods.h33
-rw-r--r--Source/JavaScriptCore/runtime/JSVariableObject.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/JSVariableObject.h2
-rw-r--r--Source/JavaScriptCore/runtime/RegExpKey.h19
-rw-r--r--Source/JavaScriptCore/runtime/StringRecursionChecker.h3
-rw-r--r--Source/JavaScriptCore/runtime/Structure.h2
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(); }