Reviewed by Oliver Hunt.
Optimized global access to global variables, using a symbol table.
SunSpider reports a 1.5% overall speedup, a 6.2% speedup on 3d-morph,
and a whopping 33.1% speedup on bitops-bitwise-and.
* API/JSCallbackObjectFunctions.h: Replaced calls to JSObject:: with
calls to Base::, since JSObject is not always our base class. This
was always a bug, but the bug is even more apparent after some of my
changes.
(KJS::::staticFunctionGetter): Replaced use of getDirect with call to
getOwnPropertySlot. Global declarations are no longer stored in the
property map, so a call to getDirect is insufficient for finding
override properties.
* API/testapi.c:
* API/testapi.js: Added test for the getDirect change mentioned above.
* kjs/ExecState.cpp:
* kjs/ExecState.h: Dialed back the optimization to store a direct
pointer to the localStorage buffer. One ExecState can grow the global
object's localStorage without another ExecState's knowledge, so
ExecState can't store a direct pointer to the localStorage buffer
unless/until we invent a way to update all the relevant ExecStates.
* kjs/JSGlobalObject.cpp: Inserted the symbol table into get and put
operations.
(KJS::JSGlobalObject::reset): Reset the symbol table and local storage,
too. Also, clear the property map here, removing the need for a
separate call.
* kjs/JSVariableObject.cpp:
* kjs/JSVariableObject.h: Added support for saving localStorage and the
symbol table to the back/forward cache, and restoring them.
* kjs/function.cpp:
(KJS::GlobalFuncImp::callAsFunction): Renamed progNode to evalNode
because it's an EvalNode, not a ProgramNode.
* kjs/lookup.h:
(KJS::cacheGlobalObject): Replaced put with faster putDirect, since
that's how the rest of lookup.h works. putDirect is safe here because
cacheGlobalObject is only used for objects whose names are not valid
identifiers.
* kjs/nodes.cpp: The good stuff!
(KJS::EvalNode::processDeclarations): Replaced hasProperty with
the new hasOwnProperty, which is slightly faster.
* kjs/object.h: Nixed clearProperties because clear() does this job now.
* kjs/property_map.cpp:
* kjs/property_map.h: More back/forward cache support.
* wtf/Vector.h:
(WTF::::grow): Added fast non-branching grow function. I used it in
an earlier version of this patch, even though it's not used anymore.
JavaScriptGlue:
Build fix.
* ForwardingHeaders/wtf/VectorTraits.h: Added.
WebCore:
Reviewed by Oliver Hunt.
Build support:
* ForwardingHeaders/kjs/SymbolTable.h: Added.
* ForwardingHeaders/wtf/VectorTraits.h: Added.
* bindings/js/JSDOMWindowCustom.cpp:
(WebCore::JSDOMWindow::customGetOwnPropertySlot): Replaced use of
getDirectLocation with getOwnPropertySlot. getDirectLocation is no
longer valid, since global declarations are not stored in the property
map.
(WebCore::JSDOMWindow::customPut): Replaced use of JSObject::put with
JSGlobalObject::put. JSObject::put is no longer valid, since global
declarations are not stored in the property map.
* bindings/js/kjs_window.cpp: Replaced JSObject:: calls with Base::
calls, since JSObject is not our base class. This was always a bug, but
the bug is even more apparent after some of my changes.
(KJS::Window::clear): Removed call to clearProperties because
JSGlobalObject::reset takes care of that now.
* history/CachedPage.cpp:
* history/CachedPage.h: Added support for saving a symbol table and
localStorage to the page cache, and restoring it.
WebKit/mac:
Reviewed by Oliver Hunt.
Build fix.
* ForwardingHeaders/kjs/SymbolTable.h: Added.
* ForwardingHeaders/wtf/VectorTraits.h: Added.
LayoutTests:
Reviewed by Oliver Hunt.
Added some tests to verify some of the changes I made while optimizing
global access to global variables.
* fast/dom/Window/resources/window-property-clearing-iframe0.html: Added.
* fast/dom/Window/resources/window-property-clearing-iframe1.html: Added.
* fast/dom/Window/window-property-clearing-expected.txt: Added.
* fast/dom/Window/window-property-clearing.html: Added.
* fast/dom/getter-on-window-object2-expected.txt: Added.
* fast/dom/getter-on-window-object2.html: Added.
Checked in failing results for these const tests. The symbol table
optimization broke const. (We didn't know this before because our only
tests used global variables.)
* fast/js/const-expected.txt:
* fast/js/kde/const-expected.txt:
* fast/js/resources/for-in-avoid-duplicates.js: Fixed a typo I noticed.
Not related to this patch.
* fast/dom/Window/window-property-shadowing.html: Changed this test to
use "this" instead of "window". The fact that "window" worked before,
despite an overriding / shadowing var declaration, was a bug.
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@28884
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
if (!m_class->className.isNull())
return m_class->className;
- return JSObject::className();
+ return Base::className();
}
template <class Base>
}
}
- return JSObject::getOwnPropertySlot(exec, propertyName, slot);
+ return Base::getOwnPropertySlot(exec, propertyName, slot);
}
template <class Base>
}
}
- return JSObject::put(exec, propertyName, value, attr);
+ return Base::put(exec, propertyName, value, attr);
}
template <class Base>
}
}
- return JSObject::deleteProperty(exec, propertyName);
+ return Base::deleteProperty(exec, propertyName);
}
template <class Base>
}
}
- JSObject::getPropertyNames(exec, propertyNames);
+ Base::getPropertyNames(exec, propertyNames);
}
template <class Base>
return toJS(value)->getNumber();
}
- return JSObject::toNumber(exec);
+ return Base::toNumber(exec);
}
template <class Base>
return toJS(value)->getString();
}
- return JSObject::toString(exec);
+ return Base::toString(exec);
}
template <class Base>
ASSERT(slot.slotBase()->inherits(&JSCallbackObject::info));
JSCallbackObject* thisObj = static_cast<JSCallbackObject*>(slot.slotBase());
- if (JSValue* cachedOrOverrideValue = thisObj->getDirect(propertyName))
- return cachedOrOverrideValue;
+ // Check for cached or override property.
+ PropertySlot slot2;
+ if (thisObj->Base::getOwnPropertySlot(exec, propertyName, slot2))
+ return slot2.getValue(exec, thisObj, propertyName);
for (JSClassRef jsClass = thisObj->m_class; jsClass; jsClass = jsClass->parentClass) {
if (OpaqueJSClass::StaticFunctionsTable* staticFunctions = jsClass->staticFunctions) {
return true;
}
+static JSValueRef globalObject_call(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ UNUSED_PARAM(function);
+ UNUSED_PARAM(thisObject);
+ UNUSED_PARAM(argumentCount);
+ UNUSED_PARAM(arguments);
+ UNUSED_PARAM(exception);
+
+ return JSValueMakeNumber(ctx, 3);
+}
static JSStaticValue globalObject_staticValues[] = {
{ "globalStaticValue", globalObject_get, globalObject_set, kJSPropertyAttributeNone },
{ 0, 0, 0, 0 }
};
+static JSStaticFunction globalObject_staticFunctions[] = {
+ { "globalStaticFunction", globalObject_call, kJSPropertyAttributeNone },
+ { 0, 0, 0 }
+};
+
static char* createStringWithContentsOfFile(const char* fileName);
static void testInitializeFinalize()
JSClassDefinition globalObjectClassDefinition = kJSClassDefinitionEmpty;
globalObjectClassDefinition.initialize = globalObject_initialize;
globalObjectClassDefinition.staticValues = globalObject_staticValues;
+ globalObjectClassDefinition.staticFunctions = globalObject_staticFunctions;
+ globalObjectClassDefinition.attributes = kJSClassAttributeNoAutomaticPrototype;
JSClassRef globalObjectClass = JSClassCreate(&globalObjectClassDefinition);
context = JSGlobalContextCreate(globalObjectClass);
print(result);
}
+function globalStaticFunction()
+{
+ return 4;
+}
+
shouldBe("globalStaticValue", 3);
+shouldBe("globalStaticFunction()", 4);
shouldBe("typeof MyObject", "function"); // our object implements 'call'
MyObject.cantFind = 1;
+2007-12-19 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Optimized global access to global variables, using a symbol table.
+
+ SunSpider reports a 1.5% overall speedup, a 6.2% speedup on 3d-morph,
+ and a whopping 33.1% speedup on bitops-bitwise-and.
+
+ * API/JSCallbackObjectFunctions.h: Replaced calls to JSObject:: with
+ calls to Base::, since JSObject is not always our base class. This
+ was always a bug, but the bug is even more apparent after some of my
+ changes.
+
+ (KJS::::staticFunctionGetter): Replaced use of getDirect with call to
+ getOwnPropertySlot. Global declarations are no longer stored in the
+ property map, so a call to getDirect is insufficient for finding
+ override properties.
+
+ * API/testapi.c:
+ * API/testapi.js: Added test for the getDirect change mentioned above.
+
+ * kjs/ExecState.cpp:
+ * kjs/ExecState.h: Dialed back the optimization to store a direct
+ pointer to the localStorage buffer. One ExecState can grow the global
+ object's localStorage without another ExecState's knowledge, so
+ ExecState can't store a direct pointer to the localStorage buffer
+ unless/until we invent a way to update all the relevant ExecStates.
+
+ * kjs/JSGlobalObject.cpp: Inserted the symbol table into get and put
+ operations.
+ (KJS::JSGlobalObject::reset): Reset the symbol table and local storage,
+ too. Also, clear the property map here, removing the need for a
+ separate call.
+
+ * kjs/JSVariableObject.cpp:
+ * kjs/JSVariableObject.h: Added support for saving localStorage and the
+ symbol table to the back/forward cache, and restoring them.
+
+ * kjs/function.cpp:
+ (KJS::GlobalFuncImp::callAsFunction): Renamed progNode to evalNode
+ because it's an EvalNode, not a ProgramNode.
+
+ * kjs/lookup.h:
+ (KJS::cacheGlobalObject): Replaced put with faster putDirect, since
+ that's how the rest of lookup.h works. putDirect is safe here because
+ cacheGlobalObject is only used for objects whose names are not valid
+ identifiers.
+
+ * kjs/nodes.cpp: The good stuff!
+
+ (KJS::EvalNode::processDeclarations): Replaced hasProperty with
+ the new hasOwnProperty, which is slightly faster.
+
+ * kjs/object.h: Nixed clearProperties because clear() does this job now.
+
+ * kjs/property_map.cpp:
+ * kjs/property_map.h: More back/forward cache support.
+
+ * wtf/Vector.h:
+ (WTF::::grow): Added fast non-branching grow function. I used it in
+ an earlier version of this patch, even though it's not used anymore.
+
2007-12-09 Mark Rowe <mrowe@apple.com>
Reviewed by Oliver Hunt.
__ZN3KJS14JSGlobalObject15restoreBuiltinsERKNS_13SavedBuiltinsE
__ZN3KJS14JSGlobalObject16stopTimeoutCheckEv
__ZN3KJS14JSGlobalObject17startTimeoutCheckEv
+__ZN3KJS14JSGlobalObject18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE
+__ZN3KJS14JSGlobalObject3putEPNS_9ExecStateERKNS_10IdentifierEPNS_7JSValueEi
__ZN3KJS14JSGlobalObject4initEv
__ZN3KJS14JSGlobalObject4markEv
__ZN3KJS14JSGlobalObject5resetEPNS_7JSValueE
__ZNK3KJS12DateInstance7getTimeERdRi
__ZNK3KJS13ArrayInstance7getItemEj
__ZNK3KJS14JSGlobalObject12saveBuiltinsERNS_13SavedBuiltinsE
+__ZNK3KJS16JSVariableObject15saveSymbolTableERN3WTF7HashMapINS1_6RefPtrINS_7UString3RepEEEmNS_17IdentifierRepHashENS_23IdentifierRepHashTraitsENS_26SymbolTableIndexHashTraitsEEE
+__ZNK3KJS16JSVariableObject16saveLocalStorageERNS_15SavedPropertiesE
+__ZNK3KJS16JSVariableObject18restoreSymbolTableERN3WTF7HashMapINS1_6RefPtrINS_7UString3RepEEEmNS_17IdentifierRepHashENS_23IdentifierRepHashTraitsENS_26SymbolTableIndexHashTraitsEEE
+__ZNK3KJS16JSVariableObject19restoreLocalStorageERNS_15SavedPropertiesE
__ZNK3KJS19InternalFunctionImp14implementsCallEv
__ZNK3KJS19InternalFunctionImp21implementsHasInstanceEv
__ZNK3KJS4List8getSliceEiRS0_
m_thisVal = thisV;
break;
}
+
+ m_localStorage = &m_variableObject->localStorage();
if (scopeNode)
m_globalObject->setCurrentExec(this);
return dynamicGlobalObject();
}
-
-void ExecState::updateLocalStorage()
-{
- m_localStorageBuffer = m_activation->localStorage().data();
-}
} // namespace KJS
#ifndef ExecState_H
#define ExecState_H
-#include "value.h"
-#include "types.h"
-#include "CommonIdentifiers.h"
#include "LabelStack.h"
+#include "LocalStorage.h"
#include "scope_chain.h"
+#include "types.h"
namespace KJS {
};
class ActivationImp;
+ class CommonIdentifiers;
class FunctionImp;
class GlobalFuncImp;
class Interpreter;
JSObject* thisValue() const { return m_thisVal; }
ExecState* callingExecState() { return m_callingExec; }
+ ExecState* savedExec() { return m_savedExec; }
ActivationImp* activationObject() { return m_activation; }
CodeType codeType() { return m_codeType; }
// important property lookup functions, to avoid taking PIC branches in Mach-O binaries
const CommonIdentifiers& propertyNames() const { return *m_propertyNames; }
- LocalStorageEntry* localStorage() { return m_localStorageBuffer; }
- void updateLocalStorage();
+ LocalStorage& localStorage() { return *m_localStorage; }
public:
ExecState(JSGlobalObject* glob, JSObject* thisV,
FunctionImp* m_function;
const List* m_arguments;
ActivationImp* m_activation;
- LocalStorageEntry* m_localStorageBuffer;
+ LocalStorage* m_localStorage;
ScopeChain m_scopeChain;
JSVariableObject* m_variableObject;
reset(prototype());
}
+bool JSGlobalObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ if (symbolTableGet(propertyName, slot))
+ return true;
+ return JSVariableObject::getOwnPropertySlot(exec, propertyName, slot);
+}
+
+void JSGlobalObject::put(ExecState* exec, const Identifier& propertyName, JSValue* value, int attr)
+{
+ if (symbolTablePut(propertyName, value, attr))
+ return;
+ return JSVariableObject::put(exec, propertyName, value, attr);
+}
+
static inline JSObject* lastInPrototypeChain(JSObject* object)
{
JSObject* o = object;
void JSGlobalObject::reset(JSValue* prototype)
{
- // Clear before inititalizing, to avoid marking uninitialized (dangerous) or
- // stale (wasteful) pointers during possible garbage collection while creating
- // new objects below.
+ // Clear before inititalizing, to avoid calling mark() on stale pointers --
+ // which would be wasteful -- or uninitialized pointers -- which would be
+ // dangerous. (The allocations below may cause a GC.)
- ExecState* exec = &d()->globalExec;
+ _prop.clear();
+ localStorage().clear();
+ symbolTable().clear();
// Prototypes
d()->functionPrototype = 0;
d()->typeErrorConstructor = 0;
d()->URIErrorConstructor = 0;
+ ExecState* exec = &d()->globalExec;
+
// Prototypes
d()->functionPrototype = new FunctionPrototype(exec);
d()->objectPrototype = new ObjectPrototype(exec, d()->functionPrototype);
public:
virtual ~JSGlobalObject();
+ virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
+ virtual void put(ExecState*, const Identifier&, JSValue*, int attr = None);
+
// Linked list of all global objects.
static JSGlobalObject* head() { return s_head; }
JSGlobalObject* next() { return d()->next; }
#include "JSVariableObject.h"
#include "PropertyNameArray.h"
+#include "property_map.h"
namespace KJS {
UString::Rep* IdentifierRepHashTraits::nullRepPtr = &UString::Rep::null; // Didn't want to make a whole source file for just this.
+void JSVariableObject::saveSymbolTable(SymbolTable& s) const
+{
+ s = *d->symbolTable;
+}
+
+void JSVariableObject::restoreSymbolTable(SymbolTable& s) const
+{
+ *d->symbolTable = s;
+}
+
+void JSVariableObject::saveLocalStorage(SavedProperties& p) const
+{
+ unsigned count = d->localStorage.size();
+
+ p.m_properties.clear();
+ p.m_count = count;
+
+ if (!count)
+ return;
+
+ p.m_properties.set(new SavedProperty[count]);
+
+ SavedProperty* prop = p.m_properties.get();
+ for (size_t i = 0; i < count; ++i, ++prop) {
+ LocalStorageEntry& entry = d->localStorage[i];
+ prop->value = entry.value;
+ prop->attributes = entry.attributes;
+ }
+}
+
+void JSVariableObject::restoreLocalStorage(SavedProperties& p) const
+{
+ unsigned count = p.m_count;
+ d->localStorage.resize(count);
+ SavedProperty* prop = p.m_properties.get();
+ for (size_t i = 0; i < count; ++i, ++prop)
+ d->localStorage[i] = LocalStorageEntry(prop->value, prop->attributes);
+}
+
bool JSVariableObject::deleteProperty(ExecState* exec, const Identifier& propertyName)
{
if (symbolTable().contains(propertyName.ustring().rep()))
public:
SymbolTable& symbolTable() { return *d->symbolTable; }
LocalStorage& localStorage() { return d->localStorage; }
+
+ void saveSymbolTable(SymbolTable& s) const;
+ void restoreSymbolTable(SymbolTable& s) const;
+ void saveLocalStorage(SavedProperties& s) const;
+ void restoreLocalStorage(SavedProperties& s) const;
+
virtual bool deleteProperty(ExecState*, const Identifier&);
virtual void getPropertyNames(ExecState*, PropertyNameArray&);
#ifndef KJS_LOCAL_STORAGE_H
#define KJS_LOCAL_STORAGE_H
-#include <wtf/Vector.h>
+#include <wtf/Forward.h>
+#include <wtf/VectorTraits.h>
namespace KJS {
class JSValue;
int sourceId;
int errLine;
UString errMsg;
- RefPtr<EvalNode> progNode(parser().parse<EvalNode>(UString(), 0, s.data(), s.size(), &sourceId, &errLine, &errMsg));
+ RefPtr<EvalNode> evalNode = parser().parse<EvalNode>(UString(), 0, s.data(), s.size(), &sourceId, &errLine, &errMsg);
Debugger* dbg = exec->dynamicGlobalObject()->debugger();
if (dbg) {
}
// no program node means a syntax occurred
- if (!progNode)
+ if (!evalNode)
return throwError(exec, SyntaxError, errMsg, errLine, sourceId, NULL);
bool switchGlobal = thisObj && thisObj != exec->dynamicGlobalObject() && thisObj->isGlobalObject();
// enter a new execution context
JSGlobalObject* globalObject = switchGlobal ? static_cast<JSGlobalObject*>(thisObj) : exec->dynamicGlobalObject();
JSObject* thisVal = static_cast<JSObject*>(exec->thisValue());
- ExecState newExec(globalObject, thisVal, progNode.get(), EvalCode, exec, globalObject->currentExec());
+ ExecState newExec(globalObject, thisVal, evalNode.get(), EvalCode, exec, globalObject->currentExec());
if (exec->hadException())
newExec.setException(exec->exception());
newExec.setVariableObject(static_cast<JSGlobalObject*>(thisObj));
}
- Completion c = progNode->execute(&newExec);
+ Completion c = evalNode->execute(&newExec);
if (switchGlobal)
newExec.popScope();
return static_cast<JSObject* >(obj);
}
JSObject* newObject = new ClassCtor(exec);
- globalObject->put(exec, propertyName, newObject, Internal | DontEnum);
+ globalObject->putDirect(propertyName, newObject, Internal | DontEnum);
return newObject;
}
// ECMA 12.2
inline void VarDeclNode::evaluateSingle(ExecState* exec)
{
+ ASSERT(exec->variableObject()->hasOwnProperty(exec, ident) || exec->codeType() == EvalCode); // Guaranteed by processDeclarations.
const ScopeChain& chain = exec->scopeChain();
JSObject* variableObject = exec->variableObject();
bool inGlobalScope = ++chain.begin() == chain.end();
- if (inGlobalScope && (init || !variableObject->getDirect(ident))) {
- JSValue* val = init ? init->evaluate(exec) : jsUndefined();
- int flags = Internal;
- if (exec->codeType() != EvalCode)
- flags |= DontDelete;
- if (varType == VarDeclNode::Constant)
- flags |= ReadOnly;
- variableObject->putDirect(ident, val, flags);
- } else if (init) {
- JSValue* val = init->evaluate(exec);
- KJS_CHECKEXCEPTIONVOID
+ if (init) {
+ if (inGlobalScope) {
+ JSValue* val = init->evaluate(exec);
+ int flags = Internal;
+ if (exec->codeType() != EvalCode)
+ flags |= DontDelete;
+ if (varType == VarDeclNode::Constant)
+ flags |= ReadOnly;
+ variableObject->put(exec, ident, val, flags);
+ } else {
+ JSValue* val = init->evaluate(exec);
+ KJS_CHECKEXCEPTIONVOID
+
+ // if the variable object is the top of the scope chain, then that must
+ // be where this variable is declared, processVarDecls would have put
+ // it there. Don't search the scope chain, to optimize this very common case.
+ if (chain.top() != variableObject)
+ return handleSlowCase(exec, chain, val);
+
+ unsigned flags = 0;
+ variableObject->getPropertyAttributes(ident, flags);
+ if (varType == VarDeclNode::Constant)
+ flags |= ReadOnly;
- // if the variable object is the top of the scope chain, then that must
- // be where this variable is declared, processVarDecls would have put
- // it there. Don't search the scope chain, to optimize this very common case.
- if (chain.top() != variableObject)
- return handleSlowCase(exec, chain, val);
-
- unsigned flags = 0;
- variableObject->getPropertyAttributes(ident, flags);
- if (varType == VarDeclNode::Constant)
- flags |= ReadOnly;
-
- ASSERT(variableObject->hasProperty(exec, ident));
- variableObject->put(exec, ident, val, flags);
+ variableObject->put(exec, ident, val, flags);
+ }
}
}
void FunctionBodyNode::initializeSymbolTable(ExecState* exec)
{
- size_t i, size;
- size_t count = 0;
+ SymbolTable& symbolTable = exec->variableObject()->symbolTable();
+ ASSERT(!symbolTable.size());
- // The order of additions here implicitly enforces the mutual exclusion described in ECMA 10.1.3.
- for (i = 0, size = m_varStack.size(); i < size; ++i) {
- if (m_varStack[i]->ident != exec->propertyNames().arguments)
- m_symbolTable.set(m_varStack[i]->ident.ustring().rep(), count);
- count++;
+ size_t localStorageIndex = 0;
+
+ for (size_t i = 0, size = m_parameters.size(); i < size; ++i, ++localStorageIndex) {
+ UString::Rep* rep = m_parameters[i].ustring().rep();
+ symbolTable.set(rep, localStorageIndex);
}
- for (i = 0, size = m_parameters.size(); i < size; ++i)
- m_symbolTable.set(m_parameters[i].ustring().rep(), count++);
+ for (size_t i = 0, size = m_functionStack.size(); i < size; ++i, ++localStorageIndex) {
+ UString::Rep* rep = m_functionStack[i]->ident.ustring().rep();
+ symbolTable.set(rep, localStorageIndex);
+ }
- for (i = 0, size = m_functionStack.size(); i < size; ++i)
- m_symbolTable.set(m_functionStack[i]->ident.ustring().rep(), count++);
+ for (size_t i = 0, size = m_varStack.size(); i < size; ++i, ++localStorageIndex) {
+ Identifier& ident = m_varStack[i]->ident;
+ if (ident == exec->propertyNames().arguments)
+ continue;
+ symbolTable.add(ident.ustring().rep(), localStorageIndex);
+ }
}
-void FunctionBodyNode::optimizeVariableAccess()
+void ProgramNode::initializeSymbolTable(ExecState* exec)
+{
+ // If a previous script defined a symbol with the same name as one of our
+ // symbols, to avoid breaking previously optimized nodes, we need to reuse
+ // the symbol's existing storage index. So, we can't be as efficient as
+ // FunctionBodyNode::initializeSymbolTable, which knows that no bindings
+ // have yet been made.
+
+ JSVariableObject* variableObject = exec->variableObject();
+ SymbolTable& symbolTable = variableObject->symbolTable();
+
+ size_t localStorageIndex = symbolTable.size();
+ size_t size;
+
+ size = m_functionStack.size();
+ m_functionIndexes.resize(size);
+ for (size_t i = 0; i < size; ++i) {
+ UString::Rep* rep = m_functionStack[i]->ident.ustring().rep();
+ pair<SymbolTable::iterator, bool> result = symbolTable.add(rep, localStorageIndex);
+ m_functionIndexes[i] = result.first->second;
+ if (result.second)
+ ++localStorageIndex;
+ }
+
+ size = m_varStack.size();
+ m_varIndexes.resize(size);
+ for (size_t i = 0; i < size; ++i) {
+ const Identifier& ident = m_varStack[i]->ident;
+ if (variableObject->getDirect(ident)) {
+ m_varIndexes[i] = missingSymbolMarker(); // Signal not to initialize this declaration.
+ continue;
+ }
+
+ UString::Rep* rep = ident.ustring().rep();
+ pair<SymbolTable::iterator, bool> result = symbolTable.add(rep, localStorageIndex);
+ if (!result.second) {
+ m_varIndexes[i] = missingSymbolMarker(); // Signal not to initialize this declaration.
+ continue;
+ }
+ m_varIndexes[i] = result.first->second;
+ ++localStorageIndex;
+ }
+}
+
+void ScopeNode::optimizeVariableAccess(ExecState* exec)
{
DeclarationStacks::NodeStack nodeStack;
Node* node = statementListInitializeVariableAccessStack(*m_children, nodeStack);
if (!node)
return;
+ SymbolTable& symbolTable = exec->variableObject()->symbolTable();
while (true) {
- node->optimizeVariableAccess(m_symbolTable, nodeStack);
+ node->optimizeVariableAccess(symbolTable, nodeStack);
size_t size = nodeStack.size();
if (!size)
{
if (!m_initialized) {
initializeSymbolTable(exec);
- optimizeVariableAccess();
+ optimizeVariableAccess(exec);
m_initialized = true;
}
LocalStorage& localStorage = exec->variableObject()->localStorage();
+
+ // We can't just resize localStorage here because that would temporarily
+ // leave uninitialized entries, which would crash GC during the mark phase.
localStorage.reserveCapacity(m_varStack.size() + m_parameters.size() + m_functionStack.size());
int minAttributes = Internal | DontDelete;
- size_t i, size;
+ // In order for our localStorage indexes to be correct, we must match the
+ // order of addition in initializeSymbolTable().
- // NOTE: Must match the order of addition in initializeSymbolTable().
+ const List& args = *exec->arguments();
+ for (size_t i = 0, size = m_parameters.size(); i < size; ++i)
+ localStorage.uncheckedAppend(LocalStorageEntry(args[i], DontDelete));
- for (i = 0, size = m_varStack.size(); i < size; ++i) {
+ for (size_t i = 0, size = m_functionStack.size(); i < size; ++i) {
+ FuncDeclNode* node = m_functionStack[i];
+ localStorage.uncheckedAppend(LocalStorageEntry(node->makeFunction(exec), minAttributes));
+ }
+
+ for (size_t i = 0, size = m_varStack.size(); i < size; ++i) {
VarDeclNode* node = m_varStack[i];
int attributes = minAttributes;
if (node->varType == VarDeclNode::Constant)
attributes |= ReadOnly;
- localStorage.append(LocalStorageEntry(jsUndefined(), attributes));
- }
-
- const List& args = *exec->arguments();
- for (i = 0, size = m_parameters.size(); i < size; ++i)
- localStorage.append(LocalStorageEntry(args[i], DontDelete));
-
- for (i = 0, size = m_functionStack.size(); i < size; ++i) {
- FuncDeclNode* node = m_functionStack[i];
- localStorage.append(LocalStorageEntry(node->makeFunction(exec), minAttributes));
+ localStorage.uncheckedAppend(LocalStorageEntry(jsUndefined(), attributes));
}
+}
- exec->updateLocalStorage();
+static void gccIsCrazy() KJS_FAST_CALL;
+static void gccIsCrazy()
+{
}
void ProgramNode::processDeclarations(ExecState* exec)
{
- size_t i, size;
-
- JSVariableObject* variableObject = exec->variableObject();
+ // If you remove this call, some SunSpider tests, including
+ // bitops-nsieve-bits.js, will regress substantially on Mac, due to a ~40%
+ // increase in L2 cache misses. FIXME: WTF?
+ gccIsCrazy();
+ initializeSymbolTable(exec);
+ optimizeVariableAccess(exec);
+
+ LocalStorage& localStorage = exec->variableObject()->localStorage();
+
+ // We can't just resize localStorage here because that would temporarily
+ // leave uninitialized entries, which would crash GC during the mark phase.
+ localStorage.reserveCapacity(localStorage.size() + m_varStack.size() + m_functionStack.size());
+
int minAttributes = Internal | DontDelete;
- for (i = 0, size = m_varStack.size(); i < size; ++i) {
- VarDeclNode* node = m_varStack[i];
- if (variableObject->hasProperty(exec, node->ident))
+ // In order for our localStorage indexes to be correct, we must match the
+ // order of addition in initializeSymbolTable().
+
+ for (size_t i = 0, size = m_functionStack.size(); i < size; ++i) {
+ FuncDeclNode* node = m_functionStack[i];
+ LocalStorageEntry entry = LocalStorageEntry(node->makeFunction(exec), minAttributes);
+ size_t index = m_functionIndexes[i];
+
+ if (index == localStorage.size())
+ localStorage.uncheckedAppend(entry);
+ else {
+ ASSERT(index < localStorage.size());
+ localStorage[index] = entry;
+ }
+ }
+
+ for (size_t i = 0, size = m_varStack.size(); i < size; ++i) {
+ size_t index = m_varIndexes[i];
+ if (index == missingSymbolMarker())
continue;
+
+ VarDeclNode* node = m_varStack[i];
int attributes = minAttributes;
if (node->varType == VarDeclNode::Constant)
attributes |= ReadOnly;
- variableObject->put(exec, node->ident, jsUndefined(), attributes);
- }
-
- for (i = 0, size = m_functionStack.size(); i < size; ++i) {
- FuncDeclNode* node = m_functionStack[i];
- variableObject->put(exec, node->ident, node->makeFunction(exec), minAttributes);
+ LocalStorageEntry entry = LocalStorageEntry(jsUndefined(), attributes);
+
+ ASSERT(index == localStorage.size());
+ localStorage.uncheckedAppend(entry);
}
}
void EvalNode::processDeclarations(ExecState* exec)
{
+ // We could optimize access to pre-existing symbols here, but SunSpider
+ // reports that to be a net loss.
+
size_t i, size;
JSVariableObject* variableObject = exec->variableObject();
for (i = 0, size = m_varStack.size(); i < size; ++i) {
VarDeclNode* node = m_varStack[i];
- if (variableObject->hasProperty(exec, node->ident))
+ if (variableObject->hasOwnProperty(exec, node->ident))
continue;
int attributes = minAttributes;
if (node->varType == VarDeclNode::Constant)
public:
ScopeNode(SourceElements*, DeclarationStacks::VarStack*, DeclarationStacks::FunctionStack*) KJS_FAST_CALL;
- int sourceId() KJS_FAST_CALL { return m_sourceId; }
- const UString& sourceURL() KJS_FAST_CALL { return m_sourceURL; }
+ int sourceId() const KJS_FAST_CALL { return m_sourceId; }
+ const UString& sourceURL() const KJS_FAST_CALL { return m_sourceURL; }
protected:
+ void optimizeVariableAccess(ExecState*) KJS_FAST_CALL;
DeclarationStacks::VarStack m_varStack;
DeclarationStacks::FunctionStack m_functionStack;
virtual Completion execute(ExecState*) KJS_FAST_CALL;
private:
+ void initializeSymbolTable(ExecState*) KJS_FAST_CALL;
ALWAYS_INLINE void processDeclarations(ExecState*) KJS_FAST_CALL;
+
+ Vector<size_t> m_varIndexes; // Storage indexes belonging to the nodes in m_varStack. (Recorded to avoid double lookup.)
+ Vector<size_t> m_functionIndexes; // Storage indexes belonging to the nodes in m_functionStack. (Recorded to avoid double lookup.)
};
class EvalNode : public ScopeNode {
private:
void initializeSymbolTable(ExecState*) KJS_FAST_CALL;
- void optimizeVariableAccess() KJS_FAST_CALL;
ALWAYS_INLINE void processDeclarations(ExecState*) KJS_FAST_CALL;
bool m_initialized;
return true;
}
+bool JSObject::hasOwnProperty(ExecState* exec, const Identifier& propertyName) const
+{
+ PropertySlot slot;
+ return const_cast<JSObject*>(this)->getOwnPropertySlot(exec, propertyName, slot);
+}
+
bool JSObject::deleteProperty(ExecState *exec, unsigned propertyName)
{
return deleteProperty(exec, Identifier::from(propertyName));
* (that is, the ECMAScript "null" value, not a null object pointer).
*/
JSObject();
-
+
virtual void mark();
virtual JSType type() const;
* @param propertyName The name of the property to check for
* @return true if the object has the property, otherwise false
*/
- bool hasProperty(ExecState *exec, const Identifier &propertyName) const;
- bool hasProperty(ExecState *exec, unsigned propertyName) const;
+ bool hasProperty(ExecState*, const Identifier&) const;
+ bool hasProperty(ExecState*, unsigned) const;
+ bool hasOwnProperty(ExecState*, const Identifier&) const;
/**
* Removes the specified property from the object.
void defineGetter(ExecState *exec, const Identifier& propertyName, JSObject *getterFunc);
void defineSetter(ExecState *exec, const Identifier& propertyName, JSObject *setterFunc);
- /**
- * Remove all properties from this object.
- * This doesn't take DontDelete into account, and isn't in the ECMA spec.
- * It's simply a quick way to remove everything stored in the property map.
- */
- void clearProperties() { _prop.clear(); }
-
void saveProperties(SavedProperties &p) const { _prop.save(p); }
void restoreProperties(const SavedProperties &p) { _prop.restore(p); }
virtual bool isActivationObject() { return false; }
virtual bool isGlobalObject() const { return false; }
+
protected:
PropertyMap _prop;
+
private:
const HashEntry* findPropertyHashEntry( const Identifier& propertyName ) const;
JSValue *_proto;
switch (id) {
case ValueOf:
return thisObj;
- case HasOwnProperty: {
- PropertySlot slot;
- return jsBoolean(thisObj->getOwnPropertySlot(exec, Identifier(args[0]->toString(exec)), slot));
- }
+ case HasOwnProperty:
+ return jsBoolean(thisObj->hasOwnProperty(exec, Identifier(args[0]->toString(exec))));
case IsPrototypeOf: {
if (!args[0]->isObject())
return jsBoolean(false);
}
};
-struct SavedProperty {
- Identifier key;
- ProtectedPtr<JSValue> value;
- unsigned attributes;
-};
-
static const unsigned emptyEntryIndex = 0;
static const unsigned deletedSentinelIndex = 1;
#define KJS_PROPERTY_MAP_H_
#include "identifier.h"
+#include "protect.h"
#include <wtf/OwnArrayPtr.h>
namespace KJS {
struct PropertyMapEntry;
struct PropertyMapHashTable;
- struct SavedProperty;
- class SavedProperties {
- friend class PropertyMap;
- public:
+ struct SavedProperty {
+ Identifier key;
+ ProtectedPtr<JSValue> value;
+ unsigned attributes;
+ };
+
+ struct SavedProperties {
SavedProperties();
~SavedProperties();
- private:
unsigned m_count;
OwnArrayPtr<SavedProperty> m_properties;
};
public:
PropertyMap();
~PropertyMap();
-
+
void clear();
void put(const Identifier&, JSValue*, unsigned attributes, bool checkReadOnly = false);
const T& last() const { return at(size() - 1); }
void shrink(size_t size);
+ void grow(size_t size);
void resize(size_t size);
void reserveCapacity(size_t newCapacity);
m_size = size;
}
+ template<typename T, size_t inlineCapacity>
+ void Vector<T, inlineCapacity>::grow(size_t size)
+ {
+ ASSERT(size >= m_size);
+ if (size > capacity())
+ expandCapacity(size);
+ TypeOperations::initialize(end(), begin() + size);
+ m_size = size;
+ }
+
template<typename T, size_t inlineCapacity>
void Vector<T, inlineCapacity>::reserveCapacity(size_t newCapacity)
{
+2007-12-19 Geoffrey Garen <ggaren@apple.com>
+
+ Build fix.
+
+ * ForwardingHeaders/wtf/VectorTraits.h: Added.
+
2007-12-10 Timothy Hatcher <timothy@apple.com>
Reviewed by Mark Rowe.
--- /dev/null
+#include <JavaScriptCore/VectorTraits.h>
+2007-12-19 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Added some tests to verify some of the changes I made while optimizing
+ global access to global variables.
+
+ * fast/dom/Window/resources/window-property-clearing-iframe0.html: Added.
+ * fast/dom/Window/resources/window-property-clearing-iframe1.html: Added.
+ * fast/dom/Window/window-property-clearing-expected.txt: Added.
+ * fast/dom/Window/window-property-clearing.html: Added.
+ * fast/dom/getter-on-window-object2-expected.txt: Added.
+ * fast/dom/getter-on-window-object2.html: Added.
+
+ Checked in failing results for these const tests. The symbol table
+ optimization broke const. (We didn't know this before because our only
+ tests used global variables.)
+
+ * fast/js/const-expected.txt:
+ * fast/js/kde/const-expected.txt:
+
+ * fast/js/resources/for-in-avoid-duplicates.js: Fixed a typo I noticed.
+ Not related to this patch.
+
+ * fast/dom/Window/window-property-shadowing.html: Changed this test to
+ use "this" instead of "window". The fact that "window" worked before,
+ despite an overriding / shadowing var declaration, was a bug.
+
2007-12-19 Dan Bernstein <mitz@apple.com>
- remove two more tests that pass now due to changed font fallback
--- /dev/null
+<script>
+var x = 1;
+function f() {}
+
+top.didFinishLoading(window);
+</script>
--- /dev/null
+<script>
+top.didFinishLoading(window);
+</script>
--- /dev/null
+This page tests whether global declarations are cleared after a navigation. If the test passes, you'll see a series of PASS messages below.
+
+\r
+Page 0:\r
+PASS: 'x' in childWindow should be true and is.\r
+PASS: childWindow.x should be 1 and is.\r
+PASS: 'f' in childWindow should be true and is.\r
+PASS: childWindow.f should be function and is.\r
+\r
+Page 1:\r
+PASS: 'x' in childWindow should be false and is.\r
+PASS: childWindow.x should be undefined and is.\r
+PASS: 'f' in childWindow should be false and is.\r
+PASS: typeof childWindow.f should be undefined and is.\r
+
--- /dev/null
+<p>
+This page tests whether global declarations are cleared after a navigation.
+If the test passes, you'll see a series of PASS messages below.
+</p>
+<pre id="console"></pre>
+
+<script>
+function log(s)
+{
+ document.getElementById("console").appendChild(document.createTextNode(s + "\r\n"));
+}
+
+function shouldBe(evalA, a, b)
+{
+ if (evalA === b) {
+ log("PASS: " + a + " should be " + b + " and is.");
+ } else {
+ log("FAIL: " + a + " should be " + b + " but instead is " + evalA + ".");
+ }
+}
+
+var count = 0;
+function didFinishLoading(childWindow) // called by subframes
+{
+ log("\r\nPage " + count + ":");
+ if (!count) {
+ shouldBe('x' in childWindow, "'x' in childWindow", true);
+ shouldBe(childWindow.x, "childWindow.x", 1);
+ shouldBe('f' in childWindow, "'f' in childWindow", true);
+ shouldBe(typeof childWindow.f, "childWindow.f", "function");
+
+ childWindow.location = "window-property-clearing-iframe1.html";
+
+ ++count;
+ } else {
+ shouldBe('x' in childWindow, "'x' in childWindow", false);
+ shouldBe(childWindow.x, "childWindow.x", undefined);
+ shouldBe('f' in childWindow, "'f' in childWindow", false);
+ shouldBe(typeof childWindow.f, "typeof childWindow.f", "undefined");
+
+ if (window.layoutTestController)
+ layoutTestController.notifyDone();
+ }
+}
+
+function test()
+{
+ if (window.layoutTestController) {
+ layoutTestController.dumpAsText();
+ layoutTestController.waitUntilDone();
+ }
+}
+
+test();
+</script>
+
+<iframe src="resources/window-property-clearing-iframe0.html"></iframe>
<body>
<pre id="console"></pre>
<script>
- if (window.layoutTestController)
+ if (this.layoutTestController)
layoutTestController.dumpAsText();
// Window Attributes
--- /dev/null
+This page tests what happens when a getter / setter on the window object conflicts with another property or declared variable.
+
+window.x is: 1
+typeof window.__lookupGetter__("x") is: function
+window.x is: 2
+typeof window.__lookupSetter__("x") is: function
+window.y is: window.y __getter__
+typeof window.__lookupGetter__("y") is: function
+window.y is: 2
+typeof window.__lookupSetter__("y") is: undefined
+window.z __setter__ called
+typeof window.__lookupSetter__("z") is: undefined
+
--- /dev/null
+<p>
+This page tests what happens when a getter / setter on the window object conflicts
+with another property or declared variable.
+</p>
+
+<pre id="console"></pre>
+
+<script>
+function log(s)
+{
+ document.getElementById("console").appendChild(document.createTextNode(s + "\n"));
+}
+
+if (window.layoutTestController)
+ layoutTestController.dumpAsText();
+
+var x = 1;
+
+try {
+ window.__defineGetter__("x", function() { return "window.x __getter__"; });
+} catch(e) { log(e); }
+log("window.x is: " + window.x);
+log("typeof window.__lookupGetter__(\"x\") is: " + typeof window.__lookupGetter__("x"));
+
+try {
+window.__defineSetter__("x", function() { log("window.x __setter__ called"); });
+} catch(e) { log(e); }
+x = 2;
+log("window.x is: " + window.x);
+log("typeof window.__lookupSetter__(\"x\") is: " + typeof window.__lookupGetter__("x"));
+
+y = 1;
+
+try {
+ window.__defineGetter__("y", function() { return "window.y __getter__"; });
+} catch(e) { log(e); }
+log("window.y is: " + window.y);
+log("typeof window.__lookupGetter__(\"y\") is: " + typeof window.__lookupGetter__("y"));
+
+try {
+window.__defineSetter__("y", function() { log("window.y __setter__ called"); });
+} catch(e) { log(e); }
+y = 2;
+log("window.y is: " + window.y);
+log("typeof window.__lookupSetter__(\"y\") is: " + typeof window.__lookupGetter__("y"));
+
+try {
+window.__defineSetter__("z", function() { log("window.z __setter__ called"); });
+} catch(e) { log(e); }
+window.z = 1;
+log("typeof window.__lookupSetter__(\"z\") is: " + typeof window.__lookupGetter__("z"));
+</script>
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-PASS x is "RIGHT"
-PASS y is "RIGHT"
+FAIL x should be RIGHT. Was WRONG.
+FAIL y should be RIGHT. Was WRONG.
PASS successfullyParsed is true
TEST COMPLETE
PASS c is 11
-PASS c is 11
+FAIL c should be 11. Was 22.
PASS v is 1
PASS successfullyParsed is true
this.yyy = "bar";
}
-constructor.prototype = { xxx: "baz", yyy: "quux" };
+constr.prototype = { xxx: "baz", yyy: "quux" };
var obj = new constr();
+2007-12-19 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Build support:
+ * ForwardingHeaders/kjs/SymbolTable.h: Added.
+ * ForwardingHeaders/wtf/VectorTraits.h: Added.
+
+ * bindings/js/JSDOMWindowCustom.cpp:
+ (WebCore::JSDOMWindow::customGetOwnPropertySlot): Replaced use of
+ getDirectLocation with getOwnPropertySlot. getDirectLocation is no
+ longer valid, since global declarations are not stored in the property
+ map.
+
+ (WebCore::JSDOMWindow::customPut): Replaced use of JSObject::put with
+ JSGlobalObject::put. JSObject::put is no longer valid, since global
+ declarations are not stored in the property map.
+
+ * bindings/js/kjs_window.cpp: Replaced JSObject:: calls with Base::
+ calls, since JSObject is not our base class. This was always a bug, but
+ the bug is even more apparent after some of my changes.
+
+ (KJS::Window::clear): Removed call to clearProperties because
+ JSGlobalObject::reset takes care of that now.
+
+ * history/CachedPage.cpp:
+ * history/CachedPage.h: Added support for saving a symbol table and
+ localStorage to the page cache, and restoring it.
+
2007-12-19 Dan Bernstein <mitz@apple.com>
Reviewed by Darin Adler and Dave Hyatt.
--- /dev/null
+#include <JavaScriptCore/SymbolTable.h>
--- /dev/null
+#include <JavaScriptCore/VectorTraits.h>
}
// Look for overrides first
- KJS::JSValue** val = getDirectLocation(propertyName);
- if (val) {
- if (!allowsAccessFrom(exec)) {
+ if (JSGlobalObject::getOwnPropertySlot(exec, propertyName, slot)) {
+ if (!allowsAccessFrom(exec))
slot.setUndefined(this);
- return true;
- }
- // FIXME: Come up with a way of having JavaScriptCore handle getters/setters in this case
- if (_prop.hasGetterSetterProperties() && val[0]->type() == KJS::GetterSetterType)
- fillGetterPropertySlot(slot, val);
- else
- slot.setValueSlot(this, val);
return true;
}
if (!impl()->frame())
return true;
- // Called by an internal KJS, save time and jump directly to JSObject.
+ // Called by an internal KJS, save time and jump directly to JSGlobalObject.
if (attr != KJS::None && attr != KJS::DontDelete) {
- KJS::JSObject::put(exec, propertyName, value, attr);
+ KJS::JSGlobalObject::put(exec, propertyName, value, attr);
return true;
}
- // We have a local override (e.g. "var location"), save time and jump directly to JSObject.
- if (KJS::JSObject::getDirect(propertyName)) {
+ // We have a local override (e.g. "var location"), save time and jump directly to JSGlobalObject.
+ KJS::PropertySlot slot;
+ if (KJS::JSGlobalObject::getOwnPropertySlot(exec, propertyName, slot)) {
if (allowsAccessFrom(exec))
- KJS::JSObject::put(exec, propertyName, value, attr);
+ KJS::JSGlobalObject::put(exec, propertyName, value, attr);
return true;
}
// reference our special objects during garbage collection
void Window::mark()
{
- JSGlobalObject::mark();
+ Base::mark();
if (d->loc && !d->loc->marked())
d->loc->mark();
}
return true;
}
- return JSObject::getOwnPropertySlot(exec, propertyName, slot);
+ return Base::getOwnPropertySlot(exec, propertyName, slot);
}
void Window::put(ExecState* exec, const Identifier& propertyName, JSValue* value, int attr)
if (entry) {
if (entry->attr & Function) {
if (allowsAccessFrom(exec))
- JSObject::put(exec, propertyName, value, attr);
+ Base::put(exec, propertyName, value, attr);
return;
}
if (entry->attr & ReadOnly)
}
}
if (allowsAccessFrom(exec))
- JSObject::put(exec, propertyName, value, attr);
+ Base::put(exec, propertyName, value, attr);
}
bool Window::allowsAccessFrom(const JSGlobalObject* other) const
// frame does not destroy it
ASSERT(impl()->frame());
impl()->frame()->keepAlive();
- return JSGlobalObject::globalExec();
+ return Base::globalExec();
}
bool Window::shouldInterruptScript() const
*d->m_returnValueSlot = getDirect("returnValue");
clearAllTimeouts();
- clearProperties();
clearHelperObjectProperties();
// Now recreate a working global object for the next URL that will use us; but only if we haven't been
// This is the only WebCore JS binding which does not inherit from DOMObject
class Window : public JSGlobalObject {
+ typedef JSGlobalObject Base;
+
friend class WebCore::JSLocation;
friend class WebCore::ScheduledAction;
protected:
, m_URL(page->mainFrame()->loader()->url())
, m_windowProperties(new SavedProperties)
, m_locationProperties(new SavedProperties)
+ , m_windowLocalStorage(new SavedProperties)
, m_windowBuiltins(new SavedBuiltins)
{
#ifndef NDEBUG
m_document->willSaveToCache();
Frame* mainFrame = page->mainFrame();
- KJSProxy* proxy = mainFrame->scriptProxy();
- KJS::Window* window = KJS::Window::retrieveWindow(mainFrame);
+ Window* window = Window::retrieveWindow(mainFrame);
mainFrame->clearTimers();
JSLock lock;
- if (proxy && window) {
- proxy->globalObject()->saveBuiltins(*m_windowBuiltins.get());
+ if (window) {
+ window->saveBuiltins(*m_windowBuiltins.get());
window->saveProperties(*m_windowProperties.get());
+ window->saveSymbolTable(m_windowSymbolTable);
+ window->saveLocalStorage(*m_windowLocalStorage.get());
window->location()->saveProperties(*m_locationProperties.get());
m_pausedTimeouts.set(window->pauseTimeouts());
}
ASSERT(m_document->view() == m_view);
Frame* mainFrame = page->mainFrame();
- KJSProxy* proxy = mainFrame->scriptProxy();
- KJS::Window* window = KJS::Window::retrieveWindow(mainFrame);
+ Window* window = Window::retrieveWindow(mainFrame);
JSLock lock;
- if (proxy && window) {
- proxy->globalObject()->restoreBuiltins(*m_windowBuiltins.get());
+ if (window) {
+ window->restoreBuiltins(*m_windowBuiltins.get());
window->restoreProperties(*m_windowProperties.get());
+ window->restoreSymbolTable(m_windowSymbolTable);
+ window->restoreLocalStorage(*m_windowLocalStorage.get());
window->location()->restoreProperties(*m_locationProperties.get());
window->resumeTimeouts(m_pausedTimeouts.get());
}
m_windowBuiltins.clear();
m_pausedTimeouts.clear();
m_cachedPagePlatformData.clear();
+ m_windowLocalStorage.clear();
+ m_windowSymbolTable.clear();
gcController().garbageCollectSoon();
}
#define CachedPage_h
#include "DocumentLoader.h"
+#include <kjs/SymbolTable.h>
#include <wtf/RefCounted.h>
#include <wtf/Forward.h>
#include <wtf/RefPtr.h>
namespace KJS {
class SavedBuiltins;
- class SavedProperties;
+ struct SavedProperties;
}
namespace WebCore {
KURL m_URL;
OwnPtr<KJS::SavedProperties> m_windowProperties;
OwnPtr<KJS::SavedProperties> m_locationProperties;
+ OwnPtr<KJS::SavedProperties> m_windowLocalStorage;
+ KJS::SymbolTable m_windowSymbolTable;
OwnPtr<KJS::SavedBuiltins> m_windowBuiltins;
OwnPtr<PausedTimeouts> m_pausedTimeouts;
OwnPtr<CachedPagePlatformData> m_cachedPagePlatformData;
+2007-12-19 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Build fix.
+
+ * ForwardingHeaders/kjs/SymbolTable.h: Added.
+ * ForwardingHeaders/wtf/VectorTraits.h: Added.
+
2007-12-16 Mark Rowe <mrowe@apple.com>
Reviewed by Maciej Stachowiak.
--- /dev/null
+#include <JavaScriptCore/SymbolTable.h>
--- /dev/null
+#include <JavaScriptCore/VectorTraits.h>