flex-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cd...@apache.org
Subject [17/51] [partial] - Migrated the directory structure to a more Maven style structure. - Started migrating the Parser from Antlr2+3 and JFlex to Antlr4.
Date Tue, 22 Jul 2014 13:35:43 GMT
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/59f6373b/compiler/src/main/java/org/apache/flex/compiler/internal/as/codegen/ABCGeneratingReducer.java
----------------------------------------------------------------------
diff --git a/compiler/src/main/java/org/apache/flex/compiler/internal/as/codegen/ABCGeneratingReducer.java b/compiler/src/main/java/org/apache/flex/compiler/internal/as/codegen/ABCGeneratingReducer.java
new file mode 100644
index 0000000..776993f
--- /dev/null
+++ b/compiler/src/main/java/org/apache/flex/compiler/internal/as/codegen/ABCGeneratingReducer.java
@@ -0,0 +1,7137 @@
+/*
+ *
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.flex.compiler.internal.as.codegen;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Vector;
+import java.util.Stack;
+
+import static org.apache.flex.abc.ABCConstants.*;
+
+import org.apache.flex.abc.ABCConstants;
+import org.apache.flex.abc.instructionlist.InstructionList;
+import org.apache.flex.abc.semantics.ECMASupport;
+import org.apache.flex.abc.semantics.Instruction;
+import org.apache.flex.abc.semantics.InstructionFactory;
+import org.apache.flex.abc.semantics.Label;
+import org.apache.flex.abc.semantics.MethodInfo;
+import org.apache.flex.abc.semantics.Name;
+import org.apache.flex.abc.semantics.Namespace;
+import org.apache.flex.abc.semantics.NoOperandsInstruction;
+import org.apache.flex.abc.semantics.Nsset;
+import org.apache.flex.abc.semantics.PooledValue;
+import org.apache.flex.compiler.constants.IASLanguageConstants;
+import org.apache.flex.compiler.constants.IASLanguageConstants.BuiltinType;
+import org.apache.flex.compiler.definitions.IAccessorDefinition;
+import org.apache.flex.compiler.definitions.IConstantDefinition;
+import org.apache.flex.compiler.definitions.IDefinition;
+import org.apache.flex.compiler.definitions.ITypeDefinition;
+import org.apache.flex.compiler.definitions.IVariableDefinition;
+import org.apache.flex.compiler.exceptions.CodegenInterruptedException;
+import org.apache.flex.compiler.exceptions.DuplicateLabelException;
+import org.apache.flex.compiler.exceptions.UnknownControlFlowTargetException;
+import org.apache.flex.compiler.internal.semantics.SemanticUtils;
+import org.apache.flex.compiler.internal.tree.as.BaseVariableNode;
+import org.apache.flex.compiler.internal.tree.as.VariableExpressionNode;
+import org.apache.flex.compiler.problems.AmbiguousGotoTargetProblem;
+import org.apache.flex.compiler.problems.AnyNamespaceCannotBeQualifierProblem;
+import org.apache.flex.compiler.problems.CodegenInternalProblem;
+import org.apache.flex.compiler.problems.DuplicateLabelProblem;
+import org.apache.flex.compiler.problems.DuplicateNamespaceDefinitionProblem;
+import org.apache.flex.compiler.problems.ICompilerProblem;
+import org.apache.flex.compiler.problems.InvalidLvalueProblem;
+import org.apache.flex.compiler.problems.InvalidNamespaceInitializerProblem;
+import org.apache.flex.compiler.problems.MultipleSwitchDefaultsProblem;
+import org.apache.flex.compiler.problems.NonConstantParamInitializerProblem;
+import org.apache.flex.compiler.problems.PackageCannotBeUsedAsValueProblem;
+import org.apache.flex.compiler.problems.UnexpectedReturnProblem;
+import org.apache.flex.compiler.problems.UnknownGotoTargetProblem;
+import org.apache.flex.compiler.problems.UnknownNamespaceProblem;
+import org.apache.flex.compiler.problems.UnknownBreakTargetProblem;
+import org.apache.flex.compiler.problems.UnknownContinueTargetProblem;
+import org.apache.flex.compiler.problems.VoidTypeProblem;
+import org.apache.flex.compiler.projects.ICompilerProject;
+import org.apache.flex.compiler.tree.as.IASNode;
+import org.apache.flex.compiler.tree.as.IDynamicAccessNode;
+import org.apache.flex.compiler.tree.as.IBinaryOperatorNode;
+import org.apache.flex.compiler.tree.as.ICatchNode;
+import org.apache.flex.compiler.tree.as.IContainerNode;
+import org.apache.flex.compiler.tree.as.IExpressionNode;
+import org.apache.flex.compiler.tree.as.IForLoopNode;
+import org.apache.flex.compiler.tree.as.IFunctionCallNode;
+import org.apache.flex.compiler.tree.as.IFunctionNode;
+import org.apache.flex.compiler.tree.as.IIdentifierNode;
+import org.apache.flex.compiler.tree.as.IImportNode;
+import org.apache.flex.compiler.tree.as.ILanguageIdentifierNode;
+import org.apache.flex.compiler.tree.as.IParameterNode;
+import org.apache.flex.compiler.tree.as.IScopedNode;
+import org.apache.flex.compiler.tree.as.ITryNode;
+import org.apache.flex.compiler.tree.as.ITypedExpressionNode;
+import org.apache.flex.compiler.tree.as.IUnaryOperatorNode;
+import org.apache.flex.compiler.tree.as.IWhileLoopNode;
+import org.apache.flex.compiler.tree.as.IWithNode;
+import org.apache.flex.compiler.tree.as.ILanguageIdentifierNode.LanguageIdentifierKind;
+import org.apache.flex.compiler.tree.as.IOperatorNode.OperatorType;
+import org.apache.flex.compiler.tree.mxml.IMXMLEventSpecifierNode;
+import org.apache.flex.compiler.internal.as.codegen.LexicalScope.NestingState;
+import org.apache.flex.compiler.internal.definitions.AccessorDefinition;
+import org.apache.flex.compiler.internal.definitions.ClassDefinition;
+import org.apache.flex.compiler.internal.definitions.DefinitionBase;
+import org.apache.flex.compiler.internal.definitions.FunctionDefinition;
+import org.apache.flex.compiler.internal.definitions.GetterDefinition;
+import org.apache.flex.compiler.internal.definitions.NamespaceDefinition;
+import org.apache.flex.compiler.internal.definitions.SetterDefinition;
+import org.apache.flex.compiler.internal.definitions.TypeDefinitionBase;
+import org.apache.flex.compiler.internal.tree.as.BaseDefinitionNode;
+import org.apache.flex.compiler.internal.tree.as.BinaryOperatorInNode;
+import org.apache.flex.compiler.internal.tree.as.DynamicAccessNode;
+import org.apache.flex.compiler.internal.tree.as.EmbedNode;
+import org.apache.flex.compiler.internal.tree.as.ExpressionNodeBase;
+import org.apache.flex.compiler.internal.tree.as.ForLoopNode;
+import org.apache.flex.compiler.internal.tree.as.FunctionNode;
+import org.apache.flex.compiler.internal.tree.as.FunctionObjectNode;
+import org.apache.flex.compiler.internal.tree.as.IdentifierNode;
+import org.apache.flex.compiler.internal.tree.as.LabeledStatementNode;
+import org.apache.flex.compiler.internal.tree.as.MemberAccessExpressionNode;
+import org.apache.flex.compiler.internal.tree.as.NamespaceNode;
+import org.apache.flex.compiler.internal.tree.as.RegExpLiteralNode;
+import org.apache.flex.compiler.internal.tree.as.SwitchNode;
+import org.apache.flex.compiler.internal.tree.as.TernaryOperatorNode;
+import org.apache.flex.compiler.internal.tree.as.VariableNode;
+
+/*
+ * Notes on changing the reducer:
+ * 
+ * - Do not add OP_finddefinition, OP_finddefstrict or OP_getlex instructions directly.  Instead use
+ *   LexicalScope.findProperty() and LexicalScope.getPropertyValue(), as these methods will
+ *   ensure the correct instructions are added when inlining a function body where the scope
+ *   chain can not be depended on.
+ */
+public class ABCGeneratingReducer
+{
+    /**
+     *  A struct for the decoded pieces of a catch block.
+     */
+    public static class CatchPrototype
+    {
+        Name catchType;
+        Name catchVarName;
+        InstructionList catchBody;
+    }
+
+    /**
+     *  ConditionalFragment holds the disparate elements of a conditional statement fragment.
+     */
+    public class ConditionalFragment
+    {
+        IASNode site;
+        /**
+         * condition is non-null when the conditional expression is not a constant.
+         * condition is null if an unconditional fragement, or if the fragement is
+         * a constant, in which case constantCondition is non-null.
+         */
+        InstructionList condition;
+        /**
+         * constantCondition is non-null when the conditional expression is a constant.
+         * constantCondition is null if an unconditional fragement, or if the fragement is
+         * a non-constant, in which case condition is non-null.
+         */
+        Object constantCondition;
+        InstructionList statement;
+
+        private Label statementLabel = null;
+
+        /**
+         *  Construct a ConditionalFragment with a single statement.
+         */
+        ConditionalFragment( IASNode site, InstructionList condition, InstructionList statement)
+        {
+            this.site = site;
+            this.condition = condition;
+            this.constantCondition = null;
+            this.statement = statement;
+        }
+
+        /**
+         *  Construct a ConditionalFragment with a list of statements,
+         *  coalescing them into a composite statement.
+         */
+        ConditionalFragment( IASNode site, InstructionList condition, Vector<InstructionList> statements)
+        {
+            this(site, condition, null, statements);
+        }
+
+        /**
+         * Construct a constant conditional ConditionalFragment with a list of
+         * statements, coalescing them into a composite statement.
+         */
+        ConditionalFragment(IASNode site, Object constantConditional, Vector<InstructionList> statements)
+        {
+            this(site, null, constantConditional, statements);
+        }
+
+        /**
+         * Private constructor called by public constructors
+         * @param site
+         * @param condition
+         * @param constantCondition
+         * @param statements
+         */
+        private ConditionalFragment(IASNode site, InstructionList condition, Object constantCondition, Vector<InstructionList> statements)
+        {
+            assert (condition == null || constantCondition == null) : "condition and constantCondition can't both be non-null";
+            this.site = site;
+            this.condition = condition;
+            this.constantCondition = constantCondition;
+            this.statement = createInstructionList(site);
+
+            for (InstructionList stmt : statements)
+            {
+                this.statement.addAll(stmt);
+            }
+        }
+
+        /**
+         *  @return the label of the fragment's condition, or
+         *    its statement label if it's the default alternative.
+         */
+        Label getLabel()
+        {
+            if ( !this.isUnconditionalAlternative() )
+            {
+                if ( this.condition != null )
+                    return this.condition.getLabel();
+                else
+                    return getStatementLabel();
+            }
+            else
+            {
+                return getStatementLabel();
+            }
+        }
+
+        /**
+         *  Cache and return the label of this conditional fragment's
+         *  statement so it can be retrieved after the statement's been
+         *  added to the overall conditional statement and this.statement
+         *  is invalidated.
+         */
+        Label getStatementLabel()
+        {
+            if ( null == this.statementLabel )
+                this.statementLabel = this.statement.getLabel();
+
+            return this.statementLabel;
+        }
+
+        /**
+         *  @return true if this is an unconditional alternative,
+         *    i.e. a default case or the last else in an if/else if/else.
+         */
+        boolean isUnconditionalAlternative()
+        {
+            return (null == this.condition) && (null == this.constantCondition);
+        }
+
+        void convertConstantConditionToInstruction()
+        {
+            if ((constantCondition == null && condition != null)  || condition == null)
+                return;
+
+            condition = transform_constant_value(site, constantCondition);
+            constantCondition = null;
+        }
+
+        /**
+         * @return true if this is a constant conditonal fragement i.e. case 7:
+         */
+        boolean isConstantConditional()
+        {
+            return this.constantCondition != null;
+        }
+    }
+
+    /**
+     *  The RuntimeMultiname class holds the components of 
+     *  the various types of runtime multiname, and puts them
+     *  together in the right order to generate the names and
+     *  instruction sequences to jamble up the AVM.
+     *
+     *  Only some permutations of the compile-time/runtime
+     *  qualifier::name possibilities are valid:
+     *  Name::expression generates MultinameL
+     *  expression::expression generates RTQnameL
+     *  expression::name generates RTQname
+     *  (name::name is a plain Multiname)
+     */
+    class RuntimeMultiname
+    {
+        /**
+         *  The compile-time qualifier of a MultinameL.
+         *  compileTimeName isn't valid (this would
+         *  be a compile-time constant Multiname).
+         */
+        Name compileTimeQualifier;
+
+        /**
+         *  The runtime qualifier of a RTQname or RTQNameL.
+         *  Compile-time and runtime names are valid.
+         */
+        InstructionList runtimeQualifier;
+
+        /**
+         *  The compile-time constant name of a RTQName.
+         *  compileTimeQualifier isn't valid (this would
+         *  be a compile-time constant Multiname).
+         */
+        Name compileTimeName;
+
+        /**
+         *  The runtime name of a MultinameL or RTQnameL.
+         */
+        InstructionList runtimeName;
+
+        /**
+         *  Construct a RTQnameL-type runtime name.
+         *  @param qualifier - the runtime qualifier.
+         *  @param name - the runtime name.
+         */
+        RuntimeMultiname(InstructionList qualifier, InstructionList runtime_name)
+        {
+            this.runtimeQualifier = qualifier;
+            this.runtimeName  = runtime_name;
+        }
+
+        /**
+         *  Construct a RTQname-type runtime name.
+         *  @param qualifier - the runtime qualifier.
+         *  @param name - the compile-time name.
+         */
+        RuntimeMultiname(InstructionList qualifier, Name name)
+        {
+            this.runtimeQualifier = qualifier;
+            this.compileTimeName  = name;
+        }
+
+        /**
+         *  Construct a MultinameL-type runtime name.
+         *  @param qualifier - the Multiname.  Note this
+         *    is the only kind of runtime name that receives
+         *    a qualifying name.
+         *  @param nameL - the runtime expression that 
+         *    yields the base name.
+         */
+        RuntimeMultiname(Name qualifier, InstructionList nameL)
+        {
+            assert(qualifier.getKind() == CONSTANT_MultinameL || qualifier.getKind() == CONSTANT_MultinameLA): "Bad qualifier kind " + qualifier.getKind() + " on name " + qualifier.toString();
+            this.compileTimeQualifier = qualifier;
+            this.runtimeName = nameL;
+        }
+
+        /**
+         *  Assemble the ingredients into an expression.
+         *  @param opcode - one of OP_getproperty or OP_setproperty.
+         *  @param rhs - the value of a setproperty call.  Passed to
+         *    this routine because there may be name-specific 
+         *    instructions before and after the value.
+         */
+        InstructionList generateGetOrSet(IASNode iNode, int opcode, InstructionList rhs)
+        {
+            InstructionList result = createInstructionList(iNode);
+
+            //  Note: numerous microoptimization opportunities here
+            //  to avoid storing values in temps by creative use of
+            //  OP_dup and OP_swap, especially in getproperty gen.
+
+            if ( this.compileTimeQualifier != null && this.runtimeName != null )
+            {
+                //  Generate MultinameL type code.
+                Binding name_temp = currentScope.allocateTemp();
+
+                result.addAll(this.runtimeName);
+                result.addInstruction(OP_dup);
+                result.addInstruction(name_temp.setlocal());
+                //  findprop(MultinameL) consumes a name from the value stack.
+                result.addInstruction(OP_findpropstrict, this.compileTimeQualifier);
+                result.addInstruction(name_temp.getlocal());
+                if ( rhs != null )
+                    result.addAll(rhs);
+
+                //  get/setprop(MultinameL) consumes a name from the value stack.
+                result.addInstruction(opcode, this.compileTimeQualifier);
+            }
+            else if ( this.runtimeQualifier != null && this.runtimeName != null )
+            {
+                //  Generate RTQnameL type code.
+                Binding name_temp = currentScope.allocateTemp();
+                Binding qual_temp = currentScope.allocateTemp();
+
+                Name rtqnl = new Name(CONSTANT_RTQnameL, null, null);
+
+                result.addAll(getRuntimeName(iNode));
+                result.addInstruction(name_temp.setlocal());
+
+                result.addAll(getRuntimeQualifier(iNode));
+                result.addInstruction(OP_dup);
+                result.addInstruction(qual_temp.setlocal());
+
+                result.addInstruction(name_temp.getlocal());
+                //  findprop(RTQNameL) consumes namespace and name from the value stack.
+                result.addInstruction(OP_findpropstrict, rtqnl);
+                result.addInstruction(qual_temp.getlocal());
+                result.addInstruction(name_temp.getlocal());
+                if ( rhs != null )
+                    result.addAll(rhs);
+
+                //  get/setprop(RTQNameL) consumes namespace and name from the value stack.
+                result.addInstruction(opcode, rtqnl);
+
+                currentScope.releaseTemp(name_temp);
+                currentScope.releaseTemp(qual_temp);
+            }
+            else
+            {
+                //  Last valid combination generates a RTQname.
+                assert(this.runtimeQualifier != null && this.compileTimeName != null) : "Unknown runtime name configuration: " + this.toString();
+
+                Name rtqn = new Name(CONSTANT_RTQname, null, this.compileTimeName.getBaseName());
+
+                result.addAll(getRuntimeQualifier(iNode));
+                result.addInstruction(OP_dup);
+                //  findprop(RTQName) consumes a namespace from the value stack.
+                result.addInstruction(OP_findpropstrict, rtqn);
+                result.addInstruction(OP_swap);
+                if ( rhs != null )
+                    result.addAll(rhs);
+
+                //  get/setprop(RTQName) consumes a namespace from the value stack.
+                result.addInstruction(opcode, rtqn);
+            }
+
+            return result;
+        }
+
+        /**
+         *  Generate the InstructionList that expresses this RuntimeName's qualifier.
+         *  @param iNode - an IASNode to contribute debug info to the result InstructionList.
+         *  @return the runtime qualifier setup instructions.
+         */
+        public InstructionList getRuntimeQualifier(IASNode iNode)
+        {
+            assert(hasRuntimeQualifier());
+            InstructionList result = createInstructionList(iNode);
+
+            result.addAll(replicate(this.runtimeQualifier));
+
+            //  Ensure the last instruction is an OP_coerce to Namespace.
+            Instruction last = result.lastElement();
+
+            if  (
+                    last.getOpcode() != OP_coerce ||
+                    last.getOperandCount() == 0 ||
+                    ! namespaceType.equals(last.getOperand(0))
+                )
+            {
+                result.addInstruction(OP_coerce, namespaceType);
+            }
+
+            return result;
+        }
+
+        /**
+         *  @return true if this RuntimeName has a runtime qualifier.
+         */
+        public boolean hasRuntimeQualifier()
+        {
+            return this.runtimeQualifier != null;
+        }
+
+        /**
+         *  @return true if this RuntimeName has a runtime name.
+         */
+        public boolean hasRuntimeName()
+        {
+            return this.runtimeName != null;
+        }
+
+        /**
+         *  Generate the InstructionList that expresses this RuntimeName's name.
+         *  @param iNode - an IASNode to contribute debug info to the result InstructionList.
+         *  @return the runtime name setup instructions.
+         */
+        public InstructionList getRuntimeName(IASNode iNode)
+        {
+            assert(hasRuntimeName());
+
+            InstructionList result = createInstructionList(iNode);
+
+            result.addAll(replicate(this.runtimeName));
+            if ( result.lastElement().getOpcode() != OP_coerce_s)
+                result.addInstruction(OP_coerce_s);
+            return result;
+        }
+
+        /**
+         *  Generate the runtime name appropriate to this qualifier/name combination.
+         *  @return the runtime name appropriate to this qualifier/name combination.
+         */
+        public Name generateName()
+        {
+            Name result;
+
+            if ( this.compileTimeQualifier != null )
+            {
+                result = this.compileTimeQualifier;
+            }
+            else if ( this.runtimeQualifier != null && this.runtimeName != null )
+            {
+                result = new Name(CONSTANT_RTQnameL, null, null);
+            }
+            else
+            {
+                //  Last valid combination generates a RTQname.
+                assert(this.runtimeQualifier != null && this.compileTimeName != null) : "Unknown runtime name configuration: " + this.toString();
+
+                result = new Name(CONSTANT_RTQname, null, this.compileTimeName.getBaseName());
+            }
+
+            return result;
+        }
+
+        /**
+         *  Convenience method generates an assignment
+         *  @param value - the value to set.
+         *  @return the instruction sequence to set a
+         *    the given multiname's value.
+         */
+        InstructionList generateAssignment(IASNode iNode, InstructionList value)
+        {
+            return generateGetOrSet(iNode, getAssignmentOpcode(iNode), value);
+        }
+
+        /**
+         *  Deduce the correct assignment opcode for a property.
+         *  @param iNode - the root of the reference to the property.
+         *  @return OP_initproperty if the property is const, OP_setproperty if not.
+         */
+        int getAssignmentOpcode(IASNode iNode)
+        {
+            if ( SemanticUtils.isConst(iNode, currentScope.getProject()) && ABCGeneratingReducer.this.inInitializingContext(iNode) )
+                return OP_initproperty;
+            else
+                return OP_setproperty;
+        }
+
+        /**
+         *  Convenience method generates an r-value.
+         *  @return the instruction sequence to look up
+         *    the given multiname.
+         */
+        InstructionList generateRvalue(IASNode iNode)
+        {
+            return generateGetOrSet(iNode, OP_getproperty, null);
+        }
+
+        /**
+         *  Diagnostic toString() method, 
+         *  used primarily to debug the assertion in generate().
+         */
+        @Override
+            public String toString()
+            {
+                return  "\n\t" + compileTimeQualifier + ",\n\t" + runtimeQualifier + ",\n\t" + compileTimeName + ",\n\t" + runtimeName;
+            }
+    }
+
+    /**
+     *  ForKeyValueLoopState holds the state of a for/in or for each/in loop:
+     *  the Hasnext2Wrapper that tracks the state of the locals required to
+     *  support the hasnext2 instruction, and the Labels that mark the top
+     *  of the loop and the test.
+     */
+    private class ForKeyValueLoopState
+    {
+        /**
+         *  Label for the loop-test logic.
+         */
+        Label test = new Label();
+ 
+        /**
+         *  Label for the top of the loop body.
+         */
+        Label loop = new Label();
+
+        /**
+         *  Hasnext2 management structure.
+         */
+        LexicalScope.Hasnext2Wrapper hasnext = currentScope.hasnext2();
+
+        /**
+         *  Generate the loop prologue code.
+         *  @return loop prologue code.
+         */
+        InstructionList generatePrologue(IASNode iNode, InstructionList base)
+        {
+            InstructionList result = createInstructionList(iNode);
+
+            //  Set up the object and index registers.
+            result.addInstruction(OP_pushbyte, 0);
+            result.addInstruction(hasnext.index_temp.setlocal());
+
+            result.addAll(base);
+            result.addInstruction(hasnext.stem_temp.setlocal());
+
+            //  Go to the loop test.
+            result.addInstruction(OP_jump, test);
+
+            //  Top of loop processing.
+            result.addInstruction(OP_label);
+            result.labelCurrent(loop);
+            return result;
+        }
+
+        /**
+         *  Generate the instruction sequence that
+         *  fetches the next key or value.
+         *  @return the instruction sequence that
+         *    fetches the next key or value.
+         */
+        InstructionList generateKeyOrValue(int opcode)
+        {
+            InstructionList result = new InstructionList();
+            result.addInstruction(hasnext.stem_temp.getlocal());
+            result.addInstruction(hasnext.index_temp.getlocal());
+            result.addInstruction(opcode);
+            return result;
+        }
+
+        /**
+         *  Generate the loop epilogue code.
+         *  @return loop epilogue code.
+         */
+        InstructionList generateEpilogue()
+        {
+            InstructionList result = new InstructionList();
+            result.addInstruction(hasnext.instruction);
+            result.labelCurrent(test);
+            currentScope.getFlowManager().resolveContinueLabel(result);
+            result.addInstruction(OP_iftrue, loop);
+            hasnext.release();
+            return result;
+        }
+    }
+
+    /**
+     *  The current LexicalScope.  Set by the caller,
+     *  changes during reduction when a scoped construct
+     *  such as an embedded function or a with statement
+     *  is encountered.
+     */
+    private LexicalScope currentScope;
+
+    /**
+     *  Instructions sent by the caller to be added to
+     *  a function definition.  Usually these are field
+     *  initialization expressions in a constructor.
+     */
+    private InstructionList instanceInitializers;
+
+    /**
+     *  "Mini scope" regions, i.e., blocks of the method body.
+     */
+    Stack<InstructionList> miniScopes = new Stack<InstructionList>();
+
+    /**
+     *  A shared name for the Namespace type.
+     */
+    public static final Name namespaceType = new Name("Namespace");
+
+    /**
+     *  A shared name for the XML type.
+     */
+    public static final Name xmlType = new Name("XML");
+
+    /**
+     *  A shared name for the XMLList type.
+     */
+    public static final Name xmlListType = new Name("XMLList");
+
+    /**
+     *  A shared name for the RegExp type.
+     */
+    public static final Name regexType = new Name("RegExp");
+
+    /**
+     *  A shared name for the void type.
+     */
+    public static final Name voidType = new Name("void");
+
+    /**
+     *  Generate code to push a numeric constant.
+     */
+    public static void pushNumericConstant(long value, InstructionList result_list)
+    {
+        result_list.pushNumericConstant(value);
+    }
+
+    /**
+     * Generate code to push a numeric value onto the stack.  This will take into account the type
+     * of the expression that generated the number - e.g. a numeric value produced from a const of type 'int'
+     * will produce at worst a pushint instruction
+     *
+     * Used by the constant folding routines so we don't lose type info when all we have is a Number.
+     *
+     * @param result_list   IL to add the instruction.
+     * @param value         the numeric value to push
+     * @param type          the type of the expression that produced the value.
+     */
+    public void pushNumericConstant(InstructionList result_list, Number value, IDefinition type)
+    {
+        ICompilerProject project = currentScope.getProject();
+        if( type == project.getBuiltinType(BuiltinType.INT) )
+        {
+            int val = ECMASupport.toInt32(value);
+            if( (byte)val == val )
+            {
+                result_list.addInstruction(OP_pushbyte, val);
+            }
+            else if( (short)val == val )
+            {
+                result_list.addInstruction(OP_pushshort, val);
+            }
+            else
+            {
+                result_list.addInstruction(OP_pushint, Integer.valueOf(val));
+            }
+        }
+        else if( type == project.getBuiltinType(BuiltinType.UINT) )
+        {
+            long uval = ECMASupport.toUInt32(value.doubleValue());
+            if ((uval & 0x7F) == uval) { // Pushbyte sign extends
+                result_list.addInstruction(OP_pushbyte, (int)uval);
+            }
+            else if ((uval & 0x7FFF) == uval) { // Pushshort sign extends
+                result_list.addInstruction(OP_pushshort, (int)uval);
+            }
+            else {
+                result_list.addInstruction(OP_pushuint, Long.valueOf(uval));
+            }
+        }
+        else
+        {
+            double dval = value.doubleValue();
+            if( ECMASupport.isNan(dval) )
+            {
+                result_list.addInstruction(OP_pushnan);
+            }
+            else if (!Double.isInfinite(dval) && (dval == ECMASupport.toInt32(value)) )
+            {
+                // distinguish pos/neg 0
+                // java treats -0 and 0 as equal, but divide by -0 results in NEG INFINITY, whereas pos
+                // 0 results in POS INFINITY
+                // positive 0 can be encoded with a pushbyte, but neg zero requires a pushdouble
+                if( dval == 0 && 1/dval == Double.NEGATIVE_INFINITY )
+                    result_list.addInstruction(OP_pushdouble, dval);
+                else
+                    // Integer
+                    pushNumericConstant(result_list, ECMASupport.toInt32(value), project.getBuiltinType(BuiltinType.INT));
+            }
+            else if( Double.isNaN(dval) )
+            {
+                result_list.addInstruction(OP_pushnan);
+            }
+            else
+            {
+                result_list.addInstruction(OP_pushdouble, value.doubleValue());
+            }
+        }
+    }
+
+    /**
+     *  @return the currently active collection of problems.
+     */
+    public Collection<ICompilerProblem> getProblems()
+    {
+        return currentScope.getProblems();
+    }
+
+    /**
+     *  Generate a binary operator.
+     *  @param l - the left-hand operand.
+     *  @param r - the right-hand operand.
+     *  @param opcode - the operator's opcode.
+     *  @return the combined instruction sequence with the operator appended.
+     */
+    InstructionList binaryOp(IASNode iNode, InstructionList l, InstructionList r, int opcode)
+    {
+        checkBinaryOp(iNode, opcode);
+        return binaryOperatorBody(iNode, l, r, InstructionFactory.getInstruction(opcode));
+    }
+
+    /**
+     *  Generate a conditional jump operator.
+     *  @param l - the left-hand operand.
+     *  @param r - the right-hand operand.
+     *  @param opcode - the operator's opcode.
+     *  @return the combined instruction sequence with the operator appended.
+     *    The target is filled in by a downstream reduction.
+     */
+    InstructionList conditionalJump(IASNode iNode, InstructionList l, InstructionList r, int opcode)
+    {
+        checkBinaryOp(iNode, opcode);
+        return binaryOperatorBody(iNode, l, r, InstructionFactory.getTargetableInstruction(opcode));
+    }
+
+    /**
+     *  Generate a binary operator.
+     *  @param l - the left-hand operand.
+     *  @param r - the right-hand operand.
+     *  @param operator - the operator, as an Instruction.
+     *  @return the combined instruction sequence with the operator appended.
+     */
+    InstructionList binaryOperatorBody(IASNode iNode, InstructionList l, InstructionList r, Instruction operator)
+    {
+        InstructionList result = createInstructionList(iNode, l.size() + r.size() + 1);
+        result.addAll(l);
+        result.addAll(r);
+        result.addInstruction(operator);
+        return result;
+    }
+
+    /**
+     *  Perform semantic checks on a binary operator.
+     */
+    public void checkBinaryOp (IASNode iNode, int opcode)
+    {
+        currentScope.getMethodBodySemanticChecker().checkBinaryOperator(iNode, opcode);
+    }
+
+    /**
+     *  Resolve a dotted name, e.g., foo.bar.baz
+     */
+    Binding dottedName(IASNode iNode, String qualifiers, String base_name)
+    {
+        if ( iNode instanceof IdentifierNode )
+        {
+            return currentScope.resolveName((IdentifierNode)iNode);
+        }
+        else if ( iNode instanceof ExpressionNodeBase )
+        {
+            ExpressionNodeBase expr = (ExpressionNodeBase) iNode;
+            Name n = expr.getMName(currentScope.getProject());
+
+            if ( n == null )
+            {
+                currentScope.addProblem(new CodegenInternalProblem(iNode, "Unable to resove member name: " + iNode.toString()));
+                n = new Name(CONSTANT_Qname, new Nsset(new Namespace(CONSTANT_PackageNs, qualifiers)), base_name);
+            }
+
+            return currentScope.getBinding(iNode, n, expr.resolve(currentScope.getProject()));
+        }
+
+        //else
+            currentScope.addProblem(new CodegenInternalProblem(iNode, "Unable to resove to a dotted name: " + iNode.toString()));
+            return new Binding(iNode, new Name(CONSTANT_Qname, new Nsset(new Namespace(CONSTANT_PackageNs, qualifiers)), base_name), null);
+    }
+
+    /**
+     *  Resolve a dotted name, e.g., foo.bar.baz, where the whole dotted name is a package
+     *  this is an error, and a diagnostic will be emitted
+     */
+    Binding errorPackageName(IASNode iNode, String qualifiers, String base_name)
+    {
+        currentScope.addProblem(new PackageCannotBeUsedAsValueProblem(iNode, "'" + qualifiers + "." + base_name + "'"));
+        return new Binding(iNode, new Name(qualifiers + "." + base_name), null);
+    }
+
+    private void generateAssignmentOp(IASNode site, Binding target, InstructionList result)
+    {
+        boolean inlined = generateInlineSetterAccess(target, result, true);
+
+        if (!inlined)
+            result.addInstruction(getAssignmentOpcode(site, target), target.getName());
+    }
+
+    /**
+     * Deduce the correct assignment opcode for a Binding.
+     * 
+     * @param b - the Binding of interest.
+     * @return the appropriate opcode to assign to the entity represented by the
+     * Binding.
+     */
+    int getAssignmentOpcode(IASNode site, Binding b)
+    {
+        if (b.getDefinition() instanceof IConstantDefinition && this.inInitializingContext(site))
+            return OP_initproperty;
+        else if (b.isSuperQualified())
+            return OP_setsuper;
+        else
+            return OP_setproperty;
+    }
+
+    /**
+     *  Is the generator in an initializing context?
+     *  @param iNode - the i-node of interest.
+     *  @return true if the generator is in a context where it should
+     *    generate initializer calls, i.e., OP_initproperty to set properties.
+     */
+    boolean inInitializingContext(IASNode iNode)
+    {
+        return SemanticUtils.isInVariableDeclaration(iNode) || SemanticUtils.isInConstructor(iNode);
+    }
+
+
+    /**
+     *  Common routine used by reductions that
+     *  need an empty list.
+     *  @param iNode - the current AST node.
+     */
+    public InstructionList createInstructionList(IASNode iNode)
+    {
+        return createInstructionList(iNode, 0);
+    }
+
+    /**
+     *  Common routine used by reductions that
+     *  need an empty list.
+     *  @param iNode - the current AST node.
+     *  @param capacity - requested capacity of the new list.
+     *    May be adjusted to accomodate debug instructions.
+     */
+    public InstructionList createInstructionList(IASNode iNode, int capacity)
+    {
+        DebugInfoInstructionList result;
+
+        String file_name = SemanticUtils.getFileName(iNode);
+
+        //  Note: getLine() uses zero-based counting.
+        int line_num = iNode.getLine() + 1;
+
+        //  Adjust the capacity requirement if debug
+        //  instructions are to be emitted.
+        if ( currentScope.emitFile(file_name) )
+            capacity++;
+        if ( currentScope.emitLine(line_num) )
+            capacity++;
+
+        //  If the required capacity is less than three
+        //  instructions, the InstructionList can hold 
+        //  them organically.  Specifying a capacity to
+        //  the InstructionList ctor causes it to allocate
+        //  a separate ArrayList.
+        if ( capacity > 3 )
+            result = new DebugInfoInstructionList(capacity);
+        else
+            result = new DebugInfoInstructionList();
+
+        if ( currentScope.emitFile(file_name) )
+        {
+            currentScope.setDebugFile(file_name);
+            result.addInstruction(OP_debugfile, currentScope.getDebugFile());
+        }
+
+        if ( currentScope.emitLine(line_num) )
+        {
+            // Set the line number in the instruction list - it will
+            // emit or not emit the debugline depending on how it's used
+            result.setDebugLine(line_num);
+            currentScope.setDebugLine(line_num);
+        }
+
+        return result;
+    }
+
+    /**
+     * Instruction list to help with emitting OP_debuglines.
+     *
+     * When given a line number, it will emit an OP_debugline when addInstruction is called with an
+     * executable instruction.
+     *
+     * If addAll is called, then the debugline will not be emitted as the IL passed in should already have
+     * any necessary debuglines if it contains executable instrucitons.
+     *
+     */
+    private static class DebugInfoInstructionList extends InstructionList
+    {
+        /**
+         * Constant for we don't have a line number
+         */
+        public static final int NO_LINE = -1;
+        /**
+         * The line number to use for an op_debugline when an executable instruction is added
+         */
+        private int line_num = NO_LINE;
+
+        DebugInfoInstructionList (int capacity)
+        {
+            super(capacity);
+        }
+        DebugInfoInstructionList ()
+        {
+            super();
+        }
+
+        /**
+         * Set the line number for this IL
+         * @param line_num  the line number
+         */
+        void setDebugLine(int line_num)
+        {
+            this.line_num = line_num;
+        }
+
+        /**
+         * Add the instruction to the IL.  If the instruction is
+         * an exectuable instruction, and we have not emitted the line number yet,
+         * then this will insert an OP_debugline with the line number before the instruction is
+         * added.
+         * @param insn  the instruction to be added.
+         * @return      the added instruction
+         */
+        public Instruction addInstruction(Instruction insn)
+        {
+
+            if( line_num != NO_LINE && insn.isExecutable() )
+            {
+                // add the debugline instruction first
+
+                // reset the line number
+                // do this before adding the instruction so
+                // we don't infinitely recurse
+                int line = line_num;
+                line_num = NO_LINE;
+
+                addInstruction(OP_debugline, line);
+            }
+            return super.addInstruction(insn);
+        }
+    }
+
+    /**
+     *  Error trap.
+     */
+    public Binding error_namespaceAccess(IASNode iNode, IASNode raw_qualifier, Binding qualified_name)
+    {
+        String qualifier = ((IdentifierNode)raw_qualifier).getName();
+
+        //  TODO: In some circumstances, the namespace qualifier
+        //  may be an invalid attribute on a declaration.
+        currentScope.addProblem(new UnknownNamespaceProblem(raw_qualifier, qualifier));
+
+        return qualified_name;
+    }
+
+    /**
+     *  Error trap.
+     */
+    public InstructionList error_reduce_Op_AssignId(IASNode iNode, InstructionList non_lvalue, InstructionList rvalue)
+    {
+        currentScope.addProblem(new InvalidLvalueProblem(iNode));
+        InstructionList result = createInstructionList(iNode, 1);
+        // Since we are reducing to an expression, make sure the instruction
+        // list we return, produces a value on the operand stack.
+        result.addInstruction(ABCConstants.OP_pushundefined);
+        return result;
+    }
+
+    /**
+     *  Generate access to a named entity.
+     *  @param name - the entity's name.
+     *  @return an instruction sequence to access the entity.
+     */
+    InstructionList generateAccess(Binding name)
+    {
+        return generateAccess(name, AccessType.Strict);
+    }
+
+    /**
+     *  Enumerate possible access types to a named entity;
+     *  Lenient is used in typeof expressions to access
+     *  variables referred to by simple name and for the
+     *  member references of member access expressions.
+     *  All other expressions use strict access.
+     */
+    private enum AccessType { Strict, Lenient }
+
+    /**
+     *  Generate access to a named entity.
+     *  @param name - the entity's name.
+     *  @param accessType - one of Lenient or Strict.
+     *  @return an instruction sequence to access the entity.
+     */
+    InstructionList generateAccess(Binding name, AccessType accessType)
+    {
+        InstructionList result = new InstructionList(2);
+        generateAccess(name, accessType, result);
+        return result;
+    }
+
+    /**
+     *  Generate access to a named entity.
+     *  @param name - the entity's name.
+     *  @param result - the instruction sequence to generate into.
+     */
+    void generateAccess(Binding binding, InstructionList result)
+    {
+        generateAccess(binding, AccessType.Strict, result);
+    }
+
+    /**
+     *  Generate access to a named entity.
+     *  @param name - the entity's name.
+     *  @param accessType - one of Lenient or Strict.
+     *  @param result - the instruction sequence to generate into.
+     */
+    void generateAccess(Binding binding, AccessType accessType, InstructionList result)
+    {
+        if (binding.isLocal())
+        {
+            result.addInstruction(binding.getlocal());
+        }
+        else
+        {
+            assert (binding.getName() != null) : "non-local Binding " + binding + " must have a name";
+            currentScope.getMethodBodySemanticChecker().checkGetProperty(binding);
+
+            boolean inlined = generateInlineGetterAccess(binding, result, false);
+
+            if (!inlined)
+                generateAccess(binding, binding.isSuperQualified(), accessType, result);
+        }
+    }
+
+    /**
+     *  Generate access to a named entity.
+     *  @param binding - the entity's binding.
+     *  @param is_super - set if the name was explicitly qualified with "super."
+     *  @param accessType - one of Lenient or Strict.
+     *  @param result - the instruction sequence to generate into.
+     */
+    void generateAccess(Binding binding, final boolean is_super, AccessType accessType, InstructionList result)
+    {
+        final Name name = binding.getName();
+        assert (name != null) : "binding must have a name when calling generateAccess()";
+
+        final IASNode node = binding.getNode();
+        if ( name.isTypeName() )
+        {
+            // a type names node should always be a ITypedExpressionNode
+            ITypedExpressionNode typeNode = (ITypedExpressionNode)node;
+            IExpressionNode collectionNode = typeNode.getCollectionNode();
+            IDefinition collectionDefinition = SemanticUtils.getDefinition(collectionNode, currentScope.getProject());
+            Binding collectionBinding = currentScope.getBinding(collectionNode, name.getTypeNameBase(), collectionDefinition);
+            generateAccess(collectionBinding, is_super, AccessType.Strict, result);
+
+            IExpressionNode typeTypeNode = typeNode.getTypeNode();
+            IDefinition typeDefinition = SemanticUtils.getDefinition(typeTypeNode, currentScope.getProject());
+            Binding typeBinding = currentScope.getBinding(typeTypeNode, name.getTypeNameParameter(), typeDefinition);
+            generateTypeNameParameter(typeBinding, result);
+
+            result.addInstruction(OP_applytype, 1);
+        }
+        else
+        {
+            // Test whether we're refering to the class being initialized, for example: 
+            // public class C {
+            //     private static var v:Vector.<C> = new Vector.<C>();
+            // }
+            // as in this case we need to do a getlocal0 as the class
+            // hasn't been initialized yet
+            boolean useLocal0 = false;
+            if (node instanceof IdentifierNode)
+            {
+                IdentifierNode id = (IdentifierNode)node;
+                IDefinition def = id.resolve(currentScope.getProject());
+                if (SemanticUtils.isRefToClassBeingInited(id, def) && !currentScope.insideInlineFunction())
+                    useLocal0 = true;
+            }
+
+            // TODO: use getslot when we can.
+            // TODO: we can at least do this when we're accessing something in an activation object            
+            if (useLocal0)
+            {
+                result.addInstruction(OP_getlocal0);
+            }
+            else if (is_super)
+            {
+                result.addAll(currentScope.findProperty(binding, true));
+                result.addInstruction(OP_getsuper, name);
+            }
+            else if (accessType == AccessType.Lenient)
+            {
+                result.addAll(currentScope.findProperty(binding, false));
+                result.addInstruction(OP_getproperty, name);
+            }
+            else
+            {
+                result.addAll(currentScope.getPropertyValue(binding));
+            }
+        }
+    }
+
+    private boolean generateInlineGetterAccess(Binding binding, InstructionList result, boolean isQualified)
+    {
+        IDefinition def = binding.getDefinition();
+        if (!(def instanceof AccessorDefinition && currentScope.getMethodBodySemanticChecker().canGetterBeInlined((AccessorDefinition)def)))
+            return false;
+
+        AccessorDefinition accessorDefinition = (AccessorDefinition)def;
+        if (accessorDefinition instanceof SetterDefinition)
+            accessorDefinition = accessorDefinition.resolveCorrespondingAccessor(currentScope.getProject());
+
+        assert (accessorDefinition != null) : "generateInlineGetterAccess() called with no getter definition";
+
+        FunctionNode functionNode = (FunctionNode)accessorDefinition.getFunctionNode();
+        return inlineFunction(accessorDefinition, functionNode, result, isQualified);
+    }
+
+    private boolean generateInlineSetterAccess(Binding binding, InstructionList result, boolean isQualified)
+    {
+        IDefinition def = binding.getDefinition();
+        if (!(def instanceof AccessorDefinition && currentScope.getMethodBodySemanticChecker().canSetterBeInlined((AccessorDefinition)def)))
+            return false;
+
+        AccessorDefinition accessorDefinition = (AccessorDefinition)def;
+        if (accessorDefinition instanceof GetterDefinition)
+            accessorDefinition = accessorDefinition.resolveCorrespondingAccessor(currentScope.getProject());
+
+        assert (accessorDefinition != null) : "generateInlineSetterAccess() called with no setter definition";
+
+        FunctionNode functionNode = (FunctionNode)accessorDefinition.getFunctionNode();
+        return inlineFunction(accessorDefinition, functionNode, result, isQualified);
+    }
+
+    private boolean generateInlineFunctionCall(Binding binding, InstructionList result, boolean isQualified, Vector<InstructionList> args)
+    {
+        IDefinition def = binding.getDefinition();
+        if (!(def instanceof FunctionDefinition && (!(def instanceof IAccessorDefinition)) && currentScope.getMethodBodySemanticChecker().canFunctionBeInlined((FunctionDefinition)def)))
+            return false;
+
+        FunctionDefinition functionDef = (FunctionDefinition)binding.getDefinition();
+        FunctionNode functionNode = (FunctionNode)functionDef.getFunctionNode();
+
+        InstructionList insn = createInstructionList(functionNode);
+        for (InstructionList arg: args)
+            insn.addAll(arg);
+
+        if (inlineFunction(functionDef, functionNode, insn, isQualified))
+        {
+            result.addAll(insn);
+            return true;
+        }
+        else
+        {
+            return false;
+        }
+    }
+
+    private boolean inlineFunction(FunctionDefinition functionDef, FunctionNode functionNode, InstructionList result, boolean isQualified)
+    {
+        try
+        {
+            InlineFunctionLexicalScope inlineFunctionScope = currentScope.pushInlineFunctionFrame(functionDef.getContainingScope(), isQualified, functionNode);
+            currentScope = inlineFunctionScope;
+
+            // generate the instructions for the body of the function
+            IScopedNode body = functionNode.getScopedNode();
+            InstructionList insns = inlineFunctionScope.getGenerator().generateInstructions(body, CmcEmitter.__statement_NT, inlineFunctionScope);
+
+            currentScope = currentScope.popFrame();
+
+            final ICompilerProject project = currentScope.getProject();
+            if (currentScope.getMethodBodySemanticChecker().functionBodyHasNonInlineableInstructions(insns, functionDef.isInline(), functionDef.getBaseName()))
+            {
+                return false;
+            }
+            else
+            {
+                inlineFunctionScope.assignActualsToFormals(functionDef, result);
+
+                if (isQualified)
+                    result.addInstruction(inlineFunctionScope.setContainingClass());
+
+                result.addAll(insns);
+
+                // test for a fallthrough when the return type is non-void, as we
+                // need coerce undefined to the return type to mimic returnvoid behavior
+                if (!(functionDef instanceof SetterDefinition) && result.canFallThrough() || result.hasPendingLabels())
+                {
+                    TypeDefinitionBase returnType = (TypeDefinitionBase)functionDef.resolveReturnType(project);
+                    if (returnType != currentScope.getProject().getBuiltinType(BuiltinType.VOID) &&
+                        returnType != currentScope.getProject().getBuiltinType(BuiltinType.ANY_TYPE))
+                    {
+                        result.addInstruction(OP_pushundefined);
+                        result.addInstruction(OP_coerce, returnType.getMName(project));
+                    }
+                }
+
+                result.labelNext(inlineFunctionScope.getInlinedFunctionCallSiteLabel());
+                inlineFunctionScope.mergeIntoContainingScope(result);
+            }
+        }
+        finally
+        {
+            functionNode.discardFunctionBody();
+        }
+
+        return true;
+    }
+
+    /**
+     *  Generate code to assign to a named entity.
+     *  @param target - the entity to be assigned to.
+     *  @param rvalue - the value to assign.
+     *  @return an instruction sequence that stores
+     *    the given rvalue in the target.
+     *  
+     */
+    InstructionList generateAssignment(IASNode iNode, Binding target, InstructionList rvalue)
+    {
+        return generateAssignment(iNode, target, rvalue, false);
+    }
+
+    /**
+     *  Generate code to assign to a named entity.
+     *  @param target - the entity to be assigned to.
+     *  @param rvalue - the value to assign.
+     *  @param need_value - when true, 
+     *    leave a DUP of the rvalue on the stack.
+     *  @return an instruction sequence that stores
+     *    the given rvalue in the target, and leaves
+     *    a DUP of the rvalue on the stack if need_value is set.
+     *  
+     */
+    InstructionList generateAssignment(IASNode iNode, Binding target, InstructionList rvalue, boolean need_value)
+    {
+        InstructionList result = createInstructionList(iNode, rvalue.size() + 4);
+
+        //  We may need to know if the RHS is in a local
+        //  for some micro-optimizations; the rvalue instruction
+        //  list is about to be invalidated, so speculatively
+        //  determine that information here.
+        int rhsOpcode = rvalue.lastElement().getOpcode();
+        final boolean rhsIsLocal = 
+            rhsOpcode == OP_getlocal || 
+            rhsOpcode == OP_getlocal0 || 
+            rhsOpcode == OP_getlocal1 || 
+            rhsOpcode == OP_getlocal2 || 
+            rhsOpcode == OP_getlocal3;
+
+        result.addAll(rvalue);
+        if ( need_value )
+            result.addInstruction(OP_dup);
+
+        // when assigning to a local or slot, we need to generate the type coerce and
+        // runtime illegal write to const checks, so combine in this if block.
+        if ( target.isLocal() || target.slotIdIsSet() )
+        {
+            if ( target.getDefinition() != null )
+            {
+                ITypeDefinition tgtType = target.getDefinition().resolveType(currentScope.getProject());
+                ITypeDefinition srcType = null;
+
+                srcType = SemanticUtils.resolveRHSTypeOfAssignment(currentScope.getProject(), iNode);
+
+                if (
+                    tgtType != null &&
+                    tgtType != ClassDefinition.getAnyTypeClassDefinition() &&
+                    !(srcType == tgtType && rhsIsLocal)
+                )
+                {
+                    coerce(result, tgtType);
+                }
+            }
+
+            //  If the target is a const and this assignment occurs outside the const's declaration,
+            //  emulate the AVM's behavior by compiling in a throw statement.
+            //  Note that this behavior differs from ASC's until ASC-4376 is fixed.
+            //  We need to keep this runtime check, as in strict mode this is a semantic error, but
+            //  in non-strict mode it needs to be caught at run time.
+            if  (
+                    SemanticUtils.isConstDefinition(target.getDefinition())  && 
+                    !SemanticUtils.isInVariableDeclaration(iNode) && 
+                    target.getName() != null
+                )
+            {
+                result.addInstruction(OP_pushstring, "Illegal write to local const " + target.getName().getBaseName());
+                result.addInstruction(OP_throw);
+            }
+            else if (target.slotIdIsSet())
+            {
+                if (currentScope.needsActivation())
+                {
+                    // Restore the activation object.
+                    result.addInstruction(currentScope.getActivationStorage().getlocal());
+                    result.addInstruction(OP_swap);
+                }
+
+                result.addInstruction(OP_setslot, target.getSlotId());
+            }
+            else
+            {
+                result.addInstruction(target.setlocal());
+            }
+        }
+        else
+        {
+            boolean inlined = generateInlineSetterAccess(target, result, false);
+
+            if (!inlined)
+            {
+                IDefinition def = target.getDefinition();
+                if (def instanceof GetterDefinition)
+                {
+                    boolean isSuper = target.isSuperQualified();
+                    SetterDefinition setter = (SetterDefinition)((GetterDefinition)def).
+                                resolveCorrespondingAccessor(currentScope.getProject());
+                    target = currentScope.getBinding(setter);   
+                    if (isSuper)
+                        target.setSuperQualified(true);
+                }
+                result.addAll(currentScope.findProperty(target, false));
+                result.addInstruction(OP_swap);
+                result.addInstruction(getAssignmentOpcode(iNode, target), target.getName());
+            }
+        }
+        return result;
+    }
+
+    /**
+     *  Generate a catch block.
+     *  @param catch_proto - the catch block's prototype.
+     */
+    InstructionList generateCatchBlock( Label try_start, Label try_end, CatchPrototype catch_proto)
+    {
+        InstructionList scope_reinit = currentScope.getFlowManager().getScopeStackReinit();
+        InstructionList current_catch = new InstructionList(catch_proto.catchBody.size() + scope_reinit.size() + 15);
+
+        //  Common prologue code.
+        if ( currentScope.needsThis() )
+        {
+            current_catch.addInstruction(OP_getlocal0);
+            current_catch.addInstruction(OP_pushscope);
+        }
+
+        if( currentScope.needsActivation() )
+        {
+            //  Restore the activation object.
+            current_catch.addInstruction(currentScope.getActivationStorage().getlocal());
+            current_catch.addInstruction(OP_pushscope);
+        }
+
+        //  Re-establish enclosing exception scopes.
+        current_catch.addAll(scope_reinit);
+
+        int handler_number = currentScope.getMethodBodyVisitor().visitException(try_start, try_end, current_catch.getLabel(), catch_proto.catchType, catch_proto.catchVarName);
+        Binding exception_storage = currentScope.getFlowManager().getFinallyContext().getExceptionStorage();
+
+        current_catch.addInstruction(OP_newcatch, handler_number);
+        current_catch.addInstruction(OP_dup);
+        if ( exception_storage != null )
+        {
+            current_catch.addInstruction(exception_storage.setlocal());
+            current_catch.addInstruction(OP_dup);
+        }
+        current_catch.addInstruction(OP_pushscope);
+        current_catch.addInstruction(OP_swap);
+        current_catch.addInstruction(OP_setslot, 1);
+
+        current_catch.addAll(catch_proto.catchBody);
+
+        if ( current_catch.canFallThrough() || current_catch.hasPendingLabels() )
+        {
+            current_catch.addInstruction(OP_popscope);
+        }
+
+        return current_catch;
+    }
+
+    /**
+     *  Generate a compound assignment statement.
+     */
+    InstructionList generateCompoundAssignment(IASNode iNode, Binding lvalue, InstructionList expr, int opcode, boolean need_value)
+    {
+        InstructionList result = createInstructionList(iNode, expr.size() + (lvalue.isLocal()? 4 : 8));
+
+        currentScope.getMethodBodySemanticChecker().checkCompoundAssignment(iNode, lvalue, opcode);
+
+        if ( lvalue.isLocal() )
+        {
+            result.addInstruction(lvalue.getlocal());
+            result.addAll(expr);
+            result.addInstruction(opcode);
+            if ( need_value )
+                result.addInstruction(OP_dup);
+
+            // Coerce to the right type if the local has a type anno
+            if ( lvalue.getDefinition() != null )
+            {
+                ITypeDefinition type = lvalue.getDefinition().resolveType(currentScope.getProject());
+
+                if ( type != ClassDefinition.getAnyTypeClassDefinition() )
+                {
+                    coerce(result, type);
+                }
+            }
+
+            result.addInstruction(lvalue.setlocal());
+        }
+        else
+        {
+            result.addAll(currentScope.findProperty(lvalue, true));
+            result.addInstruction(OP_dup);
+            result.addInstruction(OP_getproperty, lvalue.getName());
+            result.addAll(expr);
+            result.addInstruction(opcode);
+
+            Binding value_temp = null;
+            if ( need_value )
+            {
+                value_temp = currentScope.allocateTemp();
+                result.addInstruction(OP_dup);
+                result.addInstruction(value_temp.setlocal());
+            }
+            result.addInstruction(getAssignmentOpcode(iNode, lvalue), lvalue.getName());
+            if ( need_value )
+            {
+                result.addInstruction(value_temp.getlocal());
+                currentScope.releaseTemp(value_temp);
+            }
+        }
+
+        return result;
+    }
+
+    InstructionList generateCompoundBracketAssignment(IASNode iNode, InstructionList stem, InstructionList index, InstructionList expr, int opcode, boolean need_value)
+    {
+        IDynamicAccessNode arrayIndexNode = (IDynamicAccessNode)((IBinaryOperatorNode)iNode).getLeftOperandNode();
+        InstructionList result = createInstructionList(iNode, stem.size() * 2 + index.size() + expr.size() + 11 );
+
+        //  Although ASC evaluates the stem twice, it only evaluates the index once.
+        //  TODO: Inspect the index expression for side effects so the temp can be
+        //  elided in most cases.
+        Binding index_temp = currentScope.allocateTemp();
+        result.addAll(index);
+        result.addInstruction(index_temp.setlocal());
+
+        result.addAll(replicate(stem));
+        result.addInstruction(index_temp.getlocal());
+        result.addInstruction(arrayAccess(arrayIndexNode, OP_getproperty));
+        result.addAll(expr);
+        result.addInstruction(opcode);
+
+        Binding value_temp = currentScope.allocateTemp();
+        result.addInstruction(value_temp.setlocal());
+
+        result.addAll(stem);
+        result.addInstruction(index_temp.getlocal());
+        result.addInstruction(value_temp.getlocal());
+        result.addInstruction(arrayAccess(arrayIndexNode, OP_setproperty));
+
+        if ( need_value )
+            result.addInstruction(value_temp.getlocal());
+
+        currentScope.releaseTemp(value_temp);
+        currentScope.releaseTemp(index_temp);
+
+        return result;
+    }
+
+    InstructionList generateCompoundAssignmentToRuntimeName(IASNode iNode, RuntimeMultiname name, InstructionList expr, int opcode, boolean need_value)
+    {
+        InstructionList result = createInstructionList(iNode);
+        result.addAll(name.generateRvalue(iNode));
+        result.addAll(expr);
+        result.addInstruction(opcode);
+
+        if ( need_value )
+        {
+            //  TODO: In many cases this temp can be avoided by more sophisticated analysis.
+            //  TODO: See also comments in RuntimeMultiname.generateGetOrSet().
+            Binding temp = currentScope.allocateTemp();
+            result.addInstruction(temp.setlocal());
+            InstructionList temp_rhs = new InstructionList();
+            temp_rhs.addInstruction(temp.getlocal());
+            result.addAll(name.generateAssignment(iNode, temp_rhs));
+            result.addInstruction(temp.getlocal());
+            currentScope.releaseTemp(temp);
+        }
+        else
+        {
+            result = name.generateAssignment(iNode, result);
+        }
+
+        return result;
+    }
+
+    InstructionList generateCompoundMemberAssignment(IASNode iNode, InstructionList stem, Binding member, InstructionList expr, int fetch_opcode, int assign_opcode, boolean need_value)
+    {
+        InstructionList result = createInstructionList(iNode, stem.size() * 2 + expr.size() + 5 );
+        currentScope.getMethodBodySemanticChecker().checkCompoundAssignment(iNode, member, assign_opcode);
+
+        //  TODO: Depending on the resolution of ASC-4159 and 
+        //  the corresponding Falcon backwards compatibility
+        //  issue, cache the stem expression in a local to avoid
+        //  multiple evaluations.
+        result.addAll(replicate(stem));
+        result.addInstruction(fetch_opcode, member.getName());
+
+        result.addAll(expr);
+        result.addInstruction(assign_opcode);
+
+        if ( need_value )
+        {
+            result.addInstruction(OP_dup);
+        }
+
+        result.addAll(stem);
+        result.addInstruction(OP_swap);
+        result.addInstruction(getAssignmentOpcode(iNode, member), member.getName());
+
+        return result;
+    }
+
+    /**
+     *  Generate a compound logical assignment expression to a named lvalue.
+     *  @param iNode - the assignment operator (root of the subtree).
+     *  @param lvalue - the lvalue's name.
+     *  @param expr - the expression to assign.
+     *  @param is_and - true if the expression is &amp;&amp;=, false if it's ||=.
+     *  @param need_value - true if the expression's not used in a void context.
+     */
+    InstructionList generateCompoundLogicalAssignment(IASNode iNode, Binding lvalue, InstructionList expr, boolean is_and, boolean need_value)
+    {
+        InstructionList result = createInstructionList(iNode);
+        int failure_test = is_and? OP_iffalse : OP_iftrue;
+
+        currentScope.getMethodBodySemanticChecker().checkCompoundAssignment(iNode, lvalue, failure_test);
+
+        Label tail = new Label();
+
+        if ( lvalue.isLocal() )
+        {
+            //  Fetch and test the current value.
+            result.addInstruction(lvalue.getlocal());
+            //  The current value may not be the result value,
+            //  but for now assume it is.
+            if ( need_value )
+                result.addInstruction( OP_dup);
+
+            result.addInstruction( failure_test, tail );
+
+            //  Test succeeded: reset the value, but first
+            //  pop the value speculatively dup'd above.
+            if ( need_value )
+                result.addInstruction(OP_pop);
+
+            result.addAll(expr);
+
+            if ( need_value )
+                result.addInstruction(OP_dup);
+
+            result.addInstruction(lvalue.setlocal());
+        }
+        else
+        {
+            //  Fetch, speculatively dup, and test the current value.
+            result.addAll(currentScope.getPropertyValue(lvalue));
+
+            if ( need_value )
+                result.addInstruction(OP_dup);
+
+            result.addInstruction(failure_test, tail);
+
+            if ( need_value )
+                result.addInstruction(OP_pop);
+
+            result.addAll(expr);
+
+            if ( need_value )
+            {
+                result.addInstruction(OP_dup);
+            }
+
+            result.addAll(currentScope.findProperty(lvalue, true));
+            result.addInstruction(OP_swap);
+            result.addInstruction(getAssignmentOpcode(iNode, lvalue), lvalue.getName());
+
+        }
+
+        result.labelNext(tail);
+        return result;
+    }
+
+    /**
+     *  Generate compound logical assignment to a runtime name, e.g., n::x ||= foo;
+     *  @param iNode - the root of the assignment subtree.
+     *  @param name - the runtime name.
+     *  @param expr - the second operand of the implied binary expression.
+     *  @param is_and - true if the result is set to the second operand iff the first operand is true.
+     *  @param need_value - true if the value of the assignment is required.
+     */
+    InstructionList generateCompoundLogicalRuntimeNameAssignment(IASNode iNode, RuntimeMultiname name, InstructionList expr, boolean is_and, boolean need_value)
+    {
+        InstructionList result = createInstructionList(iNode);
+
+        Label tail = new Label();
+        int failure_test = is_and? OP_iffalse : OP_iftrue;
+
+        Binding rhs_temp = null;
+        InstructionList rhs_fetch = null;
+
+        //  Fetch, speculatively dup, and test the current value.
+        result.addAll(name.generateRvalue(iNode));
+
+        if ( need_value )
+            result.addInstruction(OP_dup);
+
+        result.addInstruction(failure_test, tail);
+
+        if ( need_value )
+        {
+            //  Clear the speculative dup.
+            result.addInstruction(OP_pop);
+        }
+
+        result.addAll(expr);
+
+        if ( need_value )
+        {
+            //  The runtime multiname instruction sequence
+            //  doesn't allow the rhs expression to travel
+            //  on the stack.
+            rhs_temp = currentScope.allocateTemp();
+            rhs_fetch = createInstructionList(iNode);
+
+            result.addInstruction(OP_dup);
+            result.addInstruction(rhs_temp.setlocal());
+            rhs_fetch.addInstruction(rhs_temp.getlocal());
+
+            result.addAll(name.generateAssignment(iNode, rhs_fetch));
+            currentScope.releaseTemp(rhs_temp);
+        }
+        else
+        {
+            result = (name.generateAssignment(iNode, result));
+        }
+
+        result.labelNext(tail);
+        return result;
+    }
+
+    /**
+     *  Generate a compound logical assignment expression to a a[i] type lvalue.
+     *  @param iNode - the assignment operator (root of the subtree).
+     *  @param stem - the expression that generates the lvalue's stem, e.g., a in a[i]
+     *  @param index - the index expression.
+     *  @param expr - the expression to assign.
+     *  @param is_and - true if the expression is &amp;&amp;=, false if it's ||=.
+     *  @param need_value - true if the expression's not used in a void context.
+     */
+    InstructionList generateCompoundLogicalBracketAssignment(IASNode iNode, InstructionList stem, InstructionList index, InstructionList expr, boolean is_and, boolean need_value)
+    {
+        IDynamicAccessNode arrayIndexNode = (IDynamicAccessNode)((IBinaryOperatorNode)iNode).getLeftOperandNode();
+        
+        InstructionList result = createInstructionList(iNode, stem.size() * 2 + index.size() + expr.size() + 11 );
+
+        Label tail = new Label();
+        int failure_test = is_and? OP_iffalse : OP_iftrue;
+
+        //  Although ASC evaluates the stem twice, it only evaluates the index once.
+        //  TODO: Inspect the index expression for side effects so the temp can be
+        //  elided in most cases.
+        Binding index_temp = currentScope.allocateTemp();
+        result.addAll(index);
+        result.addInstruction(index_temp.setlocal());
+
+        result.addAll(replicate(stem));
+        result.addInstruction(index_temp.getlocal());
+        result.addAll(stem);
+        result.addInstruction(index_temp.getlocal());
+        result.addInstruction(arrayAccess(arrayIndexNode, OP_getproperty));
+        //  Assume this is the result.
+        result.addInstruction(OP_dup);
+        result.addInstruction(failure_test, tail);
+
+        //  Pop the speculative result and assign the correct one.
+        result.addInstruction(OP_pop);
+        result.addAll(expr);
+
+        result.labelNext(tail);
+        Binding value_temp = null;
+        if ( need_value )
+        {
+            value_temp = currentScope.allocateTemp();
+            result.addInstruction(OP_dup);
+            result.addInstruction(value_temp.setlocal());
+        }
+        result.addInstruction(arrayAccess(arrayIndexNode, OP_setproperty));
+        if ( need_value )
+        {
+            result.addInstruction(value_temp.getlocal());
+            currentScope.releaseTemp(value_temp);
+        }
+
+        currentScope.releaseTemp(index_temp);
+
+        return result;
+    }
+
+    /**
+     *  Generate a compound logical assignment expression to a foo.bar type lvalue
+     *  @param iNode - the assignment operator (root of the subtree).
+     *  @param stem - the expression that generates the lvalue's stem, e.g., a in a[i]
+     *  @param index - the index expression.
+     *  @param expr - the expression to assign.
+     *  @param is_and - true if the expression is &amp;&amp;=, false if it's ||=.
+     *  @param need_value - true if the expression's not used in a void context.
+     */
+    InstructionList generateCompoundLogicalMemberAssignment(IASNode iNode, InstructionList stem, Binding member, InstructionList expr, int fetch_opcode, boolean is_and, boolean need_value)
+    {
+        InstructionList result = createInstructionList(iNode);
+        int failure_test = is_and? OP_iffalse : OP_iftrue;
+        currentScope.getMethodBodySemanticChecker().checkCompoundAssignment(iNode, member, failure_test);
+
+        Label tail = new Label();
+
+        result.addAll(replicate(stem));
+        result.addAll(stem);
+        result.addInstruction(OP_getproperty, member.getName());
+        //  Assume this is the result.
+        result.addInstruction(OP_dup);
+        result.addInstruction(failure_test, tail);
+
+        result.addInstruction(OP_pop);
+        result.addAll(expr);
+
+        result.labelNext(tail);
+        Binding value_temp = null;
+
+        if ( need_value )
+        {
+            value_temp = currentScope.allocateTemp();
+            result.addInstruction(OP_dup);
+            result.addInstruction(value_temp.setlocal());
+        }
+
+        result.addInstruction(getAssignmentOpcode(iNode, member), member.getName());
+
+        if ( need_value )
+        {
+            result.addInstruction(value_temp.getlocal());
+            currentScope.releaseTemp(value_temp);
+        }
+
+        return result;
+
+    }
+
+    /**
+     *  generateFunctionBody() wrapper suitable for calling from the BURM.
+     *  See JBurg ENHRQ <N> : the grammar that accepts the BURM's parameters
+     *  to a JBurg.Reduction routine doesn't grok function calls, so the BURM
+     *  cannot call generateFunctionBody(body, name.getName());
+     */
+    InstructionList generateFunctionBody(IASNode iNode, InstructionList function_body, Binding return_type)
+    {
+        return generateFunctionBody(iNode, function_body, return_type != null? return_type.getName(): null);
+    }
+
+    /**
+     *  Generate boilerplate function prolog/epilog code.
+     *  @param block - the actual CFG.
+     *  @param return_type - the function's return type.
+     *  @return the function body.
+     */
+    InstructionList generateFunctionBody(IASNode iNode, InstructionList function_body, Name return_type)
+    {
+        currentScope.getMethodBodySemanticChecker().checkFunctionBody(iNode);
+
+        currentScope.getMethodInfo().setReturnType(return_type);
+        InstructionList result = currentScope.finishMethodDeclaration( !function_body.isEmpty() || haveInstanceInitializers(), SemanticUtils.getFileName(iNode));
+
+        //  Constructor-specific processing: add the instance initializers,
+        //  add a constructsuper call if none exists.
+        if ( haveInstanceInitializers() && currentScope.getNestingState() == NestingState.NotNested)
+        {
+            result.addAll(this.instanceInitializers);
+
+            //  If this is a constructor and there's no explicit
+            //  super() call, synthesize one.
+            //  Note that this may be a semantic error if the 
+            //  superclass' constructor needs arguments.
+            if ( !function_body.hasSuchInstruction(OP_constructsuper) )
+            {
+                currentScope.getMethodBodySemanticChecker().checkDefaultSuperCall(iNode);
+                //  Call the superclass' constructor after the instance
+                //  init instructions; this doesn't seem like an abstractly
+                //  correct sequence, but it's what ASC does.
+                result.addInstruction(OP_getlocal0);
+                result.addInstruction(OP_constructsuper, 0);
+            }
+        }
+
+        result.addAll(function_body);
+
+        //  Epilog code.
+        if ( result.canFallThrough() || result.hasPendingLabels() )
+        {
+            //  Synthesize a returnvoid instruction, using the
+            //  single-purpose returnvoid so the caller can
+            //  search for it.
+
+            //  If, at some point, the MBSC walks all functions' CFGs,
+            //  then all returnvoid processing can be centralized and
+            //  this specialized Instruction will be unnecessary.
+            result.addInstruction(synthesizedReturnVoid);
+        }
+
+        return result;
+    }
+
+    /**
+     *  This returnvoid instruction is used when the reducer injects a returnvoid at
+     *  the end of a method body; the caller (with access to the MethodBodyInfo) can
+     *  create a control flow graph and search it to emit a diagnostic as appropriate.
+     */
+    public static final Instruction synthesizedReturnVoid = new NoOperandsInstruction(OP_returnvoid);
+
+    /**
+     *  Generate a named nested function.
+     *
+     *  This will generate init instructions either in controlFlow?Sensitive?Destination, or in the current scopes hoisted init instructions.
+     *  Most of the time the instuctions will go in the hoisted init instructions, but if the nested function is declared
+     *  in a 'with' or 'catch' block then the init instructions need to go into the normal controlFlow?Sensitive?Destination.
+     *
+     *  @param iNode - the function node for the nested function.
+     *  @param controlFlowSensitiveDestination - the instruction list to add instructions to
+     *  @param func_name - the function's name.
+     *  @param return_type - the function's return type.
+     *  @param function_body - the body of the function.
+     *  @pre the function's lexical scope must be at the
+     *    top of the lexical scope stack, with the declaring
+     *    function's lexical scope under it.
+     *  @post the nested function's MethodInfo is filled in,
+     *    the function body is attached to its MethodBodyInfo,
+     *    and the declaring function's initialization sequence
+     *    gets code to declare the function.
+     */
+    private void generateNestedFunction(IASNode iNode, InstructionList controlFlowSensitiveDestination, Binding func_name, Name return_type, InstructionList function_body)
+    {
+        currentScope.setFunctionName(func_name.getName().getBaseName());
+        currentScope.generateNestedFunction(generateFunctionBody(iNode, function_body, return_type));
+        //  Pull the nested function's MethodInfo out of its scope before we pop it.
+        MethodInfo nested_method_info = currentScope.getMethodInfo();
+
+        currentScope = currentScope.popFrame();
+
+        //  Initialize the nested function; add a variable 
+        //  to the containing function scope and add 
+        //  newfunction/setproperty logic to the containing
+        //  function's hoisted initialization instructions.
+        currentScope.makeVariable(func_name);
+
+        InstructionList init_insns = SemanticUtils.canNestedFunctionBeHoisted(iNode) ? currentScope.getHoistedInitInstructions() : controlFlowSensitiveDestination;
+
+        //  The containing function must be marked needsActivation() so the
+        //  binding cannot be local.
+        assert(!func_name.isLocal());
+        init_insns.addInstruction(OP_findproperty, func_name.getName());
+        init_insns.addInstruction(OP_newfunction, nested_method_info);
+        init_insns.addInstruction(OP_setproperty, func_name.getName());
+    }
+
+    /**
+     *  Generate a try/catch/finally (or try/finally) compound statement.
+     *  @param try_stmt - the body of the try block.
+     *  @param catch_blocks - associated catch blocks.
+     *    May be null if no catch blocks are present.
+     *  @param finally_stmt - the body of the finally block.
+     */
+    InstructionList generateTryCatchFinally ( InstructionList try_stmt, Vector<CatchPrototype> catch_blocks, InstructionList finally_stmt)
+    {
+        InstructionList normal_flow_fixup = new InstructionList();
+        InstructionList catch_insns = new InstructionList();
+        InstructionList final_catch = new InstructionList();
+        InstructionList finally_insns = new InstructionList();
+        InstructionList final_throw = new InstructionList();
+
+        ExceptionHandlingContext finally_context = currentScope.getFlowManager().getFinallyContext();
+
+        Label final_catch_target = final_catch.getLabel();
+
+        //  We need a local to store the caught exception.
+        Binding exception_storage = finally_context.getExceptionStorage();
+
+        Collection<Label> pending_normal_control_flow = try_stmt.stripPendingLabels();
+
+        if ( try_stmt.canFallThrough() || pending_normal_control_flow != null )
+        {
+            normal_flow_fixup.addInstruction(OP_jump, finally_context.finallyBlock);
+        }
+        else
+        {
+            //  Extend the region past a terminating
+            //  throw statement to give the AVM a
+            //  little buffer to figure out its
+            //  exception-handling regions.
+            normal_flow_fixup.addInstruction(OP_nop);
+        }
+
+        Label try_start = try_stmt.getLabel();
+        Label try_end   = normal_flow_fixup.getLastLabel();
+
+        Label finally_region_end = null;
+
+        if ( null == catch_blocks )
+        {
+            finally_region_end = try_end;
+        }
+        else
+        {
+            for ( CatchPrototype catch_proto: catch_blocks )
+            {
+
+                InstructionList catch_body = generateCatchBlock(try_start, try_end, catch_proto);
+
+                boolean is_last_catch = catch_proto.equals(catch_blocks.lastElement());
+
+                if ( catch_body.canFallThrough() )
+                {
+                    //  Signal the finally block that this execution succeeded.
+                    catch_body.addInstruction(OP_pushbyte, 0);
+                    catch_body.addInstruction(finally_context.finallyReturnStorage.setlocal());
+                    catch_body.addInstruction(OP_jump, finally_context.finallyBlock);
+                }
+                else if ( is_last_catch )
+                {
+                    //  Extend the region past a terminating throw
+                    //  insn to give the AVM a little buffer.
+                    catch_body.addInstruction(OP_nop);
+                }
+
+                if ( is_last_catch )
+                    finally_region_end = catch_body.getLastLabel();
+
+                catch_insns.addAll(catch_body);
+            }
+        }
+
+        //  Set up the exception handler for the finally block.
+        currentScope.getMethodBodyVisitor().visitException(try_start, finally_region_end, final_catch_target, null, null);
+
+        //  The final catch block only needs to save the
+        //  caught exception for a rethrow.
+        if ( currentScope.needsThis() )
+        {
+            final_catch.addInstruction(OP_getlocal0);
+            final_catch.addInstruction(OP_pushscope);
+        }
+
+        if( currentScope.needsActivation() )
+        {
+            //  Restore the activation object
+            final_catch.addInstruction(currentScope.getActivationStorage().getlocal());
+            final_catch.addInstruction(OP_pushscope);
+        }
+
+        final_catch.addAll(currentScope.getFlowManager().getScopeStackReinit());
+        final_catch.addInstruction(exception_storage.setlocal());
+        //  Signal the finally epilog that this execution failed
+        //  and should rethrow.
+        final_catch.addInstruction(OP_pushbyte, currentScope.getFlowManager().getFinallyAlternativesSize() + 1);
+        final_catch.addInstruction(finally_context.finallyReturnStorage.setlocal());
+
+        //  falls through
+        // final_catch.addInstruction(OP_jump,  finally_head);
+
+        finally_insns.addInstruction(finally_context.finallyReturnStorage.getlocal());
+        finally_insns.addInstruction(OP_convert_i);
+        finally_insns.addAll(currentScope.getFlowManager().getFinallySwitch());
+
+        //  Label the start of the final set of instructions.
+        if (!finally_stmt.isEmpty())
+        {
+            finally_stmt.labelFirst(finally_context.finallyBlock);
+        }
+        else
+            //  This is just an expedient for this degenerate finally.
+            finally_insns.labelFirst(finally_context.finallyBlock);
+
+        final_throw.addInstruction(exception_storage.getlocal());
+        final_throw.labelCurrent(finally_context.finallyDoRethrow);
+        final_throw.addInstruction(OP_throw);
+
+        //  Assemble the statement.
+        InstructionList result = new InstructionList();
+
+        result.addInstruction(OP_pushbyte, 0);
+        result.addInstruction(finally_context.finallyReturnStorage.setlocal());
+
+        result.addAll(try_stmt);
+
+        //  Send all "next statement" type control flow into the finally block.
+        result.addAllPendingLabels(pending_normal_control_flow);
+
+        result.addAll(normal_flow_fixup);
+
+        result.addAll(catch_insns);
+        result.addAll(final_catch);
+
+        result.addAll(finally_stmt);
+        result.addAll(finally_insns);
+        result.addAll(final_throw);
+
+        for ( ExceptionHandlingContext.FinallyReturn retblock: finally_context.finallyReturns )
+            result.addAll(retblock.getInstructions());
+
+        //  TODO: Need more analysis of how this temp travels through
+        //  the system before it can be safely released.  For now
+        //  just leak it.
+        //  currentScope.releaseTemp(exception_storage);
+
+        //  TODO: Removing a hanging kill exposed a latent bug 
+        //  in hasPendingLabels() and end-of-routine processing.
+        //  Give the CG a harmless instruction that will generate
+        //  a returnvoid if this is the last statement in the routine.
+        result.addInstruction(OP_nop);
+
+        //  Fallthrough out of the finally block.
+        result.labelNext(finally_context.finallyDoFallthrough);
+
+        return result;
+    }
+
+    /**
+     * Reduce a name to an instruction list that can be used in a parameterized type expression.
+     * This is different from the normal name -> expression because '*' maps to pushnull.
+     * @param iNode         the node
+     * @param param_name    the name to reduce
+     * @return              IL with instructions to push the appropriate value on the stack
+     */
+    public InstructionList reduce_typeNameParameter(IASNode iNode, Binding param_name)
+    {
+        InstructionList result = createInstructionList(iNode);
+
+        generateTypeNameParameter(param_name, result);
+
+        return result;
+    }
+
+    /**
+     *  Generate the instruction sequence that designates
+     *  the parameter of a parameterized type, e.g.,
+     *  String in Vector.&lt;String&gt; or * in Vector.&lt;*&gt;.
+     *  @param param_node - the type parameter's node.
+     *  @param param_name - the type parameter's name.
+     *    May be null in the * case.
+     *  @param result - the instruction sequence to generate into.
+     */
+    private void generateTypeNameParameter(Binding param, InstructionList result)
+    {
+        if ( param == null || param.getName() == null || param.getName().couldBeAnyType() )
+            result.addInstruction(OP_pushnull);
+        else
+            generateAccess(param, false, AccessType.Strict, result);
+    }
+
+    /**
+     * @return A
+     * {@link ControlFlowContextManager.ControlFlowContextSearchCriteria} that
+     * will find the control context that a break statement without a label in
+     * the current control flow context refers to. This should always be a
+     * control flow context for any of:
+     * <ul>
+     * <li>a labeled statement</li>
+     * <li>a loop</li>
+     * <li>a switch statement</li>
+     * </ul>
+     */
+    private ControlFlowContextManager.ControlFlowContextSearchCriteria getBreakCriteria()
+    {
+        return ControlFlowContextManager.breakWithOutLabelCriteria;
+    }
+    
+    /**
+     * @return A
+     * {@link ControlFlowContextManager.ControlFlowContextSearchCriteria} that
+     * will find the control context that a continue statement without a label
+     * in the current control flow context refers to. This should always be a
+     * control flow context for a loop.
+     */
+    private ControlFlowContextManager.ControlFlowContextSearchCriteria getContinueCriteria()
+    {
+        return ControlFlowContextManager.continueWithOutLabelCriteria;
+    }
+    
+    /**
+     * @param Label name in a break statement with a label.
+     * @return A
+     * {@link ControlFlowContextManager.ControlFlowContextSearchCriteria} that
+     * will find the control context that a break statement with a label in the
+   

<TRUNCATED>

Mime
View raw message