Global properties that use LocalStorage are not correctly listed as enumerable.

Reviewed by Geoff Garen

The problem was caused by JSObject::getPropertyAttributes not being aware
of the JSVariableObject SymbolTable.  The fix is to make getPropertyAttributes
virtual and override in JSVariableObject.  This does not produce any performance
regression.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@31225 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/JavaScriptCore/ChangeLog b/JavaScriptCore/ChangeLog
index 5346c5c..8c31e3a 100644
--- a/JavaScriptCore/ChangeLog
+++ b/JavaScriptCore/ChangeLog
@@ -1,3 +1,21 @@
+2008-03-21  Oliver Hunt  <oliver@apple.com>
+
+        Reviewed by Geoff Garen.
+
+        Global properties that use LocalStorage are not correctly listed as enumerable.
+
+        The problem was caused by JSObject::getPropertyAttributes not being aware
+        of the JSVariableObject SymbolTable.  The fix is to make getPropertyAttributes
+        virtual and override in JSVariableObject.  This does not produce any performance
+        regression.
+
+        * JavaScriptCore.exp:
+        * kjs/JSVariableObject.cpp:
+        (KJS::JSVariableObject::getPropertyNames):
+        (KJS::JSVariableObject::getPropertyAttributes):
+        * kjs/JSVariableObject.h:
+        * kjs/object.h:
+
 2008-03-21  Arkadiusz Miskiewicz  <arekm@maven.pl>
 
         Webkit does not build on linux powerpc
diff --git a/JavaScriptCore/JavaScriptCore.exp b/JavaScriptCore/JavaScriptCore.exp
index e02d26f..40609b5 100644
--- a/JavaScriptCore/JavaScriptCore.exp
+++ b/JavaScriptCore/JavaScriptCore.exp
@@ -229,6 +229,7 @@
 __ZNK3KJS14JSGlobalObject14isDynamicScopeEv
 __ZNK3KJS16JSVariableObject16isVariableObjectEv
 __ZNK3KJS16JSVariableObject16saveLocalStorageERNS_15SavedPropertiesE
+__ZNK3KJS16JSVariableObject21getPropertyAttributesERKNS_10IdentifierERj
 __ZNK3KJS19InternalFunctionImp14implementsCallEv
 __ZNK3KJS19InternalFunctionImp21implementsHasInstanceEv
 __ZNK3KJS4List8getSliceEiRS0_
@@ -255,6 +256,7 @@
 __ZNK3KJS8JSObject12defaultValueEPNS_9ExecStateENS_6JSTypeE
 __ZNK3KJS8JSObject14implementsCallEv
 __ZNK3KJS8JSObject19implementsConstructEv
+__ZNK3KJS8JSObject21getPropertyAttributesERKNS_10IdentifierERj
 __ZNK3KJS8JSObject21implementsHasInstanceEv
 __ZNK3KJS8JSObject3getEPNS_9ExecStateERKNS_10IdentifierE
 __ZNK3KJS8JSObject3getEPNS_9ExecStateEj
diff --git a/JavaScriptCore/kjs/JSVariableObject.cpp b/JavaScriptCore/kjs/JSVariableObject.cpp
index 55779a8..16cfa60 100644
--- a/JavaScriptCore/kjs/JSVariableObject.cpp
+++ b/JavaScriptCore/kjs/JSVariableObject.cpp
@@ -84,13 +84,24 @@
 
 void JSVariableObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
 {
-    SymbolTable::const_iterator::Keys end = symbolTable().end().keys();
-    for (SymbolTable::const_iterator::Keys it = symbolTable().begin().keys(); it != end; ++it)
-        propertyNames.add(Identifier(it->get()));
-
+    SymbolTable::const_iterator end = symbolTable().end();
+    for (SymbolTable::const_iterator it = symbolTable().begin(); it != end; ++it)
+        if ((localStorage()[it->second].attributes & DontEnum) == 0)
+            propertyNames.add(Identifier(it->first.get()));
+    
     JSObject::getPropertyNames(exec, propertyNames);
 }
 
+bool JSVariableObject::getPropertyAttributes(const Identifier& propertyName, unsigned& attributes) const
+{
+    size_t index = symbolTable().get(propertyName.ustring().rep());
+    if (index != missingSymbolMarker()) {
+        attributes = localStorage()[index].attributes;
+        return true;
+    }
+    return JSObject::getPropertyAttributes(propertyName, attributes);
+}
+
 void JSVariableObject::mark()
 {
     JSObject::mark();
diff --git a/JavaScriptCore/kjs/JSVariableObject.h b/JavaScriptCore/kjs/JSVariableObject.h
index 947b81e..b00448a 100644
--- a/JavaScriptCore/kjs/JSVariableObject.h
+++ b/JavaScriptCore/kjs/JSVariableObject.h
@@ -37,8 +37,8 @@
 
     class JSVariableObject : public JSObject {
     public:
-        SymbolTable& symbolTable() { return *d->symbolTable; }
-        LocalStorage& localStorage() { return d->localStorage; }
+        SymbolTable& symbolTable() const { return *d->symbolTable; }
+        LocalStorage& localStorage() const { return d->localStorage; }
         
         void saveLocalStorage(SavedProperties&) const;
         void restoreLocalStorage(const SavedProperties&);
@@ -53,6 +53,8 @@
         virtual bool isVariableObject() const;
         virtual bool isDynamicScope() const = 0;
 
+        virtual bool getPropertyAttributes(const Identifier& propertyName, unsigned& attributes) const;
+
     protected:
         // Subclasses of JSVariableObject can subclass this struct to add data
         // without increasing their own size (since there's a hard limit on the
diff --git a/JavaScriptCore/kjs/object.h b/JavaScriptCore/kjs/object.h
index bd45a4e..8227a7c 100644
--- a/JavaScriptCore/kjs/object.h
+++ b/JavaScriptCore/kjs/object.h
@@ -403,7 +403,7 @@
     virtual UString toString(ExecState *exec) const;
     virtual JSObject *toObject(ExecState *exec) const;
     
-    bool getPropertyAttributes(const Identifier& propertyName, unsigned& attributes) const;
+    virtual bool getPropertyAttributes(const Identifier& propertyName, unsigned& attributes) const;
     
     // WebCore uses this to make document.all and style.filter undetectable
     virtual bool masqueradeAsUndefined() const { return false; }
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 7d2c74c..b6eac30 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,13 @@
+2008-03-21  Oliver Hunt  <oliver@apple.com>
+
+        Reviewed by Geoff Garen.
+
+        Ensure we correctly report optimised variables as being
+        enumerable.
+
+        * fast/js/propertyIsEnumerable-expected.txt:
+        * fast/js/resources/propertyIsEnumerable.js:
+
 2008-03-21  Sam Weinig  <sam@webkit.org>
 
         Reviewed by Oliver Hunt.
diff --git a/LayoutTests/fast/js/propertyIsEnumerable-expected.txt b/LayoutTests/fast/js/propertyIsEnumerable-expected.txt
index 08db3d5..2e59e50 100644
--- a/LayoutTests/fast/js/propertyIsEnumerable-expected.txt
+++ b/LayoutTests/fast/js/propertyIsEnumerable-expected.txt
@@ -6,6 +6,11 @@
 PASS a.propertyIsEnumerable('length') is false
 PASS a.propertyIsEnumerable ('foo') is true
 PASS a.propertyIsEnumerable ('non-existant') is false
+PASS global.propertyIsEnumerable ('aVarDecl') is true
+PASS global.propertyIsEnumerable ('aFunctionDecl') is true
+PASS global.propertyIsEnumerable ('Math') is false
+PASS global.propertyIsEnumerable ('NaN') is false
+PASS global.propertyIsEnumerable ('undefined') is false
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/LayoutTests/fast/js/resources/propertyIsEnumerable.js b/LayoutTests/fast/js/resources/propertyIsEnumerable.js
index 7d92cae..a3cd032 100644
--- a/LayoutTests/fast/js/resources/propertyIsEnumerable.js
+++ b/LayoutTests/fast/js/resources/propertyIsEnumerable.js
@@ -5,8 +5,17 @@
 a = new Array();
 a.foo='bar'
 
+var aVarDecl;
+function aFunctionDecl(){}
+var global = this;
 shouldBeFalse("a.propertyIsEnumerable('length')");
 shouldBeTrue("a.propertyIsEnumerable ('foo')");
 shouldBeFalse("a.propertyIsEnumerable ('non-existant')");
 
+shouldBeTrue("global.propertyIsEnumerable ('aVarDecl')");
+shouldBeTrue("global.propertyIsEnumerable ('aFunctionDecl')");
+shouldBeFalse("global.propertyIsEnumerable ('Math')");
+shouldBeFalse("global.propertyIsEnumerable ('NaN')");
+shouldBeFalse("global.propertyIsEnumerable ('undefined')");
+
 var successfullyParsed = true;