JavaScriptCore:
authordarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 27 Jan 2008 09:38:01 +0000 (09:38 +0000)
committerdarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 27 Jan 2008 09:38:01 +0000 (09:38 +0000)
        Reviewed by Oliver.

        - fix <rdar://problem/5657450> REGRESSION: const is broken

        Test: fast/js/const.html

        SunSpider said this was 0.3% slower. And I saw some Shark samples in
        JSGlobalObject::put -- not a lot but a few. We may be able to regain the
        speed, but for now we will take that small hit for correctness sake.

        * kjs/JSGlobalObject.cpp:
        (KJS::JSGlobalObject::put): Pass the checkReadOnly flag in to symbolTablePut
        instead of passing attributes.

        * kjs/JSVariableObject.h:
        (KJS::JSVariableObject::symbolTablePut): Removed the code to set attributes
        here, since we only set attributes when creating a property. Added the code
        to check read-only here, since we need that to implement const!

        * kjs/function.cpp:
        (KJS::ActivationImp::put): Pass the checkReadOnly flag in to symbolTablePut
        instead of passing attributes.

        * kjs/nodes.cpp:
        (KJS::isConstant): Added.
        (KJS::PostIncResolveNode::optimizeVariableAccess): Create a PostIncConstNode
        if optimizing for a local variable and the variable is constant.
        (KJS::PostDecResolveNode::optimizeVariableAccess): Ditto. But PostDecConstNode.
        (KJS::PreIncResolveNode::optimizeVariableAccess): Ditto. But PreIncConstNode.
        (KJS::PreDecResolveNode::optimizeVariableAccess): Ditto. But PreDecConstNode.
        (KJS::PreIncConstNode::evaluate): Return the value + 1.
        (KJS::PreDecConstNode::evaluate): Return the value - 1.
        (KJS::PostIncConstNode::evaluate): Return the value converted to a number.
        (KJS::PostDecConstNode::evaluate): Ditto.
        (KJS::ReadModifyResolveNode::optimizeVariableAccess): Create a ReadModifyConstNode
        if optimizing for a local variable and the variable is constant.
        (KJS::AssignResolveNode::optimizeVariableAccess): Ditto. But AssignConstNode.
        (KJS::ScopeNode::optimizeVariableAccess): Pass the local storage to the
        node optimizeVariableAccess functions, since that's where we need to look to
        figure out if a variable is constant.
        (KJS::FunctionBodyNode::processDeclarations): Moved the call to
        optimizeVariableAccess until after localStorage is set up.
        (KJS::ProgramNode::processDeclarations): Ditto.

        * kjs/nodes.h: Fixed the IsConstant and HasInitializer values. They are used
        as flag masks, so a value of 0 will not work for IsConstant. Changed the
        first parameter to optimizeVariableAccess to be a const reference to a symbol
        table and added a const reference to local storage. Added classes for const
        versions of local variable access: PostIncConstNode, PostDecConstNode,
        PreIncConstNode, PreDecConstNode, ReadModifyConstNode, and AssignConstNode.

        * kjs/object.cpp:
        (KJS::JSObject::put): Tweaked comments a bit, and changed the checkReadOnly
        expression to match the form used at the two other call sites.

LayoutTests:

        Reviewed by Oliver.

        - tests for <rdar://problem/5657450> REGRESSION: const is broken

        * fast/js/const-expected.txt: Updated with results that express success
        rather than failure, and to include the many new tests I added.
        * fast/js/kde/const-expected.txt: Ditto.
        * fast/js/resources/const.js: Added many new tests, covering the various
        cases of const in globals, function locals, the slow case inside eval,
        the different node types, and the values of the expressions.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@29818 268f45cc-cd09-0410-ab3c-d52691b4dbfc

JavaScriptCore/ChangeLog
JavaScriptCore/kjs/JSGlobalObject.cpp
JavaScriptCore/kjs/JSVariableObject.h
JavaScriptCore/kjs/function.cpp
JavaScriptCore/kjs/nodes.cpp
JavaScriptCore/kjs/nodes.h
JavaScriptCore/kjs/object.cpp
LayoutTests/ChangeLog
LayoutTests/fast/js/const-expected.txt
LayoutTests/fast/js/kde/const-expected.txt
LayoutTests/fast/js/resources/const.js

index a7da613ed3b300ef549d1a29e2b7955f5a824eda..bc8d7505ed1affebff6cb72bc463e7a29423a31f 100644 (file)
@@ -1,3 +1,60 @@
+2008-01-27  Darin Adler  <darin@apple.com>
+
+        Reviewed by Oliver.
+
+        - fix <rdar://problem/5657450> REGRESSION: const is broken
+
+        Test: fast/js/const.html
+
+        SunSpider said this was 0.3% slower. And I saw some Shark samples in
+        JSGlobalObject::put -- not a lot but a few. We may be able to regain the
+        speed, but for now we will take that small hit for correctness sake.
+
+        * kjs/JSGlobalObject.cpp:
+        (KJS::JSGlobalObject::put): Pass the checkReadOnly flag in to symbolTablePut
+        instead of passing attributes.
+
+        * kjs/JSVariableObject.h:
+        (KJS::JSVariableObject::symbolTablePut): Removed the code to set attributes
+        here, since we only set attributes when creating a property. Added the code
+        to check read-only here, since we need that to implement const!
+
+        * kjs/function.cpp:
+        (KJS::ActivationImp::put): Pass the checkReadOnly flag in to symbolTablePut
+        instead of passing attributes.
+
+        * kjs/nodes.cpp:
+        (KJS::isConstant): Added.
+        (KJS::PostIncResolveNode::optimizeVariableAccess): Create a PostIncConstNode
+        if optimizing for a local variable and the variable is constant.
+        (KJS::PostDecResolveNode::optimizeVariableAccess): Ditto. But PostDecConstNode.
+        (KJS::PreIncResolveNode::optimizeVariableAccess): Ditto. But PreIncConstNode.
+        (KJS::PreDecResolveNode::optimizeVariableAccess): Ditto. But PreDecConstNode.
+        (KJS::PreIncConstNode::evaluate): Return the value + 1.
+        (KJS::PreDecConstNode::evaluate): Return the value - 1.
+        (KJS::PostIncConstNode::evaluate): Return the value converted to a number.
+        (KJS::PostDecConstNode::evaluate): Ditto.
+        (KJS::ReadModifyResolveNode::optimizeVariableAccess): Create a ReadModifyConstNode
+        if optimizing for a local variable and the variable is constant.
+        (KJS::AssignResolveNode::optimizeVariableAccess): Ditto. But AssignConstNode.
+        (KJS::ScopeNode::optimizeVariableAccess): Pass the local storage to the
+        node optimizeVariableAccess functions, since that's where we need to look to
+        figure out if a variable is constant.
+        (KJS::FunctionBodyNode::processDeclarations): Moved the call to
+        optimizeVariableAccess until after localStorage is set up.
+        (KJS::ProgramNode::processDeclarations): Ditto.
+
+        * kjs/nodes.h: Fixed the IsConstant and HasInitializer values. They are used
+        as flag masks, so a value of 0 will not work for IsConstant. Changed the
+        first parameter to optimizeVariableAccess to be a const reference to a symbol
+        table and added a const reference to local storage. Added classes for const
+        versions of local variable access: PostIncConstNode, PostDecConstNode,
+        PreIncConstNode, PreDecConstNode, ReadModifyConstNode, and AssignConstNode.
+
+        * kjs/object.cpp:
+        (KJS::JSObject::put): Tweaked comments a bit, and changed the checkReadOnly
+        expression to match the form used at the two other call sites.
+
 2008-01-27  Darin Adler  <darin@apple.com>
 
         Reviewed by Oliver.
         be better to convert a JS Number into a Date rather than
         an int).
         
-
         * bindings/qt/qt_runtime.cpp:
         (KJS::Bindings::convertValueToQVariant):
         (KJS::Bindings::convertQVariantToValue):
 
         Code style cleanups.
         Add spaces before/after braces in inline function.
-        
 
         * bindings/qt/qt_instance.h:
 
 
         Code style cleanups.
         Remove spaces and unneeded declared parameter names.
-        
 
         * bindings/qt/qt_instance.cpp:
         (KJS::Bindings::QtRuntimeObjectImp::removeFromCache):
         RuntimeObjectImp is invalidate or deleted.  This
         could result in a stale JSObject being returned for
         a valid Instance.
-        
 
         * bindings/qt/qt_instance.cpp:
         (KJS::Bindings::QtRuntimeObjectImp::QtRuntimeObjectImp):
         * A couple of fixes for autotest failures.
         Better support for converting lists, read/write only
         QMetaProperty support, modified slot search order...)
-        
 
         * bindings/qt/qt_class.cpp:
         (KJS::Bindings::QtClass::QtClass):
index 67d39ae2147dc6d9bbaef5a2550845e663b8e2ef..5466f7416dec3f0cc4612a404a7ae500d1975baa 100644 (file)
@@ -153,7 +153,7 @@ bool JSGlobalObject::getOwnPropertySlot(ExecState* exec, const Identifier& prope
 
 void JSGlobalObject::put(ExecState* exec, const Identifier& propertyName, JSValue* value, int attr)
 {
-    if (symbolTablePut(propertyName, value, attr))
+    if (symbolTablePut(propertyName, value, !(attr & ~DontDelete)))
         return;
     return JSVariableObject::put(exec, propertyName, value, attr);
 }
index 6dfbd052c888b9167ddbdeb9873c1d7025455eb0..37f7299a17aa45dd096cc2e679451a0ac61de644 100644 (file)
@@ -82,7 +82,7 @@ namespace KJS {
         }
 
         bool symbolTableGet(const Identifier&, PropertySlot&);
-        bool symbolTablePut(const Identifier&, JSValue*, int attr);
+        bool symbolTablePut(const Identifier&, JSValue*, bool checkReadOnly);
 
         JSVariableObjectData* d;
     };
@@ -110,17 +110,16 @@ namespace KJS {
         return false;
     }
 
-    inline bool JSVariableObject::symbolTablePut(const Identifier& propertyName, JSValue* value, int attr)
+    inline bool JSVariableObject::symbolTablePut(const Identifier& propertyName, JSValue* value, bool checkReadOnly)
     {
         size_t index = symbolTable().get(propertyName.ustring().rep());
-        if (index != missingSymbolMarker()) {
-            LocalStorageEntry& entry = d->localStorage[index];
-            entry.value = value;
-            entry.attributes = attr;
+        if (index == missingSymbolMarker())
+            return false;
+        LocalStorageEntry& entry = d->localStorage[index];
+        if (checkReadOnly && (entry.attributes & ReadOnly))
             return true;
-        }
-
-        return false;
+        entry.value = value;
+        return true;
     }
 
 } // namespace KJS
index 23851a1726a74bddded071ba98b0422e84a4fee6..f5b0391a7d0e62cef7100fc55348b56674e68a91 100644 (file)
@@ -419,14 +419,16 @@ bool ActivationImp::deleteProperty(ExecState* exec, const Identifier& propertyNa
 
 void ActivationImp::put(ExecState*, const Identifier& propertyName, JSValue* value, int attr)
 {
-    if (symbolTablePut(propertyName, value, attr))
+    // If any bits other than DontDelete are set, then we bypass the read-only check.
+    bool checkReadOnly = !(attr & ~DontDelete);
+    if (symbolTablePut(propertyName, value, checkReadOnly))
         return;
 
     // We don't call through to JSObject because __proto__ and getter/setter 
     // properties are non-standard extensions that other implementations do not
     // expose in the activation object.
     ASSERT(!_prop.hasGetterSetterProperties());
-    _prop.put(propertyName, value, attr, (attr == None || attr == DontDelete));
+    _prop.put(propertyName, value, attr, checkReadOnly);
 }
 
 void ActivationImp::markChildren()
index 98103369176fd8855e9ad34d9527db882139597f..5ae72e2910db4bea5dc4e3390ccaff8fe090804b 100644 (file)
@@ -46,7 +46,7 @@ namespace KJS {
 
     class FunctionBodyNodeWithDebuggerHooks : public FunctionBodyNode {
     public:
-        FunctionBodyNodeWithDebuggerHooks(SourceElements*, DeclarationStacks::VarStack*, DeclarationStacks::FunctionStack*) KJS_FAST_CALL;
+        FunctionBodyNodeWithDebuggerHooks(SourceElements*, VarStack*, FunctionStack*) KJS_FAST_CALL;
         virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
     };
 
@@ -98,6 +98,12 @@ static inline bool canSkipLookup(ExecState* exec, const Identifier& ident)
 }
 #endif
 
+static inline bool isConstant(const LocalStorage& localStorage, size_t index)
+{
+    ASSERT(index < localStorage.size());
+    return localStorage[index].attributes & ReadOnly;
+}
+
 // ------------------------------ Node -----------------------------------------
 
 #ifndef NDEBUG
@@ -416,7 +422,7 @@ void BreakpointCheckStatement::streamTo(SourceStream& stream) const
     m_statement->streamTo(stream);
 }
 
-void BreakpointCheckStatement::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void BreakpointCheckStatement::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(m_statement.get());
 }
@@ -584,7 +590,7 @@ uint32_t ResolveNode::evaluateToUInt32(ExecState* exec)
     return v->toUInt32(exec);
 }
 
-void ResolveNode::optimizeVariableAccess(SymbolTable& symbolTable, DeclarationStacks::NodeStack&)
+void ResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage&, NodeStack&)
 {
     size_t index = symbolTable.get(ident.ustring().rep());
     if (index != missingSymbolMarker())
@@ -624,7 +630,7 @@ uint32_t LocalVarAccessNode::evaluateToUInt32(ExecState* exec)
 
 // ------------------------------ ElementNode ----------------------------------
 
-void ElementNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void ElementNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     if (next)
         nodeStack.append(next.get());
@@ -648,7 +654,7 @@ JSValue *ElementNode::evaluate(ExecState *exec)
 
 // ------------------------------ ArrayNode ------------------------------------
 
-void ArrayNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void ArrayNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     if (element)
         nodeStack.append(element.get());
@@ -679,7 +685,7 @@ JSValue *ArrayNode::evaluate(ExecState *exec)
 
 // ------------------------------ ObjectLiteralNode ----------------------------
 
-void ObjectLiteralNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void ObjectLiteralNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     if (list)
         nodeStack.append(list.get());
@@ -696,7 +702,7 @@ JSValue *ObjectLiteralNode::evaluate(ExecState *exec)
 
 // ------------------------------ PropertyListNode -----------------------------
 
-void PropertyListNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void PropertyListNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     if (next)
         nodeStack.append(next.get());
@@ -732,7 +738,7 @@ JSValue *PropertyListNode::evaluate(ExecState *exec)
 
 // ------------------------------ PropertyNode -----------------------------
 
-void PropertyNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void PropertyNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(assign.get());
 }
@@ -746,7 +752,7 @@ JSValue *PropertyNode::evaluate(ExecState*)
 
 // ------------------------------ BracketAccessorNode --------------------------------
 
-void BracketAccessorNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void BracketAccessorNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(expr2.get());
     nodeStack.append(expr1.get());
@@ -801,7 +807,7 @@ uint32_t BracketAccessorNode::evaluateToUInt32(ExecState* exec)
 
 // ------------------------------ DotAccessorNode --------------------------------
 
-void DotAccessorNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void DotAccessorNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(expr.get());
 }
@@ -849,7 +855,7 @@ uint32_t DotAccessorNode::evaluateToUInt32(ExecState* exec)
 
 // ------------------------------ ArgumentListNode -----------------------------
 
-void ArgumentListNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void ArgumentListNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     if (next)
         nodeStack.append(next.get());
@@ -869,7 +875,7 @@ void ArgumentListNode::evaluateList(ExecState* exec, List& list)
 
 // ------------------------------ ArgumentsNode --------------------------------
 
-void ArgumentsNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void ArgumentsNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     if (listNode)
         nodeStack.append(listNode.get());
@@ -877,7 +883,7 @@ void ArgumentsNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::Node
 
 // ------------------------------ NewExprNode ----------------------------------
 
-void NewExprNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void NewExprNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     if (args)
         nodeStack.append(args.get());
@@ -940,7 +946,7 @@ uint32_t NewExprNode::evaluateToUInt32(ExecState* exec)
     return v->toUInt32(exec);
 }    
 
-void FunctionCallValueNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void FunctionCallValueNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(args.get());
     nodeStack.append(expr.get());
@@ -971,7 +977,7 @@ JSValue *FunctionCallValueNode::evaluate(ExecState *exec)
   return func->call(exec, thisObj, argList);
 }
 
-void FunctionCallResolveNode::optimizeVariableAccess(SymbolTable& symbolTable, DeclarationStacks::NodeStack& nodeStack)
+void FunctionCallResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(args.get());
 
@@ -1117,7 +1123,7 @@ uint32_t LocalVarFunctionCallNode::evaluateToUInt32(ExecState* exec)
     return v->toUInt32(exec);
 }
 
-void FunctionCallBracketNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void FunctionCallBracketNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(args.get());
     nodeStack.append(subscript.get());
@@ -1186,7 +1192,7 @@ static const char *dotExprDoesNotAllowCallsString()
   return "Object %s (result of expression %s.%s) does not allow calls.";
 }
 
-void FunctionCallDotNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void FunctionCallDotNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(args.get());
     nodeStack.append(base.get());
@@ -1261,11 +1267,15 @@ uint32_t FunctionCallDotNode::evaluateToUInt32(ExecState* exec)
 // ------------------------------ PostfixResolveNode ----------------------------------
 
 // Increment
-void PostIncResolveNode::optimizeVariableAccess(SymbolTable& symbolTable, DeclarationStacks::NodeStack&)
+void PostIncResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage& localStorage, NodeStack&)
 {
     size_t index = symbolTable.get(m_ident.ustring().rep());
-    if (index != missingSymbolMarker())
-        new (this) PostIncLocalVarNode(index);
+    if (index != missingSymbolMarker()) {
+        if (isConstant(localStorage, index))
+            new (this) PostIncConstNode(index);
+        else
+            new (this) PostIncLocalVarNode(index);
+    }
 }
 
 JSValue *PostIncResolveNode::evaluate(ExecState *exec)
@@ -1319,11 +1329,15 @@ void PostIncLocalVarNode::optimizeForUnnecessaryResult()
 
 
 // Decrement
-void PostDecResolveNode::optimizeVariableAccess(SymbolTable& symbolTable, DeclarationStacks::NodeStack&)
+void PostDecResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage& localStorage, NodeStack&)
 {
     size_t index = symbolTable.get(m_ident.ustring().rep());
-    if (index != missingSymbolMarker())
-        new (this) PostDecLocalVarNode(index);
+    if (index != missingSymbolMarker()) {
+        if (isConstant(localStorage, index))
+            new (this) PostDecConstNode(index);
+        else
+            new (this) PostDecLocalVarNode(index);
+    }
 }
 
 JSValue *PostDecResolveNode::evaluate(ExecState *exec)
@@ -1407,7 +1421,7 @@ void PostDecLocalVarNode::optimizeForUnnecessaryResult()
     
 // ------------------------------ PostfixBracketNode ----------------------------------
 
-void PostfixBracketNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void PostfixBracketNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(m_subscript.get());
     nodeStack.append(m_base.get());
@@ -1476,7 +1490,7 @@ JSValue *PostDecBracketNode::evaluate(ExecState *exec)
 
 // ------------------------------ PostfixDotNode ----------------------------------
 
-void PostfixDotNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void PostfixDotNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(m_base.get());
 }
@@ -1523,7 +1537,7 @@ JSValue* PostfixErrorNode::evaluate(ExecState* exec)
 
 // ------------------------------ DeleteResolveNode -----------------------------------
 
-void DeleteResolveNode::optimizeVariableAccess(SymbolTable& symbolTable, DeclarationStacks::NodeStack&)
+void DeleteResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage&, NodeStack&)
 {
     size_t index = symbolTable.get(m_ident.ustring().rep());
     if (index != missingSymbolMarker())
@@ -1565,7 +1579,7 @@ JSValue* LocalVarDeleteNode::evaluate(ExecState*)
 
 // ------------------------------ DeleteBracketNode -----------------------------------
 
-void DeleteBracketNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void DeleteBracketNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(m_subscript.get());
     nodeStack.append(m_base.get());
@@ -1590,7 +1604,7 @@ JSValue *DeleteBracketNode::evaluate(ExecState *exec)
 
 // ------------------------------ DeleteDotNode -----------------------------------
 
-void DeleteDotNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void DeleteDotNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(m_base.get());
 }
@@ -1606,7 +1620,7 @@ JSValue *DeleteDotNode::evaluate(ExecState *exec)
 
 // ------------------------------ DeleteValueNode -----------------------------------
 
-void DeleteValueNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void DeleteValueNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(m_expr.get());
 }
@@ -1622,7 +1636,7 @@ JSValue *DeleteValueNode::evaluate(ExecState *exec)
 
 // ------------------------------ VoidNode -------------------------------------
 
-void VoidNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void VoidNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(expr.get());
 }
@@ -1640,7 +1654,7 @@ JSValue *VoidNode::evaluate(ExecState *exec)
 
 // ------------------------------ TypeOfValueNode -----------------------------------
 
-void TypeOfValueNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void TypeOfValueNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(m_expr.get());
 }
@@ -1673,7 +1687,7 @@ static JSValue *typeStringForValue(JSValue *v)
     }
 }
 
-void TypeOfResolveNode::optimizeVariableAccess(SymbolTable& symbolTable, DeclarationStacks::NodeStack&)
+void TypeOfResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage&, NodeStack&)
 {
     size_t index = symbolTable.get(m_ident.ustring().rep());
     if (index != missingSymbolMarker())
@@ -1725,11 +1739,15 @@ JSValue *TypeOfValueNode::evaluate(ExecState *exec)
 
 // ------------------------------ PrefixResolveNode ----------------------------------
 
-void PreIncResolveNode::optimizeVariableAccess(SymbolTable& symbolTable, DeclarationStacks::NodeStack&)
+void PreIncResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage& localStorage, NodeStack&)
 {
     size_t index = symbolTable.get(m_ident.ustring().rep());
-    if (index != missingSymbolMarker())
-        new (this) PreIncLocalVarNode(index);
+    if (index != missingSymbolMarker()) {
+        if (isConstant(localStorage, index))
+            new (this) PreIncConstNode(index);
+        else
+            new (this) PreIncLocalVarNode(index);
+    }
 }
 
 JSValue* PreIncLocalVarNode::evaluate(ExecState* exec)
@@ -1773,11 +1791,15 @@ JSValue *PreIncResolveNode::evaluate(ExecState *exec)
   return throwUndefinedVariableError(exec, m_ident);
 }
 
-void PreDecResolveNode::optimizeVariableAccess(SymbolTable& symbolTable, DeclarationStacks::NodeStack&)
+void PreDecResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage& localStorage, NodeStack&)
 {
     size_t index = symbolTable.get(m_ident.ustring().rep());
-    if (index != missingSymbolMarker())
-        new (this) PreDecLocalVarNode(index);
+    if (index != missingSymbolMarker()) {
+        if (isConstant(localStorage, index))
+            new (this) PreDecConstNode(index);
+        else
+            new (this) PreDecLocalVarNode(index);
+    }
 }
 
 JSValue* PreDecLocalVarNode::evaluate(ExecState* exec)
@@ -1821,9 +1843,41 @@ JSValue *PreDecResolveNode::evaluate(ExecState *exec)
   return throwUndefinedVariableError(exec, m_ident);
 }
 
+// ------------------------------ PreIncConstNode ----------------------------------
+
+JSValue* PreIncConstNode::evaluate(ExecState* exec)
+{
+    ASSERT(exec->variableObject() == exec->scopeChain().top());
+    return jsNumber(exec->localStorage()[m_index].value->toNumber(exec) + 1);
+}
+
+// ------------------------------ PreDecConstNode ----------------------------------
+
+JSValue* PreDecConstNode::evaluate(ExecState* exec)
+{
+    ASSERT(exec->variableObject() == exec->scopeChain().top());
+    return jsNumber(exec->localStorage()[m_index].value->toNumber(exec) - 1);
+}
+
+// ------------------------------ PostIncConstNode ----------------------------------
+
+JSValue* PostIncConstNode::evaluate(ExecState* exec)
+{
+    ASSERT(exec->variableObject() == exec->scopeChain().top());
+    return jsNumber(exec->localStorage()[m_index].value->toNumber(exec));
+}
+
+// ------------------------------ PostDecConstNode ----------------------------------
+
+JSValue* PostDecConstNode::evaluate(ExecState* exec)
+{
+    ASSERT(exec->variableObject() == exec->scopeChain().top());
+    return jsNumber(exec->localStorage()[m_index].value->toNumber(exec));
+}
+
 // ------------------------------ PrefixBracketNode ----------------------------------
 
-void PrefixBracketNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void PrefixBracketNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(m_subscript.get());
     nodeStack.append(m_base.get());
@@ -1895,7 +1949,7 @@ JSValue *PreDecBracketNode::evaluate(ExecState *exec)
 
 // ------------------------------ PrefixDotNode ----------------------------------
 
-void PrefixDotNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void PrefixDotNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(m_base.get());
 }
@@ -1946,7 +2000,7 @@ JSValue* PrefixErrorNode::evaluate(ExecState* exec)
 
 // ------------------------------ UnaryPlusNode --------------------------------
 
-void UnaryPlusNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void UnaryPlusNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(m_expr.get());
 }
@@ -1981,7 +2035,7 @@ uint32_t UnaryPlusNode::evaluateToUInt32(ExecState* exec)
 
 // ------------------------------ NegateNode -----------------------------------
 
-void NegateNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void NegateNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(expr.get());
 }
@@ -2001,7 +2055,7 @@ double NegateNode::evaluateToNumber(ExecState* exec)
 
 // ------------------------------ BitwiseNotNode -------------------------------
 
-void BitwiseNotNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void BitwiseNotNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(expr.get());
 }
@@ -2039,7 +2093,7 @@ uint32_t BitwiseNotNode::evaluateToUInt32(ExecState* exec)
 
 // ------------------------------ LogicalNotNode -------------------------------
 
-void LogicalNotNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void LogicalNotNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(expr.get());
 }
@@ -2057,7 +2111,7 @@ bool LogicalNotNode::evaluateToBoolean(ExecState* exec)
 
 // ------------------------------ Multiplicative Nodes -----------------------------------
 
-void MultNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void MultNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(term1.get());
     nodeStack.append(term2.get());
@@ -2097,7 +2151,7 @@ uint32_t MultNode::evaluateToUInt32(ExecState* exec)
     return JSValue::toUInt32(inlineEvaluateToNumber(exec));
 }
 
-void DivNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void DivNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(term1.get());
     nodeStack.append(term2.get());
@@ -2132,7 +2186,7 @@ uint32_t DivNode::evaluateToUInt32(ExecState* exec)
     return JSValue::toUInt32(inlineEvaluateToNumber(exec));
 }
 
-void ModNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void ModNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(term1.get());
     nodeStack.append(term2.get());
@@ -2269,7 +2323,7 @@ static inline double addToNumber(ExecState* exec, JSValue* v1, JSValue *v2)
     return addSlowCaseToNumber(exec, v1, v2);
 }
 
-void AddNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void AddNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(term1.get());
     nodeStack.append(term2.get());
@@ -2376,7 +2430,7 @@ JSValue* AddStringRightNode::evaluate(ExecState* exec)
     return jsString(p1->toString(exec) + static_cast<StringImp*>(v2)->value());
 }
 
-void SubNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void SubNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(term1.get());
     nodeStack.append(term2.get());
@@ -2413,7 +2467,7 @@ uint32_t SubNode::evaluateToUInt32(ExecState* exec)
 
 // ------------------------------ Shift Nodes ------------------------------------
 
-void LeftShiftNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void LeftShiftNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(term1.get());
     nodeStack.append(term2.get());
@@ -2448,7 +2502,7 @@ uint32_t LeftShiftNode::evaluateToUInt32(ExecState* exec)
     return inlineEvaluateToInt32(exec);
 }
 
-void RightShiftNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void RightShiftNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(term1.get());
     nodeStack.append(term2.get());
@@ -2483,7 +2537,7 @@ uint32_t RightShiftNode::evaluateToUInt32(ExecState* exec)
     return inlineEvaluateToInt32(exec);
 }
 
-void UnsignedRightShiftNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void UnsignedRightShiftNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(term1.get());
     nodeStack.append(term2.get());
@@ -2550,7 +2604,7 @@ static inline bool lessThanEq(ExecState *exec, JSValue* v1, JSValue* v2)
     return !(static_cast<const StringImp*>(p2)->value() < static_cast<const StringImp*>(p1)->value());
 }
 
-void LessNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void LessNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(expr2.get());
     nodeStack.append(expr1.get());
@@ -2612,7 +2666,7 @@ bool LessStringsNode::evaluateToBoolean(ExecState* exec)
     return inlineEvaluateToBoolean(exec);
 }
 
-void GreaterNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void GreaterNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(expr2.get());
     nodeStack.append(expr1.get());
@@ -2638,7 +2692,7 @@ bool GreaterNode::evaluateToBoolean(ExecState *exec)
     return inlineEvaluateToBoolean(exec);
 }
 
-void LessEqNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void LessEqNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(expr2.get());
     nodeStack.append(expr1.get());
@@ -2664,7 +2718,7 @@ bool LessEqNode::evaluateToBoolean(ExecState* exec)
     return inlineEvaluateToBoolean(exec);
 }
 
-void GreaterEqNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void GreaterEqNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(expr2.get());
     nodeStack.append(expr1.get());
@@ -2690,7 +2744,7 @@ bool GreaterEqNode::evaluateToBoolean(ExecState* exec)
     return inlineEvaluateToBoolean(exec);
 }
 
-void InstanceOfNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void InstanceOfNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(expr2.get());
     nodeStack.append(expr1.get());
@@ -2743,7 +2797,7 @@ bool InstanceOfNode::evaluateToBoolean(ExecState* exec)
     return o2->hasInstance(exec, v1);
 }
 
-void InNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void InNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(expr2.get());
     nodeStack.append(expr1.get());
@@ -2780,7 +2834,7 @@ bool InNode::evaluateToBoolean(ExecState *exec)
 
 // ------------------------------ Equality Nodes ------------------------------------
 
-void EqualNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void EqualNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(expr2.get());
     nodeStack.append(expr1.get());
@@ -2807,7 +2861,7 @@ bool EqualNode::evaluateToBoolean(ExecState* exec)
     return inlineEvaluateToBoolean(exec);
 }
 
-void NotEqualNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void NotEqualNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(expr2.get());
     nodeStack.append(expr1.get());
@@ -2834,7 +2888,7 @@ bool NotEqualNode::evaluateToBoolean(ExecState* exec)
     return inlineEvaluateToBoolean(exec);
 }
 
-void StrictEqualNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void StrictEqualNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(expr2.get());
     nodeStack.append(expr1.get());
@@ -2861,7 +2915,7 @@ bool StrictEqualNode::evaluateToBoolean(ExecState* exec)
     return inlineEvaluateToBoolean(exec);
 }
 
-void NotStrictEqualNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void NotStrictEqualNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(expr2.get());
     nodeStack.append(expr1.get());
@@ -2890,7 +2944,7 @@ bool NotStrictEqualNode::evaluateToBoolean(ExecState* exec)
 
 // ------------------------------ Bit Operation Nodes ----------------------------------
 
-void BitAndNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void BitAndNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(expr2.get());
     nodeStack.append(expr1.get());
@@ -2935,7 +2989,7 @@ uint32_t BitAndNode::evaluateToUInt32(ExecState* exec)
     return inlineEvaluateToInt32(exec);
 }
 
-void BitXOrNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void BitXOrNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(expr2.get());
     nodeStack.append(expr1.get());
@@ -2974,7 +3028,7 @@ uint32_t BitXOrNode::evaluateToUInt32(ExecState* exec)
     return inlineEvaluateToInt32(exec);
 }
 
-void BitOrNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void BitOrNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(expr2.get());
     nodeStack.append(expr1.get());
@@ -3015,7 +3069,7 @@ uint32_t BitOrNode::evaluateToUInt32(ExecState* exec)
 
 // ------------------------------ Binary Logical Nodes ----------------------------
 
-void LogicalAndNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void LogicalAndNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(expr2.get());
     nodeStack.append(expr1.get());
@@ -3042,7 +3096,7 @@ bool LogicalAndNode::evaluateToBoolean(ExecState* exec)
     return b && expr2->evaluateToBoolean(exec);
 }
 
-void LogicalOrNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void LogicalOrNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(expr2.get());
     nodeStack.append(expr1.get());
@@ -3066,7 +3120,7 @@ bool LogicalOrNode::evaluateToBoolean(ExecState* exec)
 
 // ------------------------------ ConditionalNode ------------------------------
 
-void ConditionalNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void ConditionalNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(expr2.get());
     nodeStack.append(expr1.get());
@@ -3177,22 +3231,34 @@ static ALWAYS_INLINE JSValue* valueForReadModifyAssignment(ExecState* exec, JSVa
 
 // ------------------------------ ReadModifyResolveNode -----------------------------------
 
-void ReadModifyResolveNode::optimizeVariableAccess(SymbolTable& symbolTable, DeclarationStacks::NodeStack& nodeStack)
+void ReadModifyResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage& localStorage, NodeStack& nodeStack)
 {
     nodeStack.append(m_right.get());
     size_t index = symbolTable.get(m_ident.ustring().rep());
-    if (index != missingSymbolMarker())
-        new (this) ReadModifyLocalVarNode(index);
+    if (index != missingSymbolMarker()) {
+        if (isConstant(localStorage, index))
+            new (this) ReadModifyConstNode(index);
+        else
+            new (this) ReadModifyLocalVarNode(index);
+    }
 }
 
-void AssignResolveNode::optimizeVariableAccess(SymbolTable& symbolTable, DeclarationStacks::NodeStack& nodeStack)
+// ------------------------------ AssignResolveNode -----------------------------------
+
+void AssignResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage& localStorage, NodeStack& nodeStack)
 {
     nodeStack.append(m_right.get());
     size_t index = symbolTable.get(m_ident.ustring().rep());
-    if (index != missingSymbolMarker())
-        new (this) AssignLocalVarNode(index);
+    if (index != missingSymbolMarker()) {
+        if (isConstant(localStorage, index))
+            new (this) AssignConstNode;
+        else
+            new (this) AssignLocalVarNode(index);
+    }
 }
 
+// ------------------------------ ReadModifyLocalVarNode -----------------------------------
+
 JSValue* ReadModifyLocalVarNode::evaluate(ExecState* exec)
 {
     ASSERT(exec->variableObject() == exec->scopeChain().top());
@@ -3207,6 +3273,8 @@ JSValue* ReadModifyLocalVarNode::evaluate(ExecState* exec)
     return v;
 }
 
+// ------------------------------ AssignLocalVarNode -----------------------------------
+
 JSValue* AssignLocalVarNode::evaluate(ExecState* exec)
 {
     ASSERT(exec->variableObject() == exec->scopeChain().top());
@@ -3219,6 +3287,25 @@ JSValue* AssignLocalVarNode::evaluate(ExecState* exec)
     return v;
 }
 
+// ------------------------------ ReadModifyConstNode -----------------------------------
+
+JSValue* ReadModifyConstNode::evaluate(ExecState* exec)
+{
+    ASSERT(exec->variableObject() == exec->scopeChain().top());
+    JSValue* left = exec->localStorage()[m_index].value;
+    ASSERT(m_oper != OpEqual);
+    JSValue* result = valueForReadModifyAssignment(exec, left, m_right.get(), m_oper);
+    KJS_CHECKEXCEPTIONVALUE
+    return result;
+}
+
+// ------------------------------ AssignConstNode -----------------------------------
+
+JSValue* AssignConstNode::evaluate(ExecState* exec)
+{
+    return m_right->evaluate(exec);
+}
+
 JSValue *ReadModifyResolveNode::evaluate(ExecState *exec)
 {
   const ScopeChain& chain = exec->scopeChain();
@@ -3294,7 +3381,7 @@ JSValue *AssignResolveNode::evaluate(ExecState *exec)
 
 // ------------------------------ ReadModifyDotNode -----------------------------------
 
-void AssignDotNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void AssignDotNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(m_right.get());
     nodeStack.append(m_base.get());
@@ -3314,7 +3401,7 @@ JSValue *AssignDotNode::evaluate(ExecState *exec)
   return v;
 }
 
-void ReadModifyDotNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void ReadModifyDotNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(m_right.get());
     nodeStack.append(m_base.get());
@@ -3351,7 +3438,7 @@ JSValue* AssignErrorNode::evaluate(ExecState* exec)
 
 // ------------------------------ AssignBracketNode -----------------------------------
 
-void AssignBracketNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void AssignBracketNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(m_right.get());
     nodeStack.append(m_subscript.get());
@@ -3383,7 +3470,7 @@ JSValue *AssignBracketNode::evaluate(ExecState *exec)
   base->put(exec, propertyName, v);
   return v;
 }
-void ReadModifyBracketNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void ReadModifyBracketNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(m_right.get());
     nodeStack.append(m_subscript.get());
@@ -3431,7 +3518,7 @@ JSValue *ReadModifyBracketNode::evaluate(ExecState *exec)
 
 // ------------------------------ CommaNode ------------------------------------
 
-void CommaNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void CommaNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(expr2.get());
     nodeStack.append(expr1.get());
@@ -3453,7 +3540,7 @@ ConstDeclNode::ConstDeclNode(const Identifier& id, ExpressionNode* in)
 {
 }
 
-void ConstDeclNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void ConstDeclNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     if (next)
         nodeStack.append(next.get());
@@ -3541,7 +3628,7 @@ JSValue* ConstDeclNode::evaluate(ExecState* exec)
 
 // ------------------------------ ConstStatementNode -----------------------------
 
-void ConstStatementNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void ConstStatementNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     ASSERT(next);
     nodeStack.append(next.get());
@@ -3607,7 +3694,7 @@ BlockNode::BlockNode(SourceElements* children)
         children->releaseContentsIntoVector(m_children);
 }
 
-void BlockNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void BlockNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     statementListPushFIFO(m_children, nodeStack);
 }
@@ -3628,7 +3715,7 @@ JSValue* EmptyStatementNode::execute(ExecState* exec)
 
 // ------------------------------ ExprStatementNode ----------------------------
 
-void ExprStatementNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void ExprStatementNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     ASSERT(expr);
     nodeStack.append(expr.get());
@@ -3645,7 +3732,7 @@ JSValue* ExprStatementNode::execute(ExecState* exec)
 
 // ------------------------------ VarStatementNode ----------------------------
 
-void VarStatementNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void VarStatementNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     ASSERT(expr);
     nodeStack.append(expr.get());
@@ -3661,7 +3748,7 @@ JSValue* VarStatementNode::execute(ExecState* exec)
 
 // ------------------------------ IfNode ---------------------------------------
 
-void IfNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void IfNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(m_ifBlock.get());
     nodeStack.append(m_condition.get());
@@ -3678,10 +3765,10 @@ JSValue* IfNode::execute(ExecState* exec)
     return exec->setNormalCompletion();
 }
 
-void IfElseNode::optimizeVariableAccess(SymbolTable& table, DeclarationStacks::NodeStack& nodeStack)
+void IfElseNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage& localStorage, NodeStack& nodeStack)
 {
     nodeStack.append(m_elseBlock.get());
-    IfNode::optimizeVariableAccess(table, nodeStack);
+    IfNode::optimizeVariableAccess(symbolTable, localStorage, nodeStack);
 }
 
 // ECMA 12.5
@@ -3698,7 +3785,7 @@ JSValue* IfElseNode::execute(ExecState* exec)
 
 // ------------------------------ DoWhileNode ----------------------------------
 
-void DoWhileNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void DoWhileNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(statement.get());
     nodeStack.append(expr.get());
@@ -3740,7 +3827,7 @@ continueDoWhileLoop:
 
 // ------------------------------ WhileNode ------------------------------------
 
-void WhileNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void WhileNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(statement.get());
     nodeStack.append(expr.get());
@@ -3781,7 +3868,7 @@ JSValue* WhileNode::execute(ExecState* exec)
 
 // ------------------------------ ForNode --------------------------------------
 
-void ForNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void ForNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(statement.get());
     nodeStack.append(expr3.get());
@@ -3843,7 +3930,7 @@ ForInNode::ForInNode(const Identifier& i, ExpressionNode* in, ExpressionNode* e,
   // for( var foo = bar in baz )
 }
 
-void ForInNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void ForInNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(statement.get());
     nodeStack.append(expr.get());
@@ -3972,7 +4059,7 @@ JSValue* BreakNode::execute(ExecState *exec)
 
 // ------------------------------ ReturnNode -----------------------------------
 
-void ReturnNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void ReturnNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     if (value)
         nodeStack.append(value.get());
@@ -3996,7 +4083,7 @@ JSValue* ReturnNode::execute(ExecState* exec)
 
 // ------------------------------ WithNode -------------------------------------
 
-void WithNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void WithNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     // Can't optimize within statement because "with" introduces a dynamic scope.
     nodeStack.append(expr.get());
@@ -4019,7 +4106,7 @@ JSValue* WithNode::execute(ExecState *exec)
     
 // ------------------------------ CaseClauseNode -------------------------------
 
-void CaseClauseNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void CaseClauseNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     if (expr)
         nodeStack.append(expr.get());
@@ -4043,7 +4130,7 @@ JSValue* CaseClauseNode::executeStatements(ExecState* exec)
 
 // ------------------------------ ClauseListNode -------------------------------
 
-void ClauseListNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void ClauseListNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     if (next)
         nodeStack.append(next.get());
@@ -4059,7 +4146,7 @@ CaseBlockNode::CaseBlockNode(ClauseListNode* l1, CaseClauseNode* d, ClauseListNo
 {
 }
  
-void CaseBlockNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void CaseBlockNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     if (list2)
         nodeStack.append(list2.get());
@@ -4129,7 +4216,7 @@ JSValue* CaseBlockNode::executeBlock(ExecState* exec, JSValue* input)
 
 // ------------------------------ SwitchNode -----------------------------------
 
-void SwitchNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void SwitchNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(block.get());
     nodeStack.append(expr.get());
@@ -4152,7 +4239,7 @@ JSValue* SwitchNode::execute(ExecState* exec)
 
 // ------------------------------ LabelNode ------------------------------------
 
-void LabelNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void LabelNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(statement.get());
 }
@@ -4172,7 +4259,7 @@ JSValue* LabelNode::execute(ExecState *exec)
 
 // ------------------------------ ThrowNode ------------------------------------
 
-void ThrowNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void ThrowNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     nodeStack.append(expr.get());
 }
@@ -4189,7 +4276,7 @@ JSValue* ThrowNode::execute(ExecState* exec)
 
 // ------------------------------ TryNode --------------------------------------
 
-void TryNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void TryNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
 {
     // Can't optimize within catchBlock because "catch" introduces a dynamic scope.
     if (finallyBlock)
@@ -4228,45 +4315,50 @@ JSValue* TryNode::execute(ExecState *exec)
 
 // ------------------------------ FunctionBodyNode -----------------------------
 
-ScopeNode::ScopeNode(SourceElements* children, DeclarationStacks::VarStack* varStack, DeclarationStacks::FunctionStack* funcStack)
+ScopeNode::ScopeNode(SourceElements* children, VarStack* varStack, FunctionStack* funcStack)
     : BlockNode(children)
     , m_sourceURL(parser().sourceURL())
     , m_sourceId(parser().sourceId())
 {
     if (varStack)
         m_varStack = *varStack;
-
     if (funcStack)
         m_functionStack = *funcStack;
 }
 
-ProgramNode::ProgramNode(SourceElements* children, DeclarationStacks::VarStack* varStack, DeclarationStacks::FunctionStack* funcStack)
+// ------------------------------ ProgramNode -----------------------------
+
+ProgramNode::ProgramNode(SourceElements* children, VarStack* varStack, FunctionStack* funcStack)
     : ScopeNode(children, varStack, funcStack)
 {
 }
 
-ProgramNode* ProgramNode::create(SourceElements* children, DeclarationStacks::VarStack* varStack, DeclarationStacks::FunctionStack* funcStack)
+ProgramNode* ProgramNode::create(SourceElements* children, VarStack* varStack, FunctionStack* funcStack)
 {
     return new ProgramNode(children, varStack, funcStack);
 }
 
-EvalNode::EvalNode(SourceElements* children, DeclarationStacks::VarStack* varStack, DeclarationStacks::FunctionStack* funcStack)
+// ------------------------------ EvalNode -----------------------------
+
+EvalNode::EvalNode(SourceElements* children, VarStack* varStack, FunctionStack* funcStack)
     : ScopeNode(children, varStack, funcStack)
 {
 }
 
-EvalNode* EvalNode::create(SourceElements* children, DeclarationStacks::VarStack* varStack, DeclarationStacks::FunctionStack* funcStack)
+EvalNode* EvalNode::create(SourceElements* children, VarStack* varStack, FunctionStack* funcStack)
 {
     return new EvalNode(children, varStack, funcStack);
 }
 
-FunctionBodyNode::FunctionBodyNode(SourceElements* children, DeclarationStacks::VarStack* varStack, DeclarationStacks::FunctionStack* funcStack)
+// ------------------------------ FunctionBodyNode -----------------------------
+
+FunctionBodyNode::FunctionBodyNode(SourceElements* children, VarStack* varStack, FunctionStack* funcStack)
     : ScopeNode(children, varStack, funcStack)
     , m_initialized(false)
 {
 }
 
-FunctionBodyNode* FunctionBodyNode::create(SourceElements* children, DeclarationStacks::VarStack* varStack, DeclarationStacks::FunctionStack* funcStack)
+FunctionBodyNode* FunctionBodyNode::create(SourceElements* children, VarStack* varStack, FunctionStack* funcStack)
 {
     if (Debugger::debuggersPresent)
         return new FunctionBodyNodeWithDebuggerHooks(children, varStack, funcStack);
@@ -4280,6 +4372,8 @@ void FunctionBodyNode::initializeSymbolTable(ExecState* exec)
 
     size_t localStorageIndex = 0;
 
+    // Order must match the order in processDeclarations.
+
     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);
@@ -4311,6 +4405,8 @@ void ProgramNode::initializeSymbolTable(ExecState* exec)
 
     size_t localStorageIndex = symbolTable.size();
     size_t size;
+
+    // Order must match the order in processDeclarations.
     
     size = m_functionStack.size();
     m_functionIndexes.resize(size);
@@ -4337,6 +4433,7 @@ void ProgramNode::initializeSymbolTable(ExecState* exec)
             m_varIndexes[i] = missingSymbolMarker(); // Signal not to initialize this declaration.
             continue;
         }
+
         m_varIndexes[i] = result.first->second;
         ++localStorageIndex;
     }
@@ -4344,14 +4441,15 @@ void ProgramNode::initializeSymbolTable(ExecState* exec)
 
 void ScopeNode::optimizeVariableAccess(ExecState* exec)
 {
-    DeclarationStacks::NodeStack nodeStack;
+    NodeStack nodeStack;
     Node* node = statementListInitializeVariableAccessStack(m_children, nodeStack);
     if (!node)
         return;
     
-    SymbolTable& symbolTable = exec->variableObject()->symbolTable();
+    const SymbolTable& symbolTable = exec->variableObject()->symbolTable();
+    const LocalStorage& localStorage = exec->variableObject()->localStorage();
     while (true) {
-        node->optimizeVariableAccess(symbolTable, nodeStack);
+        node->optimizeVariableAccess(symbolTable, localStorage, nodeStack);
         
         size_t size = nodeStack.size();
         if (!size)
@@ -4364,15 +4462,11 @@ void ScopeNode::optimizeVariableAccess(ExecState* exec)
 
 void FunctionBodyNode::processDeclarations(ExecState* exec)
 {
-    if (!m_initialized) {
+    if (!m_initialized)
         initializeSymbolTable(exec);
-        optimizeVariableAccess(exec);
-        
-        m_initialized = true;
-    }
 
     if (m_functionStack.size() != 0)
-      exec->dynamicGlobalObject()->tearOffActivation(exec);
+        exec->dynamicGlobalObject()->tearOffActivation(exec);
 
     LocalStorage& localStorage = exec->variableObject()->localStorage();
     
@@ -4397,12 +4491,16 @@ void FunctionBodyNode::processDeclarations(ExecState* exec)
     }
 
     for (size_t i = 0, size = m_varStack.size(); i < size; ++i) {
-        bool isConstant = m_varStack[i].second & DeclarationStacks::IsConstant;
         int attributes = minAttributes;
-        if (isConstant)
+        if (m_varStack[i].second & DeclarationStacks::IsConstant)
             attributes |= ReadOnly;
         localStorage.uncheckedAppend(LocalStorageEntry(jsUndefined(), attributes));
     }
+
+    if (!m_initialized) {
+        optimizeVariableAccess(exec);        
+        m_initialized = true;
+    }
 }
 
 static void gccIsCrazy() KJS_FAST_CALL;
@@ -4418,7 +4516,6 @@ void ProgramNode::processDeclarations(ExecState* exec)
     gccIsCrazy();
     
     initializeSymbolTable(exec);
-    optimizeVariableAccess(exec);
 
     LocalStorage& localStorage = exec->variableObject()->localStorage();
 
@@ -4449,15 +4546,16 @@ void ProgramNode::processDeclarations(ExecState* exec)
         if (index == missingSymbolMarker())
             continue;
 
-        bool isConstant = m_varStack[i].second & DeclarationStacks::IsConstant;
         int attributes = minAttributes;
-        if (isConstant)
+        if (m_varStack[i].second & DeclarationStacks::IsConstant)
             attributes |= ReadOnly;
         LocalStorageEntry entry = LocalStorageEntry(jsUndefined(), attributes);
             
         ASSERT(index == localStorage.size());
         localStorage.uncheckedAppend(entry);
     }
+
+    optimizeVariableAccess(exec);
 }
 
 void EvalNode::processDeclarations(ExecState* exec)
@@ -4473,11 +4571,10 @@ void EvalNode::processDeclarations(ExecState* exec)
 
     for (i = 0, size = m_varStack.size(); i < size; ++i) {
         Identifier& ident = m_varStack[i].first;
-        bool isConstant = m_varStack[i].second & DeclarationStacks::IsConstant;
         if (variableObject->hasProperty(exec, ident))
             continue;
         int attributes = minAttributes;
-        if (isConstant)
+        if (m_varStack[i].second & DeclarationStacks::IsConstant)
             attributes |= ReadOnly;
         variableObject->put(exec, ident, jsUndefined(), attributes);
     }
index 9467234d57539bd991b11e7ca878cec2d02559ee..b51c73a3aab9018e4750657b43304e137112d538 100644 (file)
@@ -89,7 +89,7 @@ namespace KJS {
   
   struct DeclarationStacks {
       typedef Vector<Node*, 16> NodeStack;
-      enum { IsConstant, HasInitializer } VarAttrs;
+      enum { IsConstant = 1, HasInitializer = 2 } VarAttrs;
       typedef Vector<std::pair<Identifier, unsigned>, 16> VarStack;
       typedef Vector<FuncDeclNode*, 16> FunctionStack;
       
@@ -124,6 +124,10 @@ namespace KJS {
 
   class Node : public ParserRefCounted {
   public:
+    typedef DeclarationStacks::NodeStack NodeStack;
+    typedef DeclarationStacks::VarStack VarStack;
+    typedef DeclarationStacks::FunctionStack FunctionStack;
+
     Node() KJS_FAST_CALL;
     Node(PlacementNewAdoptType placementAdopt) KJS_FAST_CALL
     : ParserRefCounted(placementAdopt) { }
@@ -137,7 +141,7 @@ namespace KJS {
     virtual bool needsParensIfLeftmost() const { return false; }
 
     // Used for iterative, depth-first traversal of the node tree. Does not cross function call boundaries.
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL { }
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL { }
 
   protected:
     Node(JSType) KJS_FAST_CALL; // used by ExpressionNode
@@ -323,7 +327,7 @@ namespace KJS {
     {
     }
 
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
 
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
@@ -368,7 +372,7 @@ namespace KJS {
       : elision(e), node(n) { l->next = this; }
     virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
 
     PassRefPtr<ElementNode> releaseNext() KJS_FAST_CALL { return next.release(); }
 
@@ -388,7 +392,7 @@ namespace KJS {
       : element(ele), elision(0), opt(false) { }
     ArrayNode(int eli, ElementNode* ele) KJS_FAST_CALL
       : element(ele), elision(eli), opt(true) { }
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
     virtual Precedence precedence() const { return PrecPrimary; }
@@ -403,7 +407,7 @@ namespace KJS {
     enum Type { Constant, Getter, Setter };
     PropertyNode(const Identifier& n, ExpressionNode* a, Type t) KJS_FAST_CALL
       : m_name(n), assign(a), type(t) { }
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
     virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
 
@@ -423,7 +427,7 @@ namespace KJS {
       : node(n) { }
     PropertyListNode(PropertyNode* n, PropertyListNode* l) KJS_FAST_CALL
       : node(n) { l->next = this; }
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
     virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
 
@@ -440,7 +444,7 @@ namespace KJS {
   public:
     ObjectLiteralNode() KJS_FAST_CALL { }
     ObjectLiteralNode(PropertyListNode* l) KJS_FAST_CALL : list(l) { }
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
     virtual Precedence precedence() const { return PrecPrimary; }
@@ -452,7 +456,7 @@ namespace KJS {
   class BracketAccessorNode : public ExpressionNode {
   public:
     BracketAccessorNode(ExpressionNode* e1, ExpressionNode* e2) KJS_FAST_CALL : expr1(e1), expr2(e2) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
     virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
@@ -475,7 +479,7 @@ namespace KJS {
   class DotAccessorNode : public ExpressionNode {
   public:
     DotAccessorNode(ExpressionNode* e, const Identifier& s) KJS_FAST_CALL : expr(e), ident(s) { }
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
     virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
@@ -500,7 +504,7 @@ namespace KJS {
     ArgumentListNode(ExpressionNode* e) KJS_FAST_CALL : expr(e) { }
     ArgumentListNode(ArgumentListNode* l, ExpressionNode* e) KJS_FAST_CALL 
       : expr(e) { l->next = this; }
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
     virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
 
@@ -518,7 +522,7 @@ namespace KJS {
     ArgumentsNode() KJS_FAST_CALL { }
     ArgumentsNode(ArgumentListNode* l) KJS_FAST_CALL
       : listNode(l) { }
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
     virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
 
@@ -532,7 +536,7 @@ namespace KJS {
   public:
     NewExprNode(ExpressionNode* e) KJS_FAST_CALL : expr(e) {}
     NewExprNode(ExpressionNode* e, ArgumentsNode* a) KJS_FAST_CALL : expr(e), args(a) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
     virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
@@ -549,7 +553,7 @@ namespace KJS {
   class FunctionCallValueNode : public ExpressionNode {
   public:
     FunctionCallValueNode(ExpressionNode* e, ArgumentsNode* a) KJS_FAST_CALL : expr(e), args(a) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
     virtual Precedence precedence() const { return PrecCall; }
@@ -573,7 +577,7 @@ namespace KJS {
     {
     }
 
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
     virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
@@ -610,7 +614,7 @@ namespace KJS {
   class FunctionCallBracketNode : public ExpressionNode {
   public:
     FunctionCallBracketNode(ExpressionNode* b, ExpressionNode* s, ArgumentsNode* a) KJS_FAST_CALL : base(b), subscript(s), args(a) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
     virtual Precedence precedence() const { return PrecCall; }
@@ -623,7 +627,7 @@ namespace KJS {
   class FunctionCallDotNode : public ExpressionNode {
   public:
     FunctionCallDotNode(ExpressionNode* b, const Identifier& i, ArgumentsNode* a) KJS_FAST_CALL : base(b), ident(i), args(a) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
     virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
@@ -662,12 +666,11 @@ namespace KJS {
     {
     }
 
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
     virtual Precedence precedence() const { return PrecPostfix; }
     virtual void optimizeForUnnecessaryResult();
-
   };
 
   class PostIncLocalVarNode : public PostIncResolveNode {
@@ -683,6 +686,17 @@ namespace KJS {
     virtual void optimizeForUnnecessaryResult();
   };
 
+  class PostIncConstNode : public PostIncResolveNode {
+  public:
+    PostIncConstNode(size_t i) KJS_FAST_CALL
+        : PostIncResolveNode(PlacementNewAdopt)
+    {
+        ASSERT(i != missingSymbolMarker());
+        m_index = i;
+    }
+    virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+  };
+
   class PostDecResolveNode : public PrePostResolveNode {
   public:
     PostDecResolveNode(const Identifier& i) KJS_FAST_CALL : PrePostResolveNode(i) {}
@@ -692,7 +706,7 @@ namespace KJS {
     {
     }
 
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
     virtual Precedence precedence() const { return PrecPostfix; }
@@ -718,10 +732,21 @@ namespace KJS {
     ALWAYS_INLINE double inlineEvaluateToNumber(ExecState*);
   };
 
+  class PostDecConstNode : public PostDecResolveNode {
+  public:
+    PostDecConstNode(size_t i) KJS_FAST_CALL
+        : PostDecResolveNode(PlacementNewAdopt)
+    {
+        ASSERT(i != missingSymbolMarker());
+        m_index = i;
+    }
+    virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+  };
+
   class PostfixBracketNode : public ExpressionNode {
   public:
     PostfixBracketNode(ExpressionNode* b, ExpressionNode* s) KJS_FAST_CALL : m_base(b), m_subscript(s) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual Precedence precedence() const { return PrecPostfix; }
   protected:
     RefPtr<ExpressionNode> m_base;
@@ -745,7 +770,7 @@ namespace KJS {
     class PostfixDotNode : public ExpressionNode {
   public:
     PostfixDotNode(ExpressionNode* b, const Identifier& i) KJS_FAST_CALL : m_base(b), m_ident(i) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual Precedence precedence() const { return PrecPostfix; }
   protected:
     RefPtr<ExpressionNode> m_base;
@@ -786,7 +811,7 @@ namespace KJS {
     {
     }
 
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
     virtual Precedence precedence() const { return PrecUnary; }
@@ -807,7 +832,7 @@ namespace KJS {
   class DeleteBracketNode : public ExpressionNode {
   public:
     DeleteBracketNode(ExpressionNode* base, ExpressionNode* subscript) KJS_FAST_CALL : m_base(base), m_subscript(subscript) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
     virtual Precedence precedence() const { return PrecUnary; }
@@ -819,7 +844,7 @@ namespace KJS {
   class DeleteDotNode : public ExpressionNode {
   public:
     DeleteDotNode(ExpressionNode* base, const Identifier& i) KJS_FAST_CALL : m_base(base), m_ident(i) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
     virtual Precedence precedence() const { return PrecUnary; }
@@ -831,7 +856,7 @@ namespace KJS {
   class DeleteValueNode : public ExpressionNode {
   public:
     DeleteValueNode(ExpressionNode* e) KJS_FAST_CALL : m_expr(e) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
     virtual Precedence precedence() const { return PrecUnary; }
@@ -842,7 +867,7 @@ namespace KJS {
   class VoidNode : public ExpressionNode {
   public:
     VoidNode(ExpressionNode* e) KJS_FAST_CALL : expr(e) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
     virtual Precedence precedence() const { return PrecUnary; }
@@ -862,7 +887,7 @@ namespace KJS {
         m_expectedReturnType = StringType;
     }
 
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
@@ -891,7 +916,7 @@ namespace KJS {
   class TypeOfValueNode : public ExpressionNode {
   public:
     TypeOfValueNode(ExpressionNode* e) KJS_FAST_CALL : ExpressionNode(StringType), m_expr(e) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
     virtual Precedence precedence() const { return PrecUnary; }
@@ -911,7 +936,7 @@ namespace KJS {
     {
     }
     
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
 
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
@@ -930,6 +955,17 @@ namespace KJS {
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
   };
   
+  class PreIncConstNode : public PreIncResolveNode {
+  public:
+    PreIncConstNode(size_t i) KJS_FAST_CALL
+        : PreIncResolveNode(PlacementNewAdopt)
+    {
+        ASSERT(i != missingSymbolMarker());
+        m_index = i;
+    }
+    virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+  };
+
   class PreDecResolveNode : public PrePostResolveNode {
   public:
     PreDecResolveNode(const Identifier &s) KJS_FAST_CALL 
@@ -942,7 +978,7 @@ namespace KJS {
     {
     }
     
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
 
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
@@ -961,11 +997,22 @@ namespace KJS {
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
   };
   
+  class PreDecConstNode : public PreDecResolveNode {
+  public:
+    PreDecConstNode(size_t i) KJS_FAST_CALL
+        : PreDecResolveNode(PlacementNewAdopt)
+    {
+        ASSERT(i != missingSymbolMarker());
+        m_index = i;
+    }
+    virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+  };
+
   class PrefixBracketNode : public ExpressionNode {
   public:
     PrefixBracketNode(ExpressionNode* b, ExpressionNode* s) KJS_FAST_CALL : m_base(b), m_subscript(s) {}
     
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual Precedence precedence() const { return PrecUnary; }
   protected:
     RefPtr<ExpressionNode> m_base;
@@ -989,7 +1036,7 @@ namespace KJS {
   class PrefixDotNode : public ExpressionNode {
   public:
     PrefixDotNode(ExpressionNode* b, const Identifier& i) KJS_FAST_CALL : m_base(b), m_ident(i) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual Precedence precedence() const { return PrecPostfix; }
   protected:
     RefPtr<ExpressionNode> m_base;
@@ -1024,7 +1071,7 @@ namespace KJS {
   class UnaryPlusNode : public ExpressionNode {
   public:
     UnaryPlusNode(ExpressionNode* e) KJS_FAST_CALL : ExpressionNode(NumberType), m_expr(e) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
     virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
@@ -1039,7 +1086,7 @@ namespace KJS {
   class NegateNode : public ExpressionNode {
   public:
     NegateNode(ExpressionNode* e) KJS_FAST_CALL : ExpressionNode(NumberType), expr(e) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
@@ -1051,7 +1098,7 @@ namespace KJS {
   class BitwiseNotNode : public ExpressionNode {
   public:
     BitwiseNotNode(ExpressionNode* e) KJS_FAST_CALL : ExpressionNode(NumberType), expr(e) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
     virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
@@ -1067,7 +1114,7 @@ namespace KJS {
   class LogicalNotNode : public ExpressionNode {
   public:
     LogicalNotNode(ExpressionNode* e) KJS_FAST_CALL : ExpressionNode(BooleanType), expr(e) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
@@ -1079,7 +1126,7 @@ namespace KJS {
   class MultNode : public ExpressionNode {
   public:
       MultNode(ExpressionNode* t1, ExpressionNode* t2) KJS_FAST_CALL : ExpressionNode(NumberType), term1(t1), term2(t2) {}
-      virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+      virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
       virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
       virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
       virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
@@ -1096,7 +1143,7 @@ namespace KJS {
   class DivNode : public ExpressionNode {
   public:
       DivNode(ExpressionNode* t1, ExpressionNode* t2) KJS_FAST_CALL : ExpressionNode(NumberType), term1(t1), term2(t2) {}
-      virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+      virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
       virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
       virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
       virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
@@ -1112,7 +1159,7 @@ namespace KJS {
   class ModNode : public ExpressionNode {
   public:
       ModNode(ExpressionNode* t1, ExpressionNode* t2) KJS_FAST_CALL : ExpressionNode(NumberType), term1(t1), term2(t2) {}
-      virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+      virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
       virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
       virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
       virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
@@ -1129,7 +1176,7 @@ namespace KJS {
   class AddNode : public ExpressionNode {
   public:
     AddNode(ExpressionNode* t1, ExpressionNode* t2) KJS_FAST_CALL : term1(t1), term2(t2) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
     virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
@@ -1176,7 +1223,7 @@ namespace KJS {
   class SubNode : public ExpressionNode {
   public:
       SubNode(ExpressionNode* t1, ExpressionNode* t2) KJS_FAST_CALL : ExpressionNode(NumberType), term1(t1), term2(t2) {}
-      virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+      virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
       virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
       virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
       virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
@@ -1193,7 +1240,7 @@ namespace KJS {
   public:
     LeftShiftNode(ExpressionNode* t1, ExpressionNode* t2) KJS_FAST_CALL
       : ExpressionNode(NumberType), term1(t1), term2(t2) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
     virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
@@ -1210,7 +1257,7 @@ namespace KJS {
   public:
     RightShiftNode(ExpressionNode* t1, ExpressionNode* t2) KJS_FAST_CALL
       : ExpressionNode(NumberType), term1(t1), term2(t2) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
     virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
@@ -1227,7 +1274,7 @@ namespace KJS {
   public:
     UnsignedRightShiftNode(ExpressionNode* t1, ExpressionNode* t2) KJS_FAST_CALL
       : ExpressionNode(NumberType), term1(t1), term2(t2) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
     virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
@@ -1244,7 +1291,7 @@ namespace KJS {
   public:
     LessNode(ExpressionNode* e1, ExpressionNode* e2) KJS_FAST_CALL
       : ExpressionNode(BooleanType), expr1(e1), expr2(e2) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
@@ -1280,7 +1327,7 @@ namespace KJS {
   public:
     GreaterNode(ExpressionNode* e1, ExpressionNode* e2) KJS_FAST_CALL :
       expr1(e1), expr2(e2) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
@@ -1295,7 +1342,7 @@ namespace KJS {
   public:
     LessEqNode(ExpressionNode* e1, ExpressionNode* e2) KJS_FAST_CALL :
       expr1(e1), expr2(e2) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
@@ -1310,7 +1357,7 @@ namespace KJS {
   public:
     GreaterEqNode(ExpressionNode* e1, ExpressionNode* e2) KJS_FAST_CALL :
       expr1(e1), expr2(e2) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
@@ -1325,7 +1372,7 @@ namespace KJS {
   public:
     InstanceOfNode(ExpressionNode* e1, ExpressionNode* e2) KJS_FAST_CALL
         : ExpressionNode(BooleanType), expr1(e1), expr2(e2) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
@@ -1339,7 +1386,7 @@ namespace KJS {
   public:
     InNode(ExpressionNode* e1, ExpressionNode* e2) KJS_FAST_CALL :
       expr1(e1), expr2(e2) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
@@ -1353,7 +1400,7 @@ namespace KJS {
   public:
     EqualNode(ExpressionNode* e1, ExpressionNode* e2) KJS_FAST_CALL
         : ExpressionNode(BooleanType), expr1(e1), expr2(e2) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
@@ -1368,7 +1415,7 @@ namespace KJS {
   public:
     NotEqualNode(ExpressionNode* e1, ExpressionNode* e2) KJS_FAST_CALL
         : ExpressionNode(BooleanType), expr1(e1), expr2(e2) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
@@ -1383,7 +1430,7 @@ namespace KJS {
   public:
     StrictEqualNode(ExpressionNode* e1, ExpressionNode* e2) KJS_FAST_CALL
         : ExpressionNode(BooleanType), expr1(e1), expr2(e2) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
@@ -1398,7 +1445,7 @@ namespace KJS {
   public:
     NotStrictEqualNode(ExpressionNode* e1, ExpressionNode* e2) KJS_FAST_CALL
         : ExpressionNode(BooleanType), expr1(e1), expr2(e2) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
@@ -1413,7 +1460,7 @@ namespace KJS {
   public:
     BitAndNode(ExpressionNode* e1, ExpressionNode* e2) KJS_FAST_CALL
         : ExpressionNode(NumberType), expr1(e1), expr2(e2) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
     virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
@@ -1431,7 +1478,7 @@ namespace KJS {
   public:
     BitOrNode(ExpressionNode* e1, ExpressionNode* e2) KJS_FAST_CALL
         : ExpressionNode(NumberType), expr1(e1), expr2(e2) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
     virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
@@ -1449,7 +1496,7 @@ namespace KJS {
   public:
     BitXOrNode(ExpressionNode* e1, ExpressionNode* e2) KJS_FAST_CALL
         : ExpressionNode(NumberType), expr1(e1), expr2(e2) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
     virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
@@ -1470,7 +1517,7 @@ namespace KJS {
   public:
     LogicalAndNode(ExpressionNode* e1, ExpressionNode* e2) KJS_FAST_CALL
         : ExpressionNode(BooleanType), expr1(e1), expr2(e2) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
@@ -1485,7 +1532,7 @@ namespace KJS {
   public:
     LogicalOrNode(ExpressionNode* e1, ExpressionNode* e2) KJS_FAST_CALL
         : ExpressionNode(BooleanType), expr1(e1), expr2(e2) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
@@ -1503,7 +1550,7 @@ namespace KJS {
   public:
     ConditionalNode(ExpressionNode*  l, ExpressionNode* e1, ExpressionNode* e2) KJS_FAST_CALL :
       logical(l), expr1(e1), expr2(e2) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
     virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
@@ -1533,7 +1580,7 @@ namespace KJS {
     {
     }
 
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
     virtual Precedence precedence() const { return PrecAssignment; }
@@ -1556,6 +1603,17 @@ namespace KJS {
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
   };
 
+  class ReadModifyConstNode : public ReadModifyResolveNode {
+  public:
+    ReadModifyConstNode(size_t i) KJS_FAST_CALL 
+        : ReadModifyResolveNode(PlacementNewAdopt)
+    {
+        ASSERT(i != missingSymbolMarker());
+        m_index = i;
+    }
+    virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+  };
+
     class AssignResolveNode : public ExpressionNode {
   public:
      AssignResolveNode(const Identifier &ident, ExpressionNode*  right) KJS_FAST_CALL
@@ -1571,7 +1629,7 @@ namespace KJS {
     {
     }
 
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
     virtual Precedence precedence() const { return PrecAssignment; }
@@ -1593,11 +1651,20 @@ namespace KJS {
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
   };
 
+  class AssignConstNode : public AssignResolveNode {
+  public:
+    AssignConstNode() KJS_FAST_CALL 
+        : AssignResolveNode(PlacementNewAdopt)
+    { 
+    }    
+    virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+  };
+
     class ReadModifyBracketNode : public ExpressionNode {
   public:
     ReadModifyBracketNode(ExpressionNode*  base, ExpressionNode*  subscript, Operator oper, ExpressionNode*  right) KJS_FAST_CALL
       : m_base(base), m_subscript(subscript), m_oper(oper), m_right(right) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
     virtual Precedence precedence() const { return PrecAssignment; }
@@ -1612,7 +1679,7 @@ namespace KJS {
   public:
     AssignBracketNode(ExpressionNode*  base, ExpressionNode*  subscript, ExpressionNode*  right) KJS_FAST_CALL
       : m_base(base), m_subscript(subscript), m_right(right) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
     virtual Precedence precedence() const { return PrecAssignment; }
@@ -1626,7 +1693,7 @@ namespace KJS {
   public:
     AssignDotNode(ExpressionNode*  base, const Identifier& ident, ExpressionNode*  right) KJS_FAST_CALL
       : m_base(base), m_ident(ident), m_right(right) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
     virtual Precedence precedence() const { return PrecAssignment; }
@@ -1640,7 +1707,7 @@ namespace KJS {
   public:
     ReadModifyDotNode(ExpressionNode*  base, const Identifier& ident, Operator oper, ExpressionNode*  right) KJS_FAST_CALL
       : m_base(base), m_ident(ident), m_oper(oper), m_right(right) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
     virtual Precedence precedence() const { return PrecAssignment; }
@@ -1670,7 +1737,7 @@ namespace KJS {
     {
         e1->optimizeForUnnecessaryResult();
     }
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
     virtual Precedence precedence() const { return PrecExpression; }
@@ -1682,7 +1749,7 @@ namespace KJS {
   class ConstDeclNode : public ExpressionNode {
   public:
     ConstDeclNode(const Identifier& id, ExpressionNode* in) KJS_FAST_CALL;
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual KJS::JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     void evaluateSingle(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
@@ -1699,7 +1766,7 @@ namespace KJS {
   class ConstStatementNode : public StatementNode {
   public:
     ConstStatementNode(ConstDeclNode* l) KJS_FAST_CALL : next(l) { }
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
   private:
@@ -1723,7 +1790,7 @@ namespace KJS {
   class BlockNode : public StatementNode {
   public:
     BlockNode(SourceElements* children) KJS_FAST_CALL;
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
   protected:
@@ -1741,7 +1808,7 @@ namespace KJS {
   class ExprStatementNode : public StatementNode {
   public:
     ExprStatementNode(ExpressionNode* e) KJS_FAST_CALL : expr(e) { }
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
   private:
@@ -1751,7 +1818,7 @@ namespace KJS {
   class VarStatementNode : public StatementNode {
   public:
     VarStatementNode(ExpressionNode* e) KJS_FAST_CALL : expr(e) { }
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
   private:
@@ -1762,7 +1829,7 @@ namespace KJS {
   public:
     IfNode(ExpressionNode* e, StatementNode *s) KJS_FAST_CALL
       : m_condition(e), m_ifBlock(s) { }
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
   protected:
@@ -1774,7 +1841,7 @@ namespace KJS {
     public:
         IfElseNode(ExpressionNode* e, StatementNode* ifBlock, StatementNode* elseBlock) KJS_FAST_CALL
             : IfNode(e, ifBlock), m_elseBlock(elseBlock) { }
-        virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+        virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
         virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
         virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
     private:
@@ -1784,7 +1851,7 @@ namespace KJS {
   class DoWhileNode : public StatementNode {
   public:
     DoWhileNode(StatementNode *s, ExpressionNode* e) KJS_FAST_CALL : statement(s), expr(e) { }
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
   private:
@@ -1795,7 +1862,7 @@ namespace KJS {
   class WhileNode : public StatementNode {
   public:
     WhileNode(ExpressionNode* e, StatementNode *s) KJS_FAST_CALL : expr(e), statement(s) { }
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
   private:
@@ -1821,7 +1888,7 @@ namespace KJS {
         expr3->optimizeForUnnecessaryResult();
     }
 
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
   private:
@@ -1836,7 +1903,7 @@ namespace KJS {
   public:
     ForInNode(ExpressionNode*  l, ExpressionNode* e, StatementNode *s) KJS_FAST_CALL;
     ForInNode(const Identifier &i, ExpressionNode *in, ExpressionNode* e, StatementNode *s) KJS_FAST_CALL;
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
   private:
@@ -1871,7 +1938,7 @@ namespace KJS {
   class ReturnNode : public StatementNode {
   public:
     ReturnNode(ExpressionNode* v) KJS_FAST_CALL : value(v) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
   private:
@@ -1881,7 +1948,7 @@ namespace KJS {
   class WithNode : public StatementNode {
   public:
     WithNode(ExpressionNode* e, StatementNode* s) KJS_FAST_CALL : expr(e), statement(s) { }
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
   private:
@@ -1892,7 +1959,7 @@ namespace KJS {
   class LabelNode : public StatementNode {
   public:
     LabelNode(const Identifier &l, StatementNode *s) KJS_FAST_CALL : label(l), statement(s) { }
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
   private:
@@ -1903,7 +1970,7 @@ namespace KJS {
   class ThrowNode : public StatementNode {
   public:
     ThrowNode(ExpressionNode* e) KJS_FAST_CALL : expr(e) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
   private:
@@ -1914,7 +1981,7 @@ namespace KJS {
   public:
     TryNode(StatementNode *b, const Identifier &e, StatementNode *c, StatementNode *f) KJS_FAST_CALL
       : tryBlock(b), exceptionIdent(e), catchBlock(c), finallyBlock(f) { }
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
   private:
@@ -1943,7 +2010,7 @@ namespace KJS {
 
   class ScopeNode : public BlockNode {
   public:
-    ScopeNode(SourceElements*, DeclarationStacks::VarStack*, DeclarationStacks::FunctionStack*) KJS_FAST_CALL;
+    ScopeNode(SourceElements*, VarStack*, FunctionStack*) KJS_FAST_CALL;
 
     int sourceId() const KJS_FAST_CALL { return m_sourceId; }
     const UString& sourceURL() const KJS_FAST_CALL { return m_sourceURL; }
@@ -1952,8 +2019,8 @@ namespace KJS {
   protected:
     void optimizeVariableAccess(ExecState*) KJS_FAST_CALL;
 
-    DeclarationStacks::VarStack m_varStack;
-    DeclarationStacks::FunctionStack m_functionStack;
+    VarStack m_varStack;
+    FunctionStack m_functionStack;
 
   private:
     UString m_sourceURL;
@@ -1962,11 +2029,11 @@ namespace KJS {
 
   class ProgramNode : public ScopeNode {
   public:
-    static ProgramNode* create(SourceElements*, DeclarationStacks::VarStack*, DeclarationStacks::FunctionStack*) KJS_FAST_CALL;
+    static ProgramNode* create(SourceElements*, VarStack*, FunctionStack*) KJS_FAST_CALL;
     virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
     
   private:
-    ProgramNode(SourceElements*, DeclarationStacks::VarStack*, DeclarationStacks::FunctionStack*) KJS_FAST_CALL;
+    ProgramNode(SourceElements*, VarStack*, FunctionStack*) KJS_FAST_CALL;
     void initializeSymbolTable(ExecState*) KJS_FAST_CALL;
     ALWAYS_INLINE void processDeclarations(ExecState*) KJS_FAST_CALL;
 
@@ -1976,17 +2043,17 @@ namespace KJS {
 
   class EvalNode : public ScopeNode {
   public:
-    static EvalNode* create(SourceElements*, DeclarationStacks::VarStack*, DeclarationStacks::FunctionStack*) KJS_FAST_CALL;
+    static EvalNode* create(SourceElements*, VarStack*, FunctionStack*) KJS_FAST_CALL;
     virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
     
   private:
-    EvalNode(SourceElements*, DeclarationStacks::VarStack*, DeclarationStacks::FunctionStack*) KJS_FAST_CALL;
+    EvalNode(SourceElements*, VarStack*, FunctionStack*) KJS_FAST_CALL;
     ALWAYS_INLINE void processDeclarations(ExecState*) KJS_FAST_CALL;
   };
 
   class FunctionBodyNode : public ScopeNode {
   public:
-    static FunctionBodyNode* create(SourceElements*, DeclarationStacks::VarStack*, DeclarationStacks::FunctionStack*) KJS_FAST_CALL;
+    static FunctionBodyNode* create(SourceElements*, VarStack*, FunctionStack*) KJS_FAST_CALL;
 
     virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
 
@@ -1996,7 +2063,7 @@ namespace KJS {
     UString paramString() const KJS_FAST_CALL;
 
   protected:
-    FunctionBodyNode(SourceElements*, DeclarationStacks::VarStack*, DeclarationStacks::FunctionStack*) KJS_FAST_CALL;
+    FunctionBodyNode(SourceElements*, VarStack*, FunctionStack*) KJS_FAST_CALL;
 
   private:
     void initializeSymbolTable(ExecState*) KJS_FAST_CALL;
@@ -2045,7 +2112,7 @@ namespace KJS {
       CaseClauseNode(ExpressionNode* e) KJS_FAST_CALL : expr(e) { }
       CaseClauseNode(ExpressionNode* e, SourceElements* children) KJS_FAST_CALL
       : expr(e) { if (children) children->releaseContentsIntoVector(m_children); }
-      virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+      virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
       virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
       virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
 
@@ -2062,7 +2129,7 @@ namespace KJS {
       ClauseListNode(CaseClauseNode* c) KJS_FAST_CALL : clause(c) { }
       ClauseListNode(ClauseListNode* n, CaseClauseNode* c) KJS_FAST_CALL
       : clause(c) { n->next = this; }
-      virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+      virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
       CaseClauseNode* getClause() const KJS_FAST_CALL { return clause.get(); }
       ClauseListNode* getNext() const KJS_FAST_CALL { return next.get(); }
       virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
@@ -2077,7 +2144,7 @@ namespace KJS {
     class CaseBlockNode : public Node {
   public:
       CaseBlockNode(ClauseListNode* l1, CaseClauseNode* d, ClauseListNode* l2) KJS_FAST_CALL;
-      virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+      virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
       JSValue* executeBlock(ExecState*, JSValue *input) KJS_FAST_CALL;
       virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
       virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
@@ -2090,7 +2157,7 @@ namespace KJS {
   class SwitchNode : public StatementNode {
   public:
       SwitchNode(ExpressionNode* e, CaseBlockNode *b) KJS_FAST_CALL : expr(e), block(b) { }
-      virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+      virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
       virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
       virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
   private:
@@ -2103,7 +2170,7 @@ namespace KJS {
         BreakpointCheckStatement(PassRefPtr<StatementNode>) KJS_FAST_CALL;
         virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
         virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
-        virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+        virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
     private:
         RefPtr<StatementNode> m_statement;
     };
index 3cce693627f5f103a1bf98f1225ced5962a967f0..8c6a154d018511f41780df7375e0a8bf52061581 100644 (file)
@@ -208,7 +208,6 @@ void JSObject::put(ExecState* exec, const Identifier &propertyName, JSValue *val
 {
   ASSERT(value);
 
-  // non-standard netscape extension
   if (propertyName == exec->propertyNames().underscoreProto) {
     JSObject* proto = value->getObject();
     while (proto) {
@@ -221,12 +220,10 @@ void JSObject::put(ExecState* exec, const Identifier &propertyName, JSValue *val
     return;
   }
 
-  /* TODO: check for write permissions directly w/o this call */
-  /* Doesn't look very easy with the PropertyMap API - David */
-  // putValue() is used for JS assignemnts. It passes no attribute.
-  // Assume that a C++ implementation knows what it is doing
-  // and let it override the canPut() check.
-  bool checkReadOnly = !(attr & (ReadOnly | DontEnum | Internal | Function | GetterSetter));
+  // The put calls from JavaScript execution either have no attributes set, or in some cases
+  // have DontDelete set. For those calls, respect the ReadOnly flag.
+  bool checkReadOnly = !(attr & ~DontDelete);
+
   // Check if there are any setters or getters in the prototype chain
   JSObject *obj = this;
   bool hasGettersOrSetters = false;
index 7a959ed94cf91113c19f972b17d5a1c790db3d7d..e97754a14520eb53391e8654a50df3080a065511 100644 (file)
@@ -1,3 +1,16 @@
+2008-01-27  Darin Adler  <darin@apple.com>
+
+        Reviewed by Oliver.
+
+        - tests for <rdar://problem/5657450> REGRESSION: const is broken
+
+        * fast/js/const-expected.txt: Updated with results that express success
+        rather than failure, and to include the many new tests I added.
+        * fast/js/kde/const-expected.txt: Ditto.
+        * fast/js/resources/const.js: Added many new tests, covering the various
+        cases of const in globals, function locals, the slow case inside eval,
+        the different node types, and the values of the expressions.
+
 2008-01-27  Darin Adler  <darin@apple.com>
 
         Reviewed by Oliver.
index e8f6aa67d69fbf46e37b2ba8dd42f36285d87e23..6430fd1e224b342666b9163f7c9dacf47d49a463 100644 (file)
@@ -3,8 +3,46 @@ This test checks that const declarations in JavaScript work and are readonly.
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-FAIL x should be RIGHT. Was WRONG.
-FAIL y should be RIGHT. Was WRONG.
+PASS x is "RIGHT"
+PASS y is "RIGHT"
+PASS a is 1
+PASS one is 1
+PASS a is 1
+PASS one is 1
+PASS a is 2
+PASS one is 1
+PASS a is 0
+PASS one is 1
+PASS a is 3
+PASS one is 1
+PASS a is 2
+PASS one is 1
+PASS function f() { const one = 1; one++; return one; } f(); is 1
+PASS function f() { const oneString = '1'; return oneString++; } f(); is 1
+PASS function f() { const one = 1; return one++; } f(); is 1
+PASS function f() { const one = 1; one--; return one; } f(); is 1
+PASS function f() { const oneString = '1'; return oneString--; } f(); is 1
+PASS function f() { const one = 1; return one--; } f(); is 1
+PASS function f() { const one = 1; ++one; return one; } f(); is 1
+PASS function f() { const one = 1; return ++one; } f(); is 2
+PASS function f() { const one = 1; --one; return one; } f(); is 1
+PASS function f() { const one = 1; return --one; } f(); is 0
+PASS function f() { const one = 1; one += 2; return one; } f(); is 1
+PASS function f() { const one = 1; return one += 2; } f(); is 3
+PASS function f() { const one = 1; one = 2; return one; } f(); is 1
+PASS function f() { const one = 1; return one = 2; } f(); is 2
+PASS one++ is 1
+PASS one is 1
+PASS one-- is 1
+PASS one is 1
+PASS ++one is 2
+PASS one is 1
+PASS --one is 0
+PASS one is 1
+PASS one += 1 is 2
+PASS one is 1
+PASS one = 2 is 2
+PASS one is 1
 PASS successfullyParsed is true
 
 TEST COMPLETE
index 10c046f8478a4100405995cb40c323377f72aceb..61cd431b42fc382fd3c9667ab6ce797f93bd3442 100644 (file)
@@ -4,7 +4,7 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
 
 
 PASS c is 11
-FAIL c should be 11. Was 22.
+PASS c is 11
 PASS v is 1
 PASS successfullyParsed is true
 
index bd8c0deeef432678a84714c7b097b9702f7c850c..ee462cda3d64f87355360fa56f4a0e9b2c4fbd54 100644 (file)
@@ -10,4 +10,88 @@ const x = "RIGHT", y = "RIGHT";
 y = "WRONG";
 shouldBe("y", '"RIGHT"');
 
+const one = 1;
+
+var a;
+
+// PostIncResolveNode
+a = one++;
+shouldBe("a", "1");
+shouldBe("one", "1");
+
+// PostDecResolveNode
+a = one--;
+shouldBe("a", "1");
+shouldBe("one", "1");
+
+// PreIncResolveNode
+a = ++one;
+shouldBe("a", "2");
+shouldBe("one", "1");
+
+// PreDecResolveNode
+a = --one;
+shouldBe("a", "0");
+shouldBe("one", "1");
+
+// ReadModifyConstNode
+a = one += 2;
+shouldBe("a", "3");
+shouldBe("one", "1");
+
+// AssignConstNode
+a = one = 2;
+shouldBe("a", "2");
+shouldBe("one", "1");
+
+// PostIncResolveNode
+shouldBe("function f() { const one = 1; one++; return one; } f();", "1");
+shouldBe("function f() { const oneString = '1'; return oneString++; } f();", "1");
+shouldBe("function f() { const one = 1; return one++; } f();", "1");
+
+// PostDecResolveNode
+shouldBe("function f() { const one = 1; one--; return one; } f();", "1");
+shouldBe("function f() { const oneString = '1'; return oneString--; } f();", "1");
+shouldBe("function f() { const one = 1; return one--; } f();", "1");
+
+// PreIncResolveNode
+shouldBe("function f() { const one = 1; ++one; return one; } f();", "1");
+shouldBe("function f() { const one = 1; return ++one; } f();", "2");
+
+// PreDecResolveNode
+shouldBe("function f() { const one = 1; --one; return one; } f();", "1");
+shouldBe("function f() { const one = 1; return --one; } f();", "0");
+
+// ReadModifyConstNode
+shouldBe("function f() { const one = 1; one += 2; return one; } f();", "1");
+shouldBe("function f() { const one = 1; return one += 2; } f();", "3");
+
+// AssignConstNode
+shouldBe("function f() { const one = 1; one = 2; return one; } f();", "1");
+shouldBe("function f() { const one = 1; return one = 2; } f();", "2");
+
+// PostIncResolveNode
+shouldBe("one++", "1");
+shouldBe("one", "1");
+
+// PostDecResolveNode
+shouldBe("one--", "1");
+shouldBe("one", "1");
+
+// PreIncResolveNode
+shouldBe("++one", "2");
+shouldBe("one", "1");
+
+// PreDecResolveNode
+shouldBe("--one", "0");
+shouldBe("one", "1");
+
+// ReadModifyConstNode
+shouldBe("one += 1", "2");
+shouldBe("one", "1");
+
+// AssignConstNode
+shouldBe("one = 2", "2");
+shouldBe("one", "1");
+
 var successfullyParsed = true;