2008-10-30 Geoffrey Garen <ggaren@apple.com>
authorggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 31 Oct 2008 19:59:08 +0000 (19:59 +0000)
committerggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 31 Oct 2008 19:59:08 +0000 (19:59 +0000)
        Reviewed by Oliver Hunt.

        Fixed a small bit of https://bugs.webkit.org/show_bug.cgi?id=21962
        AST uses way too much memory

        Removed a word from StatementNode by nixing LabelStack and turning it
        into a compile-time data structure managed by CodeGenerator.

        v8 tests and SunSpider, run by Gavin, report no change.

        * GNUmakefile.am:
        * JavaScriptCore.order:
        * JavaScriptCore.pri:
        * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
        * JavaScriptCore.xcodeproj/project.pbxproj:
        * kjs/AllInOneFile.cpp:
        * JavaScriptCoreSources.bkl: I sure hope this builds!

        * VM/CodeGenerator.cpp:
        (JSC::CodeGenerator::CodeGenerator):
        (JSC::CodeGenerator::newLabelScope):
        (JSC::CodeGenerator::breakTarget):
        (JSC::CodeGenerator::continueTarget):
        * VM/CodeGenerator.h: Nixed the JumpContext system because it depended
        on a LabelStack in the AST, and it was a little cumbersome on the client
        side. Replaced with LabelScope, which tracks all break / continue
        information in the CodeGenerator, just like we track LabelIDs and other
        stacks of compile-time data.

        * kjs/LabelScope.h: Added.
        (JSC::LabelScope::):
        (JSC::LabelScope::LabelScope):
        (JSC::LabelScope::ref):
        (JSC::LabelScope::deref):
        (JSC::LabelScope::refCount):
        (JSC::LabelScope::breakTarget):
        (JSC::LabelScope::continueTarget):
        (JSC::LabelScope::type):
        (JSC::LabelScope::name):
        (JSC::LabelScope::scopeDepth): Simple abstraction for holding everything
        you might want to know about a break-able / continue-able scope.

        * kjs/LabelStack.cpp: Removed.
        * kjs/LabelStack.h: Removed.

        * kjs/grammar.y: No need to push labels at parse time -- we don't store
        LabelStacks in the AST anymore.

        * kjs/nodes.cpp:
        (JSC::DoWhileNode::emitCode):
        (JSC::WhileNode::emitCode):
        (JSC::ForNode::emitCode):
        (JSC::ForInNode::emitCode):
        (JSC::ContinueNode::emitCode):
        (JSC::BreakNode::emitCode):
        (JSC::SwitchNode::emitCode):
        (JSC::LabelNode::emitCode):
        * kjs/nodes.h:
        (JSC::StatementNode::):
        (JSC::LabelNode::): Use LabelScope where we used to use JumpContext.
        Simplified a bunch of code. Touched up label-related error messages a
        bit.

        * kjs/nodes2string.cpp:
        (JSC::LabelNode::streamTo): Updated for rename.

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

17 files changed:
JavaScriptCore/ChangeLog
JavaScriptCore/GNUmakefile.am
JavaScriptCore/JavaScriptCore.order
JavaScriptCore/JavaScriptCore.pri
JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
JavaScriptCore/JavaScriptCoreSources.bkl
JavaScriptCore/VM/CodeGenerator.cpp
JavaScriptCore/VM/CodeGenerator.h
JavaScriptCore/kjs/AllInOneFile.cpp
JavaScriptCore/kjs/LabelScope.h [new file with mode: 0644]
JavaScriptCore/kjs/LabelStack.cpp [deleted file]
JavaScriptCore/kjs/LabelStack.h [deleted file]
JavaScriptCore/kjs/grammar.y
JavaScriptCore/kjs/nodes.cpp
JavaScriptCore/kjs/nodes.h
JavaScriptCore/kjs/nodes2string.cpp

index e7db6fd..c26cf7b 100644 (file)
@@ -1,3 +1,71 @@
+2008-10-30  Geoffrey Garen  <ggaren@apple.com>
+
+        Reviewed by Oliver Hunt.
+        
+        Fixed a small bit of https://bugs.webkit.org/show_bug.cgi?id=21962
+        AST uses way too much memory
+        
+        Removed a word from StatementNode by nixing LabelStack and turning it
+        into a compile-time data structure managed by CodeGenerator.
+        
+        v8 tests and SunSpider, run by Gavin, report no change.
+
+        * GNUmakefile.am:
+        * JavaScriptCore.order:
+        * JavaScriptCore.pri:
+        * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * kjs/AllInOneFile.cpp:
+        * JavaScriptCoreSources.bkl: I sure hope this builds!
+        
+        * VM/CodeGenerator.cpp:
+        (JSC::CodeGenerator::CodeGenerator):
+        (JSC::CodeGenerator::newLabelScope):
+        (JSC::CodeGenerator::breakTarget):
+        (JSC::CodeGenerator::continueTarget):
+        * VM/CodeGenerator.h: Nixed the JumpContext system because it depended
+        on a LabelStack in the AST, and it was a little cumbersome on the client
+        side. Replaced with LabelScope, which tracks all break / continue
+        information in the CodeGenerator, just like we track LabelIDs and other
+        stacks of compile-time data.
+
+        * kjs/LabelScope.h: Added.
+        (JSC::LabelScope::):
+        (JSC::LabelScope::LabelScope):
+        (JSC::LabelScope::ref):
+        (JSC::LabelScope::deref):
+        (JSC::LabelScope::refCount):
+        (JSC::LabelScope::breakTarget):
+        (JSC::LabelScope::continueTarget):
+        (JSC::LabelScope::type):
+        (JSC::LabelScope::name):
+        (JSC::LabelScope::scopeDepth): Simple abstraction for holding everything
+        you might want to know about a break-able / continue-able scope.
+
+        * kjs/LabelStack.cpp: Removed.
+        * kjs/LabelStack.h: Removed.
+
+        * kjs/grammar.y: No need to push labels at parse time -- we don't store
+        LabelStacks in the AST anymore.
+
+        * kjs/nodes.cpp:
+        (JSC::DoWhileNode::emitCode):
+        (JSC::WhileNode::emitCode):
+        (JSC::ForNode::emitCode):
+        (JSC::ForInNode::emitCode):
+        (JSC::ContinueNode::emitCode):
+        (JSC::BreakNode::emitCode):
+        (JSC::SwitchNode::emitCode):
+        (JSC::LabelNode::emitCode):
+        * kjs/nodes.h:
+        (JSC::StatementNode::):
+        (JSC::LabelNode::): Use LabelScope where we used to use JumpContext.
+        Simplified a bunch of code. Touched up label-related error messages a
+        bit.
+
+        * kjs/nodes2string.cpp:
+        (JSC::LabelNode::streamTo): Updated for rename.
+
 2008-10-31  Cameron Zwarich  <zwarich@apple.com>
 
         Reviewed by Darin Adler.
index 23be186..f42baee 100644 (file)
@@ -317,8 +317,7 @@ javascriptcore_sources += \
        JavaScriptCore/kjs/JSLock.cpp \
        JavaScriptCore/kjs/JSLock.h \
        JavaScriptCore/kjs/JSStaticScopeObject.cpp \
-       JavaScriptCore/kjs/LabelStack.cpp \
-       JavaScriptCore/kjs/LabelStack.h \
+       JavaScriptCore/kjs/LabelScope.h \
        JavaScriptCore/kjs/Parser.cpp \
        JavaScriptCore/kjs/PropertyNameArray.cpp \
        JavaScriptCore/kjs/RegExpConstructor.cpp \
index 09d22bd..9f7cb30 100644 (file)
@@ -933,7 +933,6 @@ __ZNK3KJS12ContinueNode8streamToERNS_12SourceStreamE
 __ZN3KJS11FunctionImp12callerGetterEPNS_9ExecStateEPNS_8JSObjectERKNS_10IdentifierERKNS_12PropertySlotE
 __ZN3KJS9BreakNodeC1ERKNS_10IdentifierE
 __ZN3KJS13StatementNode9pushLabelERKNS_10IdentifierE
-__ZN3KJS10LabelStack4pushERKNS_10IdentifierE
 __ZN3KJS9ThrowNode7executeEPNS_9ExecStateE
 __ZNK3KJS15NumberObjectImp19implementsConstructEv
 __ZN3KJS22numberProtoFuncValueOfEPNS_9ExecStateEPNS_8JSObjectERKNS_4ListE
index 9fb71a1..1f91a18 100644 (file)
@@ -107,7 +107,6 @@ SOURCES += \
     runtime/JSString.cpp \
     runtime/JSValue.cpp \
     runtime/JSWrapperObject.cpp \
-    kjs/LabelStack.cpp \
     kjs/lexer.cpp \
     kjs/lookup.cpp \
     runtime/MathObject.cpp \
index 8c3f642..82f2039 100644 (file)
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath="..\..\kjs\LabelStack.cpp"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\kjs\LabelStack.h"\r
+                               RelativePath="..\..\kjs\LabelScope.h"\r
                                >\r
                        </File>\r
                        <File\r
index 78c772c..89525f1 100644 (file)
                95F6E6950E5B5F970091E860 /* JSProfilerPrivate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 95988BA90E477BEC00D28D4D /* JSProfilerPrivate.cpp */; };
                95FDFA140E22998F0006FB00 /* HeavyProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 95FDFA130E22998F0006FB00 /* HeavyProfile.cpp */; };
                95FDFA160E2299980006FB00 /* HeavyProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 95FDFA150E2299980006FB00 /* HeavyProfile.h */; };
+               960097A60EBABB58007A7297 /* LabelScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 960097A50EBABB58007A7297 /* LabelScope.h */; };
                A72700900DAC6BBC00E548D7 /* JSNotAnObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A72700780DAC605600E548D7 /* JSNotAnObject.cpp */; };
                A72701B60DADE94900E548D7 /* ExceptionHelpers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A72701B40DADE94900E548D7 /* ExceptionHelpers.cpp */; };
                A72701B90DADE94900E548D7 /* ExceptionHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = A72701B30DADE94900E548D7 /* ExceptionHelpers.h */; };
                BC18C42D0E16F5CD00B34460 /* JSVariableObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 14F252560D08DD8D004ECFFF /* JSVariableObject.h */; settings = {ATTRIBUTES = (Private, ); }; };
                BC18C42E0E16F5CD00B34460 /* JSWrapperObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 65C7A1720A8EAACB00FA37EA /* JSWrapperObject.h */; settings = {ATTRIBUTES = (Private, ); }; };
                BC18C42F0E16F5CD00B34460 /* LabelID.h in Headers */ = {isa = PBXBuildFile; fileRef = 149B20D70D8A0891009CB8C7 /* LabelID.h */; };
-               BC18C4300E16F5CD00B34460 /* LabelStack.h in Headers */ = {isa = PBXBuildFile; fileRef = 65B813A80CD1D01900DF59D6 /* LabelStack.h */; settings = {ATTRIBUTES = (Private, ); }; };
                BC18C4310E16F5CD00B34460 /* lexer.h in Headers */ = {isa = PBXBuildFile; fileRef = F692A8660255597D01FF60F7 /* lexer.h */; };
                BC18C4340E16F5CD00B34460 /* ListHashSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 657EB7450B708F540063461B /* ListHashSet.h */; settings = {ATTRIBUTES = (Private, ); }; };
                BC18C4350E16F5CD00B34460 /* ListRefPtr.h in Headers */ = {isa = PBXBuildFile; fileRef = 148A1626095D16BB00666D0D /* ListRefPtr.h */; settings = {ATTRIBUTES = (Private, ); }; };
                6592C316098B7DE10003D4F6 /* Vector.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Vector.h; sourceTree = "<group>"; };
                6592C317098B7DE10003D4F6 /* VectorTraits.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = VectorTraits.h; sourceTree = "<group>"; };
                65B174BE09D1000200820339 /* chartables.c */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.c; fileEncoding = 30; path = chartables.c; sourceTree = "<group>"; };
-               65B813A80CD1D01900DF59D6 /* LabelStack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LabelStack.h; sourceTree = "<group>"; };
                65C02FBB0637462A003E7EE6 /* protect.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = protect.h; sourceTree = "<group>"; tabWidth = 8; };
                65C647B3093EF8D60022C380 /* RefPtr.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = RefPtr.h; sourceTree = "<group>"; tabWidth = 8; };
                65C7A1710A8EAACB00FA37EA /* JSWrapperObject.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = JSWrapperObject.cpp; sourceTree = "<group>"; };
                95E3BC040E1AE68200B2D1C1 /* CallIdentifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CallIdentifier.h; path = profiler/CallIdentifier.h; sourceTree = "<group>"; };
                95FDFA130E22998F0006FB00 /* HeavyProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = HeavyProfile.cpp; path = profiler/HeavyProfile.cpp; sourceTree = "<group>"; };
                95FDFA150E2299980006FB00 /* HeavyProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HeavyProfile.h; path = profiler/HeavyProfile.h; sourceTree = "<group>"; };
+               960097A50EBABB58007A7297 /* LabelScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LabelScope.h; path = kjs/LabelScope.h; sourceTree = "<group>"; };
                A72700770DAC605600E548D7 /* JSNotAnObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSNotAnObject.h; sourceTree = "<group>"; };
                A72700780DAC605600E548D7 /* JSNotAnObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSNotAnObject.cpp; sourceTree = "<group>"; };
                A72701B30DADE94900E548D7 /* ExceptionHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExceptionHelpers.h; path = VM/ExceptionHelpers.h; sourceTree = "<group>"; };
                BC02E98A0E183E38000F9297 /* ErrorInstance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ErrorInstance.cpp; sourceTree = "<group>"; };
                BC02E98B0E183E38000F9297 /* ErrorInstance.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ErrorInstance.h; sourceTree = "<group>"; };
                BC02E9B60E1842FA000F9297 /* JSString.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSString.cpp; sourceTree = "<group>"; };
-               BC02E9B70E1844CF000F9297 /* LabelStack.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LabelStack.cpp; sourceTree = "<group>"; };
                BC02E9B80E184545000F9297 /* GetterSetter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GetterSetter.cpp; sourceTree = "<group>"; };
                BC02E9B90E184580000F9297 /* JSNumberCell.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSNumberCell.cpp; sourceTree = "<group>"; };
                BC1166000E1997B1008066DD /* DateInstance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DateInstance.cpp; sourceTree = "<group>"; };
                149B15DF0D81F887009CB8C7 /* compiler */ = {
                        isa = PBXGroup;
                        children = (
+                               960097A50EBABB58007A7297 /* LabelScope.h */,
                                149B15E90D81F986009CB8C7 /* CodeGenerator.cpp */,
                                149B15E80D81F986009CB8C7 /* CodeGenerator.h */,
                                149B20D70D8A0891009CB8C7 /* LabelID.h */,
                                A7E42C180E3938830065A544 /* JSStaticScopeObject.h */,
                                14ABB454099C2A0F00E2A24F /* JSType.h */,
                                93F1981A08245AAE001E9ABC /* keywords.table */,
-                               BC02E9B70E1844CF000F9297 /* LabelStack.cpp */,
-                               65B813A80CD1D01900DF59D6 /* LabelStack.h */,
                                F692A8680255597D01FF60F7 /* lookup.cpp */,
                                F692A8690255597D01FF60F7 /* lookup.h */,
                                F692A8770255597D01FF60F7 /* operations.cpp */,
                                BC18C42D0E16F5CD00B34460 /* JSVariableObject.h in Headers */,
                                BC18C42E0E16F5CD00B34460 /* JSWrapperObject.h in Headers */,
                                BC18C42F0E16F5CD00B34460 /* LabelID.h in Headers */,
-                               BC18C4300E16F5CD00B34460 /* LabelStack.h in Headers */,
                                BC18C4310E16F5CD00B34460 /* lexer.h in Headers */,
                                BC18C4340E16F5CD00B34460 /* ListHashSet.h in Headers */,
                                BC18C4350E16F5CD00B34460 /* ListRefPtr.h in Headers */,
                                869EBCB70E8C6D4A008722CC /* ResultType.h in Headers */,
                                14F3488F0E95EF8A003648BC /* CollectorHeapIterator.h in Headers */,
                                BC9041480EB9250900FE26FA /* StructureIDTransitionTable.h in Headers */,
+                               960097A60EBABB58007A7297 /* LabelScope.h in Headers */,
                                BC95437D0EBA70FD0072B6D3 /* PropertyMapHashTable.h in Headers */,
                                1C61516D0EBAC7A00031376F /* ProfilerServer.h in Headers */,
                                7E4EE7090EBB7963005934AA /* StructureIDChain.h in Headers */,
index 66fb77f..700d5a3 100644 (file)
@@ -61,7 +61,6 @@ Source files for JSCore.
         kjs/JSGlobalData.cpp
         kjs/JSLock.cpp
         kjs/JSStaticScopeObject.cpp
-        kjs/LabelStack.cpp
         kjs/lexer.cpp
         kjs/lookup.cpp
         kjs/nodes.cpp
index c78daa2..04fcc3a 100644 (file)
@@ -204,7 +204,6 @@ CodeGenerator::CodeGenerator(ProgramNode* programNode, const Debugger* debugger,
     , m_finallyDepth(0)
     , m_dynamicScopeDepth(0)
     , m_codeType(GlobalCode)
-    , m_continueDepth(0)
     , m_nextGlobal(-1)
     , m_globalData(&scopeChain.globalObject()->globalExec()->globalData())
     , m_lastOpcodeID(op_end)
@@ -282,7 +281,6 @@ CodeGenerator::CodeGenerator(FunctionBodyNode* functionBody, const Debugger* deb
     , m_finallyDepth(0)
     , m_dynamicScopeDepth(0)
     , m_codeType(FunctionCode)
-    , m_continueDepth(0)
     , m_globalData(&scopeChain.globalObject()->globalExec()->globalData())
     , m_lastOpcodeID(op_end)
 {
@@ -353,7 +351,6 @@ CodeGenerator::CodeGenerator(EvalNode* evalNode, const Debugger* debugger, const
     , m_finallyDepth(0)
     , m_dynamicScopeDepth(0)
     , m_codeType(EvalCode)
-    , m_continueDepth(0)
     , m_globalData(&scopeChain.globalObject()->globalExec()->globalData())
     , m_lastOpcodeID(op_end)
 {
@@ -451,6 +448,18 @@ RegisterID* CodeGenerator::highestUsedRegister()
     return &m_calleeRegisters.last();
 }
 
+PassRefPtr<LabelScope> CodeGenerator::newLabelScope(LabelScope::Type type, const Identifier* name)
+{
+    // Reclaim free label scopes.
+    while (m_labelScopes.size() && !m_labelScopes.last().refCount())
+        m_labelScopes.removeLast();
+
+    // Allocate new label scope.
+    LabelScope scope(type, name, scopeDepth(), newLabel(), type == LabelScope::Loop ? newLabel() : 0); // Only loops have continue targets.
+    m_labelScopes.append(scope);
+    return &m_labelScopes.last();
+}
+
 PassRefPtr<LabelID> CodeGenerator::newLabel()
 {
     // Reclaim free label IDs.
@@ -1356,62 +1365,70 @@ void CodeGenerator::popFinallyContext()
     m_finallyDepth--;
 }
 
-void CodeGenerator::pushJumpContext(LabelStack* labels, LabelID* continueTarget, LabelID* breakTarget, bool isValidUnlabeledBreakTarget)
+LabelScope* CodeGenerator::breakTarget(const Identifier& name)
 {
-    JumpContext context = { labels, continueTarget, breakTarget, scopeDepth(), isValidUnlabeledBreakTarget };
-    m_jumpContextStack.append(context);
-    if (continueTarget)
-        m_continueDepth++;
-}
-
-void CodeGenerator::popJumpContext()
-{
-    ASSERT(m_jumpContextStack.size());
-    if (m_jumpContextStack.last().continueTarget)
-        m_continueDepth--;
-    m_jumpContextStack.removeLast();
-}
+    // Reclaim free label scopes.
+    while (m_labelScopes.size() && !m_labelScopes.last().refCount())
+        m_labelScopes.removeLast();
 
-JumpContext* CodeGenerator::jumpContextForContinue(const Identifier& label)
-{
-    if(!m_jumpContextStack.size())
+    if (!m_labelScopes.size())
         return 0;
 
-    if (label.isEmpty()) {
-        for (int i = m_jumpContextStack.size() - 1; i >= 0; i--) {
-            JumpContext* scope = &m_jumpContextStack[i];
-            if (scope->continueTarget)
+    // We special-case the following, which is a syntax error in Firefox:
+    // label:
+    //     break;
+    if (name.isEmpty()) {
+        for (int i = m_labelScopes.size() - 1; i >= 0; --i) {
+            LabelScope* scope = &m_labelScopes[i];
+            if (scope->type() != LabelScope::NamedLabel) {
+                ASSERT(scope->breakTarget());
                 return scope;
+            }
         }
         return 0;
     }
 
-    for (int i = m_jumpContextStack.size() - 1; i >= 0; i--) {
-        JumpContext* scope = &m_jumpContextStack[i];
-        if (scope->labels->contains(label))
+    for (int i = m_labelScopes.size() - 1; i >= 0; --i) {
+        LabelScope* scope = &m_labelScopes[i];
+        if (scope->name() && *scope->name() == name) {
+            ASSERT(scope->breakTarget());
             return scope;
+        }
     }
     return 0;
 }
 
-JumpContext* CodeGenerator::jumpContextForBreak(const Identifier& label)
+LabelScope* CodeGenerator::continueTarget(const Identifier& name)
 {
-    if(!m_jumpContextStack.size())
+    // Reclaim free label scopes.
+    while (m_labelScopes.size() && !m_labelScopes.last().refCount())
+        m_labelScopes.removeLast();
+
+    if (!m_labelScopes.size())
         return 0;
 
-    if (label.isEmpty()) {
-        for (int i = m_jumpContextStack.size() - 1; i >= 0; i--) {
-            JumpContext* scope = &m_jumpContextStack[i];
-            if (scope->isValidUnlabeledBreakTarget)
+    if (name.isEmpty()) {
+        for (int i = m_labelScopes.size() - 1; i >= 0; --i) {
+            LabelScope* scope = &m_labelScopes[i];
+            if (scope->type() == LabelScope::Loop) {
+                ASSERT(scope->continueTarget());
                 return scope;
+            }
         }
         return 0;
     }
 
-    for (int i = m_jumpContextStack.size() - 1; i >= 0; i--) {
-        JumpContext* scope = &m_jumpContextStack[i];
-        if (scope->labels->contains(label))
-            return scope;
+    // Continue to the loop nested nearest to the label scope that matches
+    // 'name'.
+    LabelScope* result = 0;
+    for (int i = m_labelScopes.size() - 1; i >= 0; --i) {
+        LabelScope* scope = &m_labelScopes[i];
+        if (scope->type() == LabelScope::Loop) {
+            ASSERT(scope->continueTarget());
+            result = scope;
+        }
+        if (scope->name() && *scope->name() == name)
+            return result; // may be 0
     }
     return 0;
 }
index 14d139c..75fc0a5 100644 (file)
@@ -34,6 +34,7 @@
 #include "HashTraits.h"
 #include "Instruction.h"
 #include "LabelID.h"
+#include "LabelScope.h"
 #include "Machine.h"
 #include "RegisterID.h"
 #include "SegmentedVector.h"
@@ -49,15 +50,6 @@ namespace JSC {
     class ScopeChain;
     class ScopeNode;
 
-    // JumpContexts are used to track entry and exit points for javascript loops and switch statements
-    struct JumpContext {
-        LabelStack* labels;
-        LabelID* continueTarget;
-        LabelID* breakTarget;
-        int scopeDepth;
-        bool isValidUnlabeledBreakTarget;
-    };
-
     struct FinallyContext {
         LabelID* finallyAddr;
         RegisterID* retAddrDst;
@@ -157,6 +149,7 @@ namespace JSC {
             return dst == ignoredResult() ? 0 : (dst && dst != src) ? emitMove(dst, src) : src;
         }
 
+        PassRefPtr<LabelScope> newLabelScope(LabelScope::Type, const Identifier* = 0);
         PassRefPtr<LabelID> newLabel();
 
         // The emitNode functions are just syntactic sugar for calling
@@ -309,12 +302,9 @@ namespace JSC {
 
         void pushFinallyContext(LabelID* target, RegisterID* returnAddrDst);
         void popFinallyContext();
-        bool inContinueContext() { return m_continueDepth > 0; };
-        bool inJumpContext() { return m_jumpContextStack.size() > 0; };
-        void pushJumpContext(LabelStack*, LabelID* continueTarget, LabelID* breakTarget, bool isValidUnlabeledBreakTarget);
-        void popJumpContext();
-        JumpContext* jumpContextForContinue(const Identifier&);
-        JumpContext* jumpContextForBreak(const Identifier&);
+
+        LabelScope* breakTarget(const Identifier&);
+        LabelScope* continueTarget(const Identifier&);
 
         void beginSwitch(RegisterID*, SwitchInfo::SwitchType);
         void endSwitch(uint32_t clauseCount, RefPtr<LabelID>*, ExpressionNode**, LabelID* defaultLabel, int32_t min, int32_t range);
@@ -425,14 +415,13 @@ namespace JSC {
         SegmentedVector<RegisterID, 512> m_calleeRegisters;
         SegmentedVector<RegisterID, 512> m_parameters;
         SegmentedVector<RegisterID, 512> m_globals;
-        SegmentedVector<LabelID, 512> m_labels;
+        SegmentedVector<LabelScope, 256> m_labelScopes;
+        SegmentedVector<LabelID, 256> m_labels;
         RefPtr<RegisterID> m_lastConstant;
         int m_finallyDepth;
         int m_dynamicScopeDepth;
         CodeType m_codeType;
 
-        Vector<JumpContext> m_jumpContextStack;
-        int m_continueDepth;
         Vector<ControlFlowContext> m_scopeContextStack;
         Vector<SwitchInfo> m_switchContextStack;
 
index e19e114..34cad1c 100644 (file)
@@ -61,7 +61,6 @@
 #include "runtime/JSString.cpp"
 #include "runtime/JSNumberCell.cpp"
 #include "GetterSetter.cpp"
-#include "LabelStack.cpp"
 #include "runtime/InternalFunction.cpp"
 #include "interpreter.cpp"
 #include "runtime/JSImmediate.cpp"
diff --git a/JavaScriptCore/kjs/LabelScope.h b/JavaScriptCore/kjs/LabelScope.h
new file mode 100644 (file)
index 0000000..8c30be5
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LabelScope_h
+#define LabelScope_h
+
+#include <wtf/PassRefPtr.h>
+#include "LabelID.h"
+
+namespace JSC {
+
+    class Identifier;
+
+    class LabelScope {
+    public:
+        enum Type { Loop, Switch, NamedLabel };
+
+        LabelScope(Type type, const Identifier* name, int scopeDepth, PassRefPtr<LabelID> breakTarget, PassRefPtr<LabelID> continueTarget)
+            : m_refCount(0)
+            , m_type(type)
+            , m_name(name)
+            , m_scopeDepth(scopeDepth)
+            , m_breakTarget(breakTarget)
+            , m_continueTarget(continueTarget)
+        {
+        }
+
+        // It doesn't really make sense to copy a LabelScope, but we need this copy
+        // constructor to support moving LabelScopes in a Vector.
+
+        LabelScope(const LabelScope& other)
+            : m_refCount(other.m_refCount)
+            , m_type(other.m_type)
+            , m_name(other.m_name)
+            , m_scopeDepth(other.m_scopeDepth)
+            , m_breakTarget(other.m_breakTarget)
+            , m_continueTarget(other.m_continueTarget)
+        {
+        }
+
+        void ref() { ++m_refCount; }
+        void deref()
+        {
+            --m_refCount;
+            ASSERT(m_refCount >= 0);
+        }
+        int refCount() const { return m_refCount; }
+
+        LabelID* breakTarget() const { return m_breakTarget.get(); }
+        LabelID* continueTarget() const { return m_continueTarget.get(); }
+
+        Type type() const { return m_type; }
+        const Identifier* name() const { return m_name; }
+        int scopeDepth() const { return m_scopeDepth; }
+
+    private:
+        int m_refCount;
+        Type m_type;
+        const Identifier* m_name;
+        int m_scopeDepth;
+        RefPtr<LabelID> m_breakTarget;
+        RefPtr<LabelID> m_continueTarget;
+    };
+
+} // namespace JSC
+
+#endif // LabelScope_h
diff --git a/JavaScriptCore/kjs/LabelStack.cpp b/JavaScriptCore/kjs/LabelStack.cpp
deleted file mode 100644 (file)
index e3fd775..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- *  Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
- *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
- *  Copyright (C) 2004, 2007, 2008 Apple Inc. All rights reserved.
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Library General Public
- *  License as published by the Free Software Foundation; either
- *  version 2 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Library General Public License for more details.
- *
- *  You should have received a copy of the GNU Library General Public License
- *  along with this library; see the file COPYING.LIB.  If not, write to
- *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- *  Boston, MA 02110-1301, USA.
- *
- */
-
-#include "config.h"
-#include "LabelStack.h"
-
-namespace JSC {
-
-bool LabelStack::push(const Identifier& id)
-{
-    if (contains(id))
-        return false;
-
-    StackElem* newTopOfStack = new StackElem;
-    newTopOfStack->id = id;
-    newTopOfStack->prev = m_topOfStack;
-    m_topOfStack = newTopOfStack;
-    return true;
-}
-
-bool LabelStack::contains(const Identifier &id) const
-{
-    if (id.isEmpty())
-        return true;
-
-    for (StackElem* curr = m_topOfStack; curr; curr = curr->prev) {
-        if (curr->id == id)
-            return true;
-    }
-
-    return false;
-}
-
-} // namespace JSC
diff --git a/JavaScriptCore/kjs/LabelStack.h b/JavaScriptCore/kjs/LabelStack.h
deleted file mode 100644 (file)
index 00f293f..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
- *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
- *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Library General Public
- *  License as published by the Free Software Foundation; either
- *  version 2 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Library General Public License for more details.
- *
- *  You should have received a copy of the GNU Library General Public License
- *  along with this library; see the file COPYING.LIB.  If not, write to
- *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- *  Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef LabelStack_h
-#define LabelStack_h
-
-#include "identifier.h"
-#include <wtf/Noncopyable.h>
-
-namespace JSC {
-
-    class LabelStack : Noncopyable {
-    public:
-        LabelStack()
-            : m_topOfStack(0)
-        {
-        }
-        ~LabelStack();
-
-        bool push(const Identifier &id);
-        bool contains(const Identifier &id) const;
-        void pop();
-
-    private:
-        struct StackElem {
-            Identifier id;
-            StackElem* prev;
-        };
-
-        StackElem* m_topOfStack;
-    };
-
-    inline LabelStack::~LabelStack()
-    {
-        StackElem* prev;
-        for (StackElem* e = m_topOfStack; e; e = prev) {
-            prev = e->prev;
-            delete e;
-        }
-    }
-
-    inline void LabelStack::pop()
-    {
-        if (StackElem* e = m_topOfStack) {
-            m_topOfStack = e->prev;
-            delete e;
-        }
-    }
-
-} // namespace JSC
-
-#endif // LabelStack_h
index dfd0ac7..b40dfb6 100644 (file)
@@ -1118,8 +1118,7 @@ DefaultClause:
 ;
 
 LabelledStatement:
-    IDENT ':' Statement                 { $3.m_node->pushLabel(*$1);
-                                          LabelNode* node = new LabelNode(GLOBAL_DATA, *$1, $3.m_node);
+    IDENT ':' Statement                 { LabelNode* node = new LabelNode(GLOBAL_DATA, *$1, $3.m_node);
                                           SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column);
                                           $$ = createNodeDeclarationInfo<StatementNode*>(node, $3.m_varDeclarations, $3.m_funcDeclarations, $3.m_features, $3.m_numConstants); }
 ;
index b68b453..4439e03 100644 (file)
@@ -30,6 +30,7 @@
 #include "ExecState.h"
 #include "JSGlobalObject.h"
 #include "JSStaticScopeObject.h"
+#include "LabelScope.h"
 #include "Parser.h"
 #include "PropertyNameArray.h"
 #include "RegExpObject.h"
@@ -1174,6 +1175,8 @@ RegisterID* IfElseNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 
 RegisterID* DoWhileNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 {
+    RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop);
+
     RefPtr<LabelID> topOfLoop = generator.newLabel();
     generator.emitLabel(topOfLoop.get());
 
@@ -1181,20 +1184,15 @@ RegisterID* DoWhileNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 
     if (!m_statement->isBlock())
         generator.emitDebugHook(WillExecuteStatement, m_statement->firstLine(), m_statement->lastLine());
-
-    RefPtr<LabelID> continueTarget = generator.newLabel();
-    RefPtr<LabelID> breakTarget = generator.newLabel();
-
-    generator.pushJumpContext(&m_labelStack, continueTarget.get(), breakTarget.get(), true);
+        
     RefPtr<RegisterID> result = generator.emitNode(dst, m_statement.get());
-    generator.popJumpContext();
 
-    generator.emitLabel(continueTarget.get());
+    generator.emitLabel(scope->continueTarget());
     generator.emitDebugHook(WillExecuteStatement, m_expr->lineNo(), m_expr->lineNo());
     RegisterID* cond = generator.emitNode(m_expr.get());
     generator.emitJumpIfTrue(cond, topOfLoop.get());
 
-    generator.emitLabel(breakTarget.get());
+    generator.emitLabel(scope->breakTarget());
     return result.get();
 }
 
@@ -1202,26 +1200,24 @@ RegisterID* DoWhileNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 
 RegisterID* WhileNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 {
-    RefPtr<LabelID> topOfLoop = generator.newLabel();
-    RefPtr<LabelID> continueTarget = generator.newLabel();
-    RefPtr<LabelID> breakTarget = generator.newLabel();
+    RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop);
 
-    generator.emitJump(continueTarget.get());
+    generator.emitJump(scope->continueTarget());
+
+    RefPtr<LabelID> topOfLoop = generator.newLabel();
     generator.emitLabel(topOfLoop.get());
 
     if (!m_statement->isBlock())
         generator.emitDebugHook(WillExecuteStatement, m_statement->firstLine(), m_statement->lastLine());
  
-    generator.pushJumpContext(&m_labelStack, continueTarget.get(), breakTarget.get(), true);
     generator.emitNode(dst, m_statement.get());
-    generator.popJumpContext();
 
-    generator.emitLabel(continueTarget.get());
+    generator.emitLabel(scope->continueTarget());
     generator.emitDebugHook(WillExecuteStatement, m_expr->lineNo(), m_expr->lineNo());
     RegisterID* cond = generator.emitNode(m_expr.get());
     generator.emitJumpIfTrue(cond, topOfLoop.get());
 
-    generator.emitLabel(breakTarget.get());
+    generator.emitLabel(scope->breakTarget());
     
     // FIXME: This should return the last statement executed so that it can be returned as a Completion
     return 0;
@@ -1234,37 +1230,35 @@ RegisterID* ForNode::emitCode(CodeGenerator& generator, RegisterID* dst)
     if (dst == ignoredResult())
         dst = 0;
 
+    RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop);
+
     generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine());
 
     if (m_expr1)
         generator.emitNode(ignoredResult(), m_expr1.get());
 
-    RefPtr<LabelID> topOfLoop = generator.newLabel();
-    RefPtr<LabelID> beforeCondition = generator.newLabel();
-    RefPtr<LabelID> continueTarget = generator.newLabel(); 
-    RefPtr<LabelID> breakTarget = generator.newLabel(); 
-    generator.emitJump(beforeCondition.get());
+    RefPtr<LabelID> condition = generator.newLabel();
+    generator.emitJump(condition.get());
 
+    RefPtr<LabelID> topOfLoop = generator.newLabel();
     generator.emitLabel(topOfLoop.get());
-    generator.pushJumpContext(&m_labelStack, continueTarget.get(), breakTarget.get(), true);
+
     if (!m_statement->isBlock())
         generator.emitDebugHook(WillExecuteStatement, m_statement->firstLine(), m_statement->lastLine());
     RefPtr<RegisterID> result = generator.emitNode(dst, m_statement.get());
-    generator.popJumpContext();
-    generator.emitLabel(continueTarget.get());
+
+    generator.emitLabel(scope->continueTarget());
     if (m_expr3)
         generator.emitNode(ignoredResult(), m_expr3.get());
 
-    generator.emitLabel(beforeCondition.get());
+    generator.emitLabel(condition.get());
     if (m_expr2) {
         RegisterID* cond = generator.emitNode(m_expr2.get());
         generator.emitJumpIfTrue(cond, topOfLoop.get());
-    } else {
+    } else
         generator.emitJump(topOfLoop.get());
-    }
 
-    generator.emitLabel(breakTarget.get());
-    
+    generator.emitLabel(scope->breakTarget());
     return result.get();
 }
 
@@ -1298,11 +1292,12 @@ ForInNode::ForInNode(JSGlobalData* globalData, const Identifier& ident, Expressi
 
 RegisterID* ForInNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 {
+    RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop);
+
     if (!m_lexpr->isLocation())
         return emitThrowError(generator, ReferenceError, "Left side of for-in statement is not a reference.");
-    RefPtr<LabelID> loopStart = generator.newLabel();
+
     RefPtr<LabelID> continueTarget = generator.newLabel(); 
-    RefPtr<LabelID> breakTarget = generator.newLabel(); 
 
     generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine());
 
@@ -1310,8 +1305,11 @@ RegisterID* ForInNode::emitCode(CodeGenerator& generator, RegisterID* dst)
         generator.emitNode(ignoredResult(), m_init.get());
     RegisterID* forInBase = generator.emitNode(m_expr.get());
     RefPtr<RegisterID> iter = generator.emitGetPropertyNames(generator.newTemporary(), forInBase);
-    generator.emitJump(continueTarget.get());
+    generator.emitJump(scope->continueTarget());
+
+    RefPtr<LabelID> loopStart = generator.newLabel();
     generator.emitLabel(loopStart.get());
+
     RegisterID* propertyName;
     if (m_lexpr->isResolveNode()) {
         const Identifier& ident = static_cast<ResolveNode*>(m_lexpr.get())->identifier();
@@ -1345,15 +1343,13 @@ RegisterID* ForInNode::emitCode(CodeGenerator& generator, RegisterID* dst)
         generator.emitPutByVal(base.get(), subscript, propertyName);
     }   
 
-    generator.pushJumpContext(&m_labelStack, continueTarget.get(), breakTarget.get(), true);
     if (!m_statement->isBlock())
         generator.emitDebugHook(WillExecuteStatement, m_statement->firstLine(), m_statement->lastLine());
     generator.emitNode(dst, m_statement.get());
-    generator.popJumpContext();
 
-    generator.emitLabel(continueTarget.get());
+    generator.emitLabel(scope->continueTarget());
     generator.emitNextPropertyName(propertyName, iter.get(), loopStart.get());
-    generator.emitLabel(breakTarget.get());
+    generator.emitLabel(scope->breakTarget());
     return dst;
 }
 
@@ -1362,23 +1358,14 @@ RegisterID* ForInNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 // ECMA 12.7
 RegisterID* ContinueNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 {
-    if (!generator.inContinueContext())
-        return emitThrowError(generator, SyntaxError, "Invalid continue statement.");
+    LabelScope* scope = generator.continueTarget(m_ident);
 
-    JumpContext* targetContext = generator.jumpContextForContinue(m_ident);
+    if (!scope)
+        return m_ident.isEmpty()
+            ? emitThrowError(generator, SyntaxError, "Invalid continue statement.")
+            : emitThrowError(generator, SyntaxError, "Undefined label: '%s'.", m_ident);
 
-    if (!targetContext) {
-        if (m_ident.isEmpty())
-            return emitThrowError(generator, SyntaxError, "Invalid continue statement.");
-        else
-            return emitThrowError(generator, SyntaxError, "Label %s not found.", m_ident);
-    }
-
-    if (!targetContext->continueTarget)
-        return emitThrowError(generator, SyntaxError, "Invalid continue statement.");        
-
-    generator.emitJumpScopes(targetContext->continueTarget, targetContext->scopeDepth);
-    
+    generator.emitJumpScopes(scope->continueTarget(), scope->scopeDepth());
     return dst;
 }
 
@@ -1387,22 +1374,14 @@ RegisterID* ContinueNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 // ECMA 12.8
 RegisterID* BreakNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 {
-    if (!generator.inJumpContext())
-        return emitThrowError(generator, SyntaxError, "Invalid break statement.");
-    
-    JumpContext* targetContext = generator.jumpContextForBreak(m_ident);
+    LabelScope* scope = generator.breakTarget(m_ident);
     
-    if (!targetContext) {
-        if (m_ident.isEmpty())
-            return emitThrowError(generator, SyntaxError, "Invalid break statement.");
-        else
-            return emitThrowError(generator, SyntaxError, "Label %s not found.", m_ident);
-    }
-
-    ASSERT(targetContext->breakTarget);
-
-    generator.emitJumpScopes(targetContext->breakTarget, targetContext->scopeDepth);
+    if (!scope)
+        return m_ident.isEmpty()
+            ? emitThrowError(generator, SyntaxError, "Invalid break statement.")
+            : emitThrowError(generator, SyntaxError, "Undefined label: '%s'.", m_ident);
 
+    generator.emitJumpScopes(scope->breakTarget(), scope->scopeDepth());
     return dst;
 }
 
@@ -1583,15 +1562,12 @@ RegisterID* CaseBlockNode::emitCodeForBlock(CodeGenerator& generator, RegisterID
 
 RegisterID* SwitchNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 {
-    RefPtr<LabelID> breakTarget = generator.newLabel();
+    RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Switch);
 
     RefPtr<RegisterID> r0 = generator.emitNode(m_expr.get());
-    generator.pushJumpContext(&m_labelStack, 0, breakTarget.get(), true);
     RegisterID* r1 = m_block->emitCodeForBlock(generator, r0.get(), dst);
-    generator.popJumpContext();
-
-    generator.emitLabel(breakTarget.get());
 
+    generator.emitLabel(scope->breakTarget());
     return r1;
 }
 
@@ -1599,19 +1575,13 @@ RegisterID* SwitchNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 
 RegisterID* LabelNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 {
-    if (generator.jumpContextForBreak(m_label))
-        return emitThrowError(generator, SyntaxError, "Duplicated label %s found.", m_label);
+    if (generator.breakTarget(m_name))
+        return emitThrowError(generator, SyntaxError, "Duplicate label: %s.", m_name);
 
-    RefPtr<LabelID> l0 = generator.newLabel();
-    m_labelStack.push(m_label);
-    generator.pushJumpContext(&m_labelStack, 0, l0.get(), false);
-    
+    RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::NamedLabel, &m_name);
     RegisterID* r0 = generator.emitNode(dst, m_statement.get());
-    
-    generator.popJumpContext();
-    m_labelStack.pop();
-    
-    generator.emitLabel(l0.get());
+
+    generator.emitLabel(scope->breakTarget());
     return r0;
 }
 
index 03e4e54..7d88136 100644 (file)
@@ -29,7 +29,6 @@
 #include "Error.h"
 #include "JSString.h"
 #include "JSType.h"
-#include "LabelStack.h"
 #include "Opcode.h"
 #include "RegisterID.h"
 #include "ResultType.h"
@@ -231,14 +230,11 @@ namespace JSC {
         int firstLine() const JSC_FAST_CALL { return lineNo(); }
         int lastLine() const JSC_FAST_CALL { return m_lastLine; }
 
-        virtual void pushLabel(const Identifier& ident) JSC_FAST_CALL { m_labelStack.push(ident); }
         virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
         virtual bool isEmptyStatement() const JSC_FAST_CALL { return false; }
 
         virtual bool isBlock() const JSC_FAST_CALL { return false; }
         virtual bool isLoop() const JSC_FAST_CALL { return false; }
-    protected:
-        LabelStack m_labelStack;
 
     private:
         int m_lastLine;
@@ -2087,19 +2083,18 @@ namespace JSC {
 
     class LabelNode : public StatementNode, public ThrowableExpressionData {
     public:
-        LabelNode(JSGlobalData* globalData, const Identifier& label, StatementNode* statement) JSC_FAST_CALL
+        LabelNode(JSGlobalData* globalData, const Identifier& name, StatementNode* statement) JSC_FAST_CALL
             : StatementNode(globalData)
-            , m_label(label)
+            , m_name(name)
             , m_statement(statement)
         {
         }
 
         virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
         virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
-        virtual void pushLabel(const Identifier& ident) JSC_FAST_CALL { m_statement->pushLabel(ident); }
 
     private:
-        Identifier m_label;
+        Identifier m_name;
         RefPtr<StatementNode> m_statement;
     };
 
index d7ae4fc..4afefe0 100644 (file)
@@ -899,7 +899,7 @@ void SwitchNode::streamTo(SourceStream& s) const
 
 void LabelNode::streamTo(SourceStream& s) const
 {
-    s << Endl << m_label << ":" << Indent << m_statement << Unindent;
+    s << Endl << m_name << ":" << Indent << m_statement << Unindent;
 }
 
 void ThrowNode::streamTo(SourceStream& s) const