You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by cd...@apache.org on 2014/07/22 15:36:06 UTC

[40/51] [partial] - Migrated the directory structure to a more Maven style structure. - Started migrating the Parser from Antlr2+3 and JFlex to Antlr4.

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/59f6373b/compiler/src/main/java/org/apache/flex/abc/optimize/PeepholeOptimizerMethodBodyVisitor.java
----------------------------------------------------------------------
diff --git a/compiler/src/main/java/org/apache/flex/abc/optimize/PeepholeOptimizerMethodBodyVisitor.java b/compiler/src/main/java/org/apache/flex/abc/optimize/PeepholeOptimizerMethodBodyVisitor.java
new file mode 100644
index 0000000..1b03a94
--- /dev/null
+++ b/compiler/src/main/java/org/apache/flex/abc/optimize/PeepholeOptimizerMethodBodyVisitor.java
@@ -0,0 +1,1520 @@
+/*
+ *
+ *  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.abc.optimize;
+
+import static 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.visitors.DelegatingMethodBodyVisitor;
+import org.apache.flex.abc.visitors.IMethodBodyVisitor;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * IMethodBodyVisitor that will do peephole optimization of the method body.
+ * TODO: Not copmlete yet - should be equivalent to the peephole optimizer in
+ * MXMLC 4.5 Optimizations implemented: Eliminate unnecessary convert_d
+ * instructions Eliminate unnecessary convert_b instructions Eliminate
+ * unnecessary convert_i instructions Eliminate unnecessary convert_s
+ * instructions Eliminate unnecessary convert_u instructions Replace callprops
+ * where the return value is unused, with callpropvoid
+ */
+public class PeepholeOptimizerMethodBodyVisitor extends DelegatingMethodBodyVisitor
+{
+    /**
+     * How many instructions we can look back on
+     */
+    private static final int PEEPHOLE_WINDOW_SIZE = 4;
+
+    /**
+     * Constant that means we don't have any labels in the peephole window
+     */
+    private static final int NO_LABEL = -1;
+
+    public PeepholeOptimizerMethodBodyVisitor(IMethodBodyVisitor delegate)
+    {
+        super(delegate);
+    }
+
+    /**
+     * Hold a small window of previous instructions so that the optimizer can
+     * rewind and rewrite small sections of ABC
+     */
+    private List<InstructionInfo> instructions = new LinkedList<InstructionInfo>();
+
+    /**
+     * The index of the instruction with the most recently seen label - we can't
+     * look back past a label.
+     */
+    private int lastLabelSeen = NO_LABEL;
+
+    /**
+     * If we delete instructions that have labeling actions associated with
+     * them, we have to apply those labeling instructions to whatever
+     * instruction ends up replacing the deleted instruction(s). This list holds
+     * those labels.
+     */
+    private List<Label> labelsFromDeletedInsns = null;
+
+    /**
+     * basically holds a function object that sends instructions on to the right
+     * place once the peephole optimizer is finished. This will either send the
+     * instructions on to the next IMethodBodyVisitor, or to a new
+     * InstructionList
+     */
+    private InstructionFinisher finisher = new DelegateFinisher();
+
+    /**
+     * Resets the entire method body at once. The Peephole optimizer will
+     * process the entire instruction list, performing it's optimizations,
+     * before passing the InstructionList down to the next IMethodBodyVisitor. So
+     * any MethodBodyVisitors that the optimizer delegates to will receive a new
+     * InstructionList, with optimizations, instead of the InstructionList
+     * passed in.
+     * 
+     * @param new_list The new Instructions for the method.
+     */
+    @Override
+    public void visitInstructionList(InstructionList new_list)
+    {
+        // for the delegates that run after this IVisitor, they will be processing
+        // a new copy of the instruction list, which will have the optimized opcodes
+        InstructionList newInstructions = new InstructionList();
+        InstructionFinisher old = this.finisher;
+
+        // Create a new finisher, which will put the instruction into a new InstructionList
+        // instead of passing them on to the next delegate
+        this.finisher = new InstructionListFinisher(newInstructions);
+        for (Instruction inst : new_list.getInstructions())
+        {
+            visitInstruction(inst);
+        }
+        // Make sure we flush any remaining instructions to the IL
+        flush();
+
+        // delegate the call with the new instruction list
+        super.visitInstructionList(newInstructions);
+
+        // Reset the finisher to the delegating one
+        this.finisher = old;
+    }
+
+    @Override
+    public void visitInstruction(int opcode)
+    {
+        visitInstruction(InstructionFactory.getInstruction(opcode));
+
+    }
+
+    @Override
+    public void visitInstruction(int opcode, int immediate_operand)
+    {
+        visitInstruction(InstructionFactory.getInstruction(opcode, immediate_operand));
+    }
+
+    @Override
+    public void visitInstruction(int opcode, Object[] operands)
+    {
+        visitInstruction(InstructionFactory.getInstruction(opcode, operands));
+    }
+
+    @Override
+    public void visitInstruction(int opcode, Object single_operand)
+    {
+        visitInstruction(InstructionFactory.getInstruction(opcode, single_operand));
+    }
+
+    @Override
+    /**
+     * Add the instruction to our peephole window and performs any optimizations.
+     *
+     * The optimizations are performed on the instructions already in the window - we do them
+     * now, and not when they are added, because we need to know if any labels targeted the instructions
+     * and we don't know that when we first see the instruction (but we do when we see the next instruction)
+     * @param instruction  the Instruction to add
+     */
+    public void visitInstruction(Instruction instruction)
+    {
+        // Optimize the instructions we already have
+        processPreviousInstructions();
+
+        // add the instruction, but don't do any optimizations yet
+        addInstruction(instruction);
+    }
+
+    /**
+     * Perform optimizations on the instructions currently held in the window.
+     * This is so we don't do the optimizations until we are sure a particular
+     * instruction was or was not the target of a jump. If it was a target, then
+     * we don't do the optimizations as we don't have enough information to
+     * determine all the ways control might flow to that instruction.
+     */
+    private void processPreviousInstructions()
+    {
+        InstructionInfo last = previous(0);
+        InstructionInfo secondLast = previous(1);
+
+        // Check if we have a labelCurrent on the last instruction, or a labelNext on the previous instruction
+        if (last.getLabelCurrents().isEmpty() && secondLast.getLabelNexts().isEmpty())
+        {
+            switch (last.getOpcode())
+            {
+                case OP_convert_b:
+                {
+                    op_convert_b(last);
+                    break;
+                }
+                case OP_convert_d:
+                {
+                    op_convert_d(last);
+                    break;
+                }
+                case OP_convert_i:
+                {
+                    op_convert_i(last);
+                    break;
+                }
+                case OP_convert_u:
+                {
+                    op_convert_u(last);
+                    break;
+                }
+                case OP_convert_s:
+                {
+                    op_convert_s(last);
+                    break;
+                }
+                case OP_getproperty:
+                {
+                    op_getproperty(last);
+                    break;
+                }
+                case OP_iffalse:
+                {
+                    op_iffalse(last);
+                    break;
+                }
+                case OP_iftrue:
+                {
+                    op_iftrue(last);
+                    break;
+                }
+                case OP_pop:
+                {
+                    op_pop(last);
+                    break;
+                }
+                case OP_nop:
+                {
+                    delete(0);
+                    break;
+                }
+                case OP_getlocal:
+                {
+                    OP_getlocal(last);
+                    break;
+                }
+                case OP_returnvoid:
+                {
+                    op_returnvoid(last);
+                    break;
+                }
+                default:
+                {
+                    break;
+                }
+            }
+        }
+    }
+
+    public void visitEnd()
+    {
+        flush();
+        super.visitEnd();
+    }
+
+    /**
+     * Flush any remaining instructions
+     */
+    private void flush()
+    {
+        processPreviousInstructions();
+        
+        // finish any remaining instructions
+        for (InstructionInfo info : instructions)
+        {
+            finishInstruction(info);
+        }
+        
+        instructions.clear();
+    }
+
+    /**
+     * Bind a Label object (not to be confused with the AVM OP_label
+     * instruction) to the last-visited ABC instruction in this method.
+     * 
+     * @pre visitInstruction() must have been called at least once, i.e., there
+     * must be a last-visited ABC instruction.
+     */
+    public void labelCurrent(Label l)
+    {
+        jumpOptimizations(l, LabelKind.LABEL_CURRENT);
+
+        int idx = getLastInstructionIndex();
+        InstructionInfo instructionInfo = instructions.get(idx);
+        lastLabelSeen = idx;
+        instructionInfo.addLabelCurrent(l);
+    }
+
+    /**
+     * Enum to pass around to indicate what kind of labeling operation we are
+     * performing
+     */
+    private static enum LabelKind
+    {
+        LABEL_CURRENT,
+        LABEL_NEXT
+    }
+
+    /**
+     * Helper method to perform optimizations around jumps when we get a
+     * labeling operation. Shared with labelNext and labelCurrent methods
+     * 
+     * @param l the Label object passed into the label operation
+     * @param kind what kind of labeling operation are we doing (labelNext or
+     * labelCurrent)
+     */
+    private void jumpOptimizations(Label l, LabelKind kind)
+    {
+        // Need to start looking at different indexes for label current vs. label next
+        // this is because for a label next, the next instruction won't have come in yet.
+        int idx = kind == LabelKind.LABEL_CURRENT ? 1 : 0;
+
+        InstructionInfo prev = previous(idx);
+        switch (prev.getOpcode())
+        {
+            case OP_jump:
+            {
+                InstructionInfo prev2 = previous(idx + 1);
+                Instruction insn = prev2.getInstruction();
+                if (insn != null && insn.isBranch() && insn.getTarget() == l)
+                {
+                    // If the previous instructions were an if that jumped here, and it
+                    // only jumped over another jump, then we can invert the if instruction
+                    // and save a jump
+                    //   iffalse L1, jump L2, L1    -> iftrue L2, L1
+                    Instruction newIf = invertIf(prev2, prev);
+                    if (newIf != null)
+                    {
+                        if (kind == LabelKind.LABEL_CURRENT)
+                        {
+                            // labelCurrent, so we need to preserve the last instruction
+                            Instruction[] newInsns = {newIf, previous(0).getInstruction()};
+                            replace(idx + 1, newInsns);
+                        }
+                        else
+                        {
+                            // labelNext so we can just delete the last instruction
+                            replace(idx + 1, newIf);
+                        }
+                    }
+                }
+                // If the previous instruction was a jump, and it just jumped
+                // to the next instruction, then we can remove the jump and just fall
+                // through
+                //   jump L1, L1 -> L1
+                else if (prev.getOperand(0) == l)
+                {
+                    if (kind == LabelKind.LABEL_NEXT)
+                        // can just delete the jump because we don't have the next instruction yet
+                        delete(idx);
+                    else
+                        // replace the jump with its target
+                        replace(idx, previous(0).getInstruction());
+                }
+            }
+        }
+    }
+
+    /**
+     * Helper method to invert if expr target jump other-target to if not expr
+     * other-target Used to optimize some common patterns with if's and jumps
+     */
+    private Instruction invertIf(InstructionInfo oldIf, InstructionInfo oldJump)
+    {
+        Instruction newIf = null;
+        switch (oldIf.getOpcode())
+        {
+            case OP_ifeq:
+            {
+                newIf = InstructionFactory.createModifiedInstruction(OP_ifne, oldJump.getInstruction());
+                break;
+            }
+            case OP_ifstricteq:
+            {
+                newIf = InstructionFactory.createModifiedInstruction(OP_ifstrictne, oldJump.getInstruction());
+                break;
+            }
+            case OP_ifstrictne:
+            {
+                newIf = InstructionFactory.createModifiedInstruction(OP_ifstricteq, oldJump.getInstruction());
+                break;
+            }
+            case OP_ifge:
+            {
+                newIf = InstructionFactory.createModifiedInstruction(OP_ifnge, oldJump.getInstruction());
+                break;
+            }
+            case OP_ifgt:
+            {
+                newIf = InstructionFactory.createModifiedInstruction(OP_ifngt, oldJump.getInstruction());
+                break;
+            }
+            case OP_iflt:
+            {
+                newIf = InstructionFactory.createModifiedInstruction(OP_ifnlt, oldJump.getInstruction());
+                break;
+            }
+            case OP_ifle:
+            {
+                newIf = InstructionFactory.createModifiedInstruction(OP_ifnle, oldJump.getInstruction());
+                break;
+            }
+            case OP_ifne:
+            {
+                newIf = InstructionFactory.createModifiedInstruction(OP_ifeq, oldJump.getInstruction());
+                break;
+            }
+            case OP_ifnge:
+            {
+                newIf = InstructionFactory.createModifiedInstruction(OP_ifge, oldJump.getInstruction());
+                break;
+            }
+            case OP_ifngt:
+            {
+                newIf = InstructionFactory.createModifiedInstruction(OP_ifgt, oldJump.getInstruction());
+                break;
+            }
+            case OP_ifnlt:
+            {
+                newIf = InstructionFactory.createModifiedInstruction(OP_iflt, oldJump.getInstruction());
+                break;
+            }
+            case OP_ifnle:
+            {
+                newIf = InstructionFactory.createModifiedInstruction(OP_ifle, oldJump.getInstruction());
+                break;
+            }
+            case OP_iftrue:
+            {
+                newIf = InstructionFactory.createModifiedInstruction(OP_iffalse, oldJump.getInstruction());
+                break;
+            }
+            case OP_iffalse:
+            {
+                newIf = InstructionFactory.createModifiedInstruction(OP_iftrue, oldJump.getInstruction());
+                break;
+            }
+        }
+        
+        return newIf;
+    }
+
+    /**
+     * Helper method to get the index of the last instruction in the window
+     * 
+     * @return the index of the last instruction
+     */
+    private int getLastInstructionIndex()
+    {
+        return instructions.size() - 1;
+    }
+
+    /**
+     * Bind a Label object (not to be confused with the AVM OP_label
+     * instruction) to the next ABC instruction that gets visited in this method
+     * 
+     * @post visitInstruction() must be called at least once after labelNext,
+     * i.e., there must be a next instruction.
+     */
+    public void labelNext(Label l)
+    {
+        jumpOptimizations(l, LabelKind.LABEL_NEXT);
+
+        int idx = getLastInstructionIndex();
+        instructions.get(idx).addLabelNext(l);
+        lastLabelSeen = idx + 1;
+    }
+
+    /**
+     * Fetch a previous instruction from the peephole window
+     * 
+     * @param i the index of the previous instruction. 0 is the last instruction
+     * processed (so the immediately preceeding instruction), and
+     * PEEPHOLE_WINDOW_SIZE-1 is the oldest instruction that can be fetched.
+     * @return the InstructionInfo for some previous instruction, or the
+     * noInstruction object if i falls outside of the peephole window
+     */
+    private InstructionInfo previous(int i)
+    {
+        int size = instructions.size();
+        int idx = i + 1;
+        if (size >= idx)
+        {
+            int realIdx = size - idx;
+
+            // Can't look back past a label
+            if (indexBeforeLabel(realIdx))
+                return noInstruction;
+
+            return instructions.get(realIdx);
+        }
+        return noInstruction;
+    }
+
+    /**
+     * Helper method to determine if the index passed in occurrs before the last
+     * label instruction in the window
+     */
+    private boolean indexBeforeLabel(int idx)
+    {
+        return lastLabelSeen != NO_LABEL
+                // if we did a label next we can still look back until that
+                // next instruction comes in
+                && lastLabelSeen < PEEPHOLE_WINDOW_SIZE
+                && idx < lastLabelSeen;
+    }
+
+    /**
+     * Replace the previous instruction(s), from the end of the peephole window
+     * up to i with a new Instruction. It will replace all the previous
+     * instructions through i. Must not be called with an index that falls
+     * outside of the peephole window.
+     * 
+     * @param i the index of the previous instruction to replace. Follows the
+     * same indexing strategy as the previous() method 0 is the last instruction
+     * in the window, 1 is two instructions ago, up to PEEPHOLE_WINDOW_SIZE-1
+     * which is the oldest instruction that can be replaced.
+     * @param insn The new instruction to insert at i
+     */
+    private void replace(int i, Instruction insn)
+    {
+        Instruction[] newInsns = {insn};
+        replace(i, newInsns);
+    }
+
+    /**
+     * Replace the previous instruction(s), from the end of the peephole window
+     * up to i with a new Instruction sequence. It will replace all the previous
+     * instructions through i. Must not be called with an index that falls
+     * outside of the peephole window.
+     * 
+     * @param i the index of the previous instruction to replace. Follows the
+     * same indexing strategy as the previous() method 0 is the last instruction
+     * in the window, 1 is two instructions ago, up to PEEPHOLE_WINDOW_SIZE-1
+     * which is the oldest instruction that can be replaced.
+     * @param insns The new instruction sequence to insert at i
+     */
+    private void replace(int i, Instruction[] insns)
+    {
+        if (insns.length == 0)
+            return;
+
+        int size = instructions.size();
+        int idx = i + 1;
+        if (size >= idx)
+        {
+            int realIdx = size - idx;
+
+            assert !indexBeforeLabel(realIdx) : "Attempting to replace instruction sequence that spans a label";
+
+            // replace the instruction
+            InstructionInfo info = instructions.get(realIdx);
+            info.setInstruction(insns[0]);
+
+            // Delete any remaining instructions, saving the list of labelNexts from the last deleted
+            // instruction
+            List<Label> labelNexts = null;
+            for (int r = size - 1; r >= (realIdx + 1); --r)
+            {
+                InstructionInfo temp = instructions.remove(r);
+                if (r == size - 1)
+                {
+                    // Save the labelNexts from the last deleted instruction
+                    labelNexts = temp.getLabelNexts();
+                }
+            }
+
+            // Add the remaining instructions
+            for (int r = 1, l = insns.length; r < l; ++r)
+                addInstruction(insns[r]);
+
+            if (labelNexts != null)
+            {
+                // Apply any saved labelNexts to the last instruction added
+                for (Label l : labelNexts)
+                    labelNext(l);
+            }
+        }
+        else
+        {
+            assert false : "Trying to replace instructions that fall outside the peephole window";
+        }
+    }
+
+    /**
+     * Delete the previous instruction(s), from the end of the peephole window
+     * up to i. Must not be called with an index that falls outside of the
+     * peephole window.
+     * 
+     * @param i the index of the previous instruction to replace. Follows the
+     * same indexing strategy as the previous() method 0 is the last instruction
+     * in the window, 1 is two instructions ago, up to PEEPHOLE_WINDOW_SIZE-1
+     * which is the oldest instruction that can be replaced.
+     */
+    private void delete(int i)
+    {
+        int size = instructions.size();
+        int idx = i + 1;
+        if (size >= idx)
+        {
+            int realIdx = size - idx;
+
+            assert !indexBeforeLabel(realIdx) : "Attempting to delete instruction sequence that spans a label";
+
+            List<Label> labels = null;
+
+            for (int r = size - 1; r >= realIdx; --r)
+            {
+                InstructionInfo temp = instructions.remove(r);
+
+                if (r == size - 1)
+                {
+                    // Save any label nexts from the last deleted instruction
+                    List<Label> labelNexts = temp.getLabelNexts();
+                    if (!labelNexts.isEmpty())
+                    {
+                        if (labels == null)
+                            labels = new ArrayList<Label>();
+                        labels.addAll(labelNexts);
+                    }
+                }
+                else if (r == realIdx)
+                {
+                    // save any label currents from the first deleted instruction
+                    List<Label> labelCurrents = temp.getLabelCurrents();
+                    if (!labelCurrents.isEmpty())
+                    {
+                        if (labels == null)
+                            labels = new ArrayList<Label>();
+                        labels.addAll(labelCurrents);
+                    }
+                }
+            }
+            if (labels != null)
+            {
+                if (labelsFromDeletedInsns == null)
+                    labelsFromDeletedInsns = labels;
+                else
+                    labelsFromDeletedInsns.addAll(labels);
+            }
+        }
+        else
+        {
+            assert false : "Trying to delete instructions that fall outside the peephole window";
+        }
+    }
+
+    /**
+     * InstructionInfo to represent noInstruction - used when we look back past
+     * the size of the peephole window
+     */
+    private static InstructionInfo noInstruction = new InstructionInfo();
+
+    /**
+     * Optimizations for OP_convert_b: equals, convert_b -> equals strictequals,
+     * convert_b -> strictequals not, convert_b -> not greaterthan, convert_b ->
+     * greaterthan lessthan, convert_b -> lessthan greaterequals, convert_b ->
+     * greaterequals lessequals, convert_b -> lessequals istype, convert_b ->
+     * istype istypelate, convert_b -> istypelate instanceof, convert_b ->
+     * instanceof deleteproperty, convert_d -> deleteproperty in, convert_d ->
+     * in convert_b, convert_b -> convert_b pushtrue, convert_b -> pushtrue
+     * pushfalse, convert_b -> pushfalse
+     * 
+     * @param i The convert_b instruction
+     */
+    private void op_convert_b(InstructionInfo i)
+    {
+        InstructionInfo prev = previous(1);
+        switch (prev.getOpcode())
+        {
+            case OP_equals:
+            case OP_strictequals:
+            case OP_not:
+            case OP_greaterthan:
+            case OP_lessthan:
+            case OP_greaterequals:
+            case OP_lessequals:
+            case OP_istype:
+            case OP_istypelate:
+            case OP_instanceof:
+            case OP_deleteproperty:
+            case OP_in:
+            case OP_convert_b:
+            case OP_pushtrue:
+            case OP_pushfalse:
+            {
+                // result is already a boolean, just erase the op_convert_b
+                delete(0);
+                break;
+            }
+            default:
+            {
+                // nothing to do - instruction has already been added
+            }
+        }
+    }
+
+    /**
+     * Optimizations for OP_convert_d: convert_d, convert_d -> convert_d
+     * pushbyte n, convert_d -> pushdouble n pushint n, convert_d -> pushdouble
+     * n pushuint n, convert_d -> pushdouble n pushdouble n, convert_d ->
+     * pushdouble n pushnan, convert_d -> pushnan lf32, convert_d -> lf32 lf64,
+     * convert_d -> lf64
+     * 
+     * @param i The convert_d instruction
+     */
+    private void op_convert_d(InstructionInfo i)
+    {
+        InstructionInfo prev = previous(1);
+        switch (prev.getOpcode())
+        {
+            case OP_pushbyte:
+            {
+                // replace pushbyte, convert d with pushdouble - should be faster
+                replace(1, InstructionFactory.getInstruction(OP_pushdouble, new Double(convertByteImmediateToDouble(prev.getImmediate()))));
+                break;
+            }
+            case OP_pushint:
+            case OP_pushuint:
+            {
+                // replace pushint , convert d with pushdouble - should be faster
+                replace(1, InstructionFactory.getInstruction(OP_pushdouble, new Double(((Number)prev.getOperand(0)).doubleValue())));
+                break;
+            }
+            case OP_pushdouble:
+            case OP_pushnan:
+            case OP_lf32:
+            case OP_lf64:
+            case OP_convert_d:
+            {
+                // result is already a double, just erase the op_convert_d
+                delete(0);
+                break;
+            }
+            default:
+            {
+                // nothing to do - instruction has already been added
+            }
+        }
+    }
+
+    /**
+     * Optimizations for OP_convert_i: convert_i, convert_i -> convert_i
+     * coerce_i, convert_i -> coerce_i OP_bitand, convert_i -> OP_bitand
+     * OP_bitor, convert_i -> OP_bitor OP_bitxor, convert_i -> OP_bitxor lshift,
+     * convert_i -> lshift rshift, convert_i -> rshift add_i, convert_i -> add_i
+     * subtract_i, convert_i -> subtract_i increment_i, convert_i -> increment_i
+     * decrement_i, convert_i -> decrement_i multiply_i, convert_i -> multiply_i
+     * pushbyte, convert_i -> pushbyte pushshort, convert_i -> pushshort
+     * pushint, convert_i -> pushint li8, convert_i -> li8 li16, convert_i ->
+     * li16 li32, convert_i -> li32 sxi1, convert_i -> sxi1 sxi8, convert_i ->
+     * sxi8 sxi16, convert_i -> sxi16
+     * 
+     * @param i The convert_b instruction
+     */
+    private void op_convert_i(InstructionInfo i)
+    {
+        InstructionInfo prev = previous(1);
+        switch (prev.getOpcode())
+        {
+            case OP_convert_i:
+            case OP_coerce_i:
+            case OP_bitand:
+            case OP_bitor:
+            case OP_bitxor:
+            case OP_lshift:
+            case OP_rshift:
+            case OP_add_i:
+            case OP_subtract_i:
+            case OP_increment_i:
+            case OP_decrement_i:
+            case OP_multiply_i:
+            case OP_pushbyte:
+            case OP_pushshort:
+            case OP_pushint:
+            case OP_li8:
+            case OP_li16:
+            case OP_li32:
+            case OP_sxi1:
+            case OP_sxi8:
+            case OP_sxi16:
+            {
+                // result is already an int, just erase the op_convert_i
+                delete(0);
+                break;
+            }
+            default:
+            {
+                // nothing to do - instruction has already been added
+            }
+        }
+    }
+
+    /**
+     * Optimizations for OP_convert_s: coerce_s, convert_s -> coerce_s
+     * convert_s, convert_s -> convert_s pushstring, convert_s -> pushstring
+     * typeof, convert_s -> typeof
+     * 
+     * @param i The convert_b instruction
+     */
+    private void op_convert_s(InstructionInfo i)
+    {
+        InstructionInfo prev = previous(1);
+        switch (prev.getOpcode())
+        {
+            case OP_coerce_s:
+            case OP_convert_s:
+            case OP_pushstring:
+            case OP_typeof:
+            {
+                // result is already a String, just erase the op_convert_s
+                delete(0);
+                break;
+            }
+            default:
+            {
+                // nothing to do - instruction has already been added
+            }
+        }
+    }
+
+    /**
+     * Optimizations for OP_convert_i: convert_u, convert_u -> convert_u
+     * pushuint, convert_u -> pushuint
+     * 
+     * @param i The convert_b instruction
+     */
+    private void op_convert_u(InstructionInfo i)
+    {
+        InstructionInfo prev = previous(1);
+        switch (prev.getOpcode())
+        {
+            case OP_convert_u:
+            case OP_pushuint:
+            {
+                // result is already a uint, just erase the op_convert_u
+                delete(0);
+                break;
+            }
+            default:
+            {
+                // nothing to do - instruction has already been added
+            }
+        }
+    }
+
+    /**
+     * Optimizations for OP_getproperty: findpropstrict name, getproperty name
+     * -> getlex name
+     * 
+     * @param i the getproperty instruction
+     */
+    private void op_getproperty(InstructionInfo i)
+    {
+        InstructionInfo prev = previous(1);
+        switch (prev.getOpcode())
+        {
+            case OP_findpropstrict:
+            {
+                // can optimize findpropstrict, followed by getprop of the same name
+                // if there are any instructions btwn the findpropstrict and getprop (such as to compute a runtime
+                // multiname), we won't match this pattern
+                if (i.getOperand(0).equals(prev.getOperand(0)))
+                    replace(1, InstructionFactory.createModifiedInstruction(OP_getlex, prev.getInstruction()));
+                break;
+            }
+        }
+    }
+
+    /**
+     * Optimizations for OP_iffalse: convert_b, iffalse -> iffalse equals,
+     * iffalse -> ifne strictequals, iffalse -> strictne lessthen, iffalse ->
+     * ifnlt lessequals, iffalse -> ifnle greaterthan, iffalse -> ifngt
+     * greaterequals, iffalse -> ifnge pushfalse, iffalse -> jump pushtrue,
+     * iffalse -> nothing strictequals, not, iffalse -> ifstrictequals equals,
+     * not, iffalse -> ifeq lessthan, not, iffalse -> iflt lessequals, not,
+     * iffalse -> ifle greaterthan, not, iffalse -> ifgt greaterequals,
+     * not,iffalse -> ifge not, iffalse -> iftrue
+     * 
+     * @param i the iffalse instruction
+     */
+    private void op_iffalse(InstructionInfo i)
+    {
+        InstructionInfo prev = previous(1);  
+        
+        // Check if we know what's on the stack. If so, we don't need
+        // to do a conditional branch
+        switch(isTrueInstructionInfo(prev))
+        {
+            case TRUE:
+                delete(1);          // if we can't branch, just eat the push / iffalse instructions
+                return;
+            case FALSE:
+                replace(1, InstructionFactory.createModifiedInstruction(OP_jump, i.getInstruction()));
+                    // If we always branch, then replace the push / iffalse with an uncontidional jump
+                return;
+            case DONT_KNOW:
+                break;             // continue on if we don't know it's a constant boolean
+            default:
+                assert false;
+                
+        }
+        switch (prev.getOpcode())
+        {
+            case OP_convert_b:
+            {
+                // replace with just iffalse
+                replace(1, i.getInstruction());
+                break;
+            }
+            case OP_equals:
+            {
+                replace(1, InstructionFactory.createModifiedInstruction(OP_ifne, i.getInstruction()));
+                break;
+            }
+            case OP_strictequals:
+            {
+                replace(1, InstructionFactory.createModifiedInstruction(OP_ifstrictne, i.getInstruction()));
+                break;
+            }
+            case OP_lessthan:
+            {
+                replace(1, InstructionFactory.createModifiedInstruction(OP_ifnlt, i.getInstruction()));
+                break;
+            }
+            case OP_lessequals:
+            {
+                replace(1, InstructionFactory.createModifiedInstruction(OP_ifnle, i.getInstruction()));
+                break;
+            }
+            case OP_greaterthan:
+            {
+                replace(1, InstructionFactory.createModifiedInstruction(OP_ifngt, i.getInstruction()));
+                break;
+            }
+            case OP_greaterequals:
+            {
+                replace(1, InstructionFactory.createModifiedInstruction(OP_ifnge, i.getInstruction()));
+                break;
+            }
+           
+            case OP_not:
+            {
+                InstructionInfo prev2 = previous(2);
+                switch (prev2.getOpcode())
+                {
+                    case OP_strictequals:
+                    {
+                        replace(2, InstructionFactory.createModifiedInstruction(OP_ifstricteq, i.getInstruction()));
+                        break;
+                    }
+                    case OP_equals:
+                    {
+                        replace(2, InstructionFactory.createModifiedInstruction(OP_ifeq, i.getInstruction()));
+                        break;
+                    }
+                    case OP_lessthan:
+                    {
+                        replace(2, InstructionFactory.createModifiedInstruction(OP_iflt, i.getInstruction()));
+                        break;
+                    }
+                    case OP_lessequals:
+                    {
+                        replace(2, InstructionFactory.createModifiedInstruction(OP_ifle, i.getInstruction()));
+                        break;
+                    }
+                    case OP_greaterthan:
+                    {
+                        replace(2, InstructionFactory.createModifiedInstruction(OP_ifgt, i.getInstruction()));
+                        break;
+                    }
+                    case OP_greaterequals:
+                    {
+                        replace(2, InstructionFactory.createModifiedInstruction(OP_ifge, i.getInstruction()));
+                        break;
+                    }
+                    default:
+                    {
+                        replace(1, InstructionFactory.createModifiedInstruction(OP_iftrue, i.getInstruction()));
+                        break;
+                    }
+                }
+                break;
+            }
+
+            default:
+            {
+                // nothing to do, instruction was already added
+            }
+        }
+    }
+    
+  
+    /**
+     * Optimizations for OP_iftrue: convert_b, iftrue -> iftrue equals, iftrue
+     * -> ifeq strictequals, iftrue -> ifstricteq lessthen, iftrue -> iflt
+     * lessequals, iftrue -> ifle greaterthan, iftrue -> ifgt greaterequals,
+     * iftrue -> ifge pushfalse, iftrue -> jump pushtrue, iftrue -> nothing
+     * strictequals, not, iftrue -> ifstrictne equals, not, iftrue -> ifne
+     * lessthan, not, iftrue -> ifnlt lessequals, not, iftrue -> ifnle
+     * greaterthan, not, iftrue -> ifngt greaterequals, not,iftrue -> ifnge not,
+     * iftrue -> iffalse
+     * 
+     * @param i the iftrue instruction
+     */
+    private void op_iftrue(InstructionInfo i)
+    {
+        InstructionInfo prev = previous(1);
+        
+        
+        switch(isTrueInstructionInfo(prev))
+        {
+            case FALSE:
+                delete(1);
+                return;
+            case TRUE:
+                replace(1, InstructionFactory.createModifiedInstruction(OP_jump, i.getInstruction()));
+                return;
+            case DONT_KNOW:
+                break;             // continue on if we don't know it's a constant boolean
+            default:
+                assert false;
+                
+        }
+        switch (prev.getOpcode())
+        {
+            case OP_convert_b:
+            {
+                replace(1, i.getInstruction());
+                break;
+            }
+            case OP_equals:
+            {
+                replace(1, InstructionFactory.createModifiedInstruction(OP_ifeq, i.getInstruction()));
+                break;
+            }
+            case OP_strictequals:
+            {
+                replace(1, InstructionFactory.createModifiedInstruction(OP_ifstricteq, i.getInstruction()));
+                break;
+            }
+            case OP_lessthan:
+            {
+                replace(1, InstructionFactory.createModifiedInstruction(OP_iflt, i.getInstruction()));
+                break;
+            }
+            case OP_lessequals:
+            {
+                replace(1, InstructionFactory.createModifiedInstruction(OP_ifle, i.getInstruction()));
+                break;
+            }
+            case OP_greaterthan:
+            {
+                replace(1, InstructionFactory.createModifiedInstruction(OP_ifgt, i.getInstruction()));
+                break;
+            }
+            case OP_greaterequals:
+            {
+                replace(1, InstructionFactory.createModifiedInstruction(OP_ifge, i.getInstruction()));
+                break;
+            }
+           
+            case OP_not:
+            {
+                InstructionInfo prev2 = previous(2);
+                switch (prev2.getOpcode())
+                {
+                    case OP_strictequals:
+                    {
+                        replace(2, InstructionFactory.createModifiedInstruction(OP_ifstrictne, i.getInstruction()));
+                        break;
+                    }
+                    case OP_equals:
+                    {
+                        replace(2, InstructionFactory.createModifiedInstruction(OP_ifne, i.getInstruction()));
+                        break;
+                    }
+                    case OP_lessthan:
+                    {
+                        replace(2, InstructionFactory.createModifiedInstruction(OP_ifnlt, i.getInstruction()));
+                        break;
+                    }
+                    case OP_lessequals:
+                    {
+                        replace(2, InstructionFactory.createModifiedInstruction(OP_ifnle, i.getInstruction()));
+                        break;
+                    }
+                    case OP_greaterthan:
+                    {
+                        replace(2, InstructionFactory.createModifiedInstruction(OP_ifngt, i.getInstruction()));
+                        break;
+                    }
+                    case OP_greaterequals:
+                    {
+                        replace(2, InstructionFactory.createModifiedInstruction(OP_ifnge, i.getInstruction()));
+                        break;
+                    }
+                    default:
+                    {
+                        replace(1, InstructionFactory.createModifiedInstruction(OP_iffalse, i.getInstruction()));
+                        break;
+                    }
+                }
+                break;
+            }
+
+            default:
+                // nothing to do, instruction was already added
+        }
+    }
+    
+    private enum ConstantBoolean { TRUE, FALSE, DONT_KNOW }
+    /**
+     * evaluates an instruction and determines if it will result in true or false on TOS.
+     * 
+     * @param i is an instruction to analyze
+     * @return whether TOS is true, false, or not known
+     */
+    private static ConstantBoolean isTrueInstructionInfo(InstructionInfo i)
+    {
+        ConstantBoolean ret = ConstantBoolean.DONT_KNOW;
+        switch(i.getOpcode())
+        {
+            case OP_pushtrue:
+                ret = ConstantBoolean.TRUE;
+                break;
+            case OP_pushfalse:
+                ret = ConstantBoolean.FALSE;
+                break;
+            case OP_pushbyte:
+            {        
+                int value = i.getImmediate();
+                assert value >= 0;
+                ret =  ECMASupport.toBoolean(value) ? ConstantBoolean.TRUE : ConstantBoolean.FALSE;
+                break;
+            }
+            case OP_pushint:
+            {        
+                int value = (Integer)i.getOperand(0);
+                ret =  ECMASupport.toBoolean(value) ? ConstantBoolean.TRUE : ConstantBoolean.FALSE;
+                break;
+            }
+            case OP_pushuint:
+            {        
+                long value = (Long)i.getOperand(0);
+                ret =  ECMASupport.toBoolean(value) ? ConstantBoolean.TRUE : ConstantBoolean.FALSE;
+                break;
+            } 
+            case OP_pushstring:
+            {        
+                String value = i.getOperand(0).toString();
+                ret =  ECMASupport.toBoolean(value) ? ConstantBoolean.TRUE : ConstantBoolean.FALSE;
+                break;
+            }
+            case OP_pushnull:
+                ret = ConstantBoolean.FALSE;
+                break;
+        }
+        return ret;
+    }
+
+
+    /**
+     * Optimizations for OP_pop: callprop, pop -> callpropvoid callsuper, pop ->
+     * callsupervoid
+     */
+    private void op_pop(InstructionInfo i)
+    {
+        InstructionInfo prev = previous(1);
+        switch (prev.getOpcode())
+        {
+            case OP_callproperty:
+            {
+                replace(1, InstructionFactory.createModifiedInstruction(OP_callpropvoid, prev.getInstruction()));
+                break;
+            }
+            case OP_callsuper:
+            {
+                replace(1, InstructionFactory.createModifiedInstruction(OP_callsupervoid, prev.getInstruction()));
+                break;
+            }
+            default:
+            {
+                // nothing to do, instruction has already been added
+            }
+        }
+    }
+
+    /**
+     * Optimizations for OP_returnvoid: returnvoid, returnvoid -> returnvoid
+     * getlocal0, pushscope, returnvoid -> returnvoid (insn without side
+     * effect), returnvoid -> returnvoid
+     */
+    private void op_returnvoid(InstructionInfo i)
+    {
+        InstructionInfo prev = previous(1);
+        switch (prev.getOpcode())
+        {
+            case OP_returnvoid:
+            {
+                delete(0);
+                break;
+            }
+            //  Any instruction without side effects that
+            //  the CG is likely to generate can go here.
+            case OP_pop:
+            {
+                replace(1, i.getInstruction());
+                break;
+            }
+            case OP_pushscope:
+            {
+                if (previous(2).getOpcode() == OP_getlocal0)
+                    //  Trivial function.
+                    replace(2, i.getInstruction());
+                break;
+            }
+            default:
+            {
+                // nothing to do, instruction has already been added
+            }
+        }
+    }
+
+    /**
+     * Optimizations for OP_getlocal: setlocal N, getlocal N -> dup, setlocal N
+     */
+    private void OP_getlocal(InstructionInfo i)
+    {
+        InstructionInfo prev = previous(1);
+        InstructionInfo cur = previous(0);
+
+        switch (prev.getOpcode())
+        {
+            case OP_setlocal:
+            {
+                if (cur.getInstruction().getImmediate() != prev.getInstruction().getImmediate())
+                    break; // set,get of different locals
+
+                Instruction[] newInsns = {InstructionFactory.getInstruction(OP_dup), prev.getInstruction()};
+                replace(1, newInsns);
+                break;
+            }
+            default:
+            {
+                // nothing to do, instruction has already been added
+            }
+        }
+    }
+
+    /**
+     * convert the immediate of a pushbyte to a double value.
+     */
+    double convertByteImmediateToDouble(int i)
+    {
+        byte b = (byte)i;
+        return (double)b;
+    }
+
+    /**
+     * Add an instruction to the peephole window. If the window is already full
+     * then the first instruction will be removed, and passed on to the next
+     * delegate to make room for the new instruction
+     * 
+     * @param insn the Instruction to add
+     */
+    private void addInstruction(Instruction insn)
+    {
+        int size = instructions.size();
+        InstructionInfo info = null;
+        if (size == PEEPHOLE_WINDOW_SIZE)
+        {
+            // reuse the InstructionInfo if we can
+            info = instructions.remove(0);
+            finishInstruction(info);
+
+            if (lastLabelSeen != NO_LABEL)
+                --lastLabelSeen;
+        }
+        else
+        {
+            info = new InstructionInfo();
+        }
+        info.reset(insn);
+        instructions.add(info);
+
+        if (labelsFromDeletedInsns != null)
+        {
+            // If we saved any labels from a deleted instruction sequence,
+            // apply them here.
+            // They will always be label currents no matter what the started out
+            // as - if we deleted something with a labelNext, this is still the next instruction
+            // and if we deleted something with a labelCurrent then this instruction is the new current instruction
+            for (Label l : labelsFromDeletedInsns)
+                labelCurrent(l);
+            labelsFromDeletedInsns = null;
+        }
+    }
+
+    /**
+     * Called when the peephole optimizer is finished with an instruction. This
+     * method will pass the instruction through to the next IMethodBodyVisitor,
+     * and call any needed labeling methods.
+     * 
+     * @param info The InstructionInfo that the optimizer is done with
+     */
+    private void finishInstruction(InstructionInfo info)
+    {
+        finisher.visitInstruction(info.getInstruction());
+        
+        for (Label l : info.getLabelCurrents())
+        {
+            finisher.labelCurrent(l);
+        }
+        
+        for (Label l : info.getLabelNexts())
+        {
+            finisher.labelNext(l);
+        }
+    }
+
+    /**
+     * Helper class to hold info about an Instruction. In addition to the
+     * Instruction, it also keeps track of any labelNext, or labelCurrent
+     * instructions that must be applied to the Instruction once it is passed on
+     * to the next IMethodBodyVisitor
+     */
+    private static class InstructionInfo
+    {
+        InstructionInfo()
+        {
+        }
+
+        /**
+         * Hold the instruction
+         */
+        private Instruction insn;
+
+        /**
+         * label(s) to use for a labelNext operation once we are done with the
+         * instruction
+         */
+        private List<Label> labelNexts = new ArrayList<Label>();
+
+        /**
+         * label(s) to use for a labelCurrent operation once we are done with
+         * the instruction
+         */
+        private List<Label> labelCurrents = new ArrayList<Label>();
+
+        /**
+         * Reset the Instruction info to its default state with a new
+         * Instruction. This method will clear any labelNext/labelCurrent data.
+         * This is so we can reuse the InstructionInfo instances.
+         */
+        void reset(Instruction i)
+        {
+            this.insn = i;
+            labelNexts.clear();
+            labelCurrents.clear();
+        }
+
+        /**
+         * Change the Instruction this InstructionInfo points at. This is useful
+         * for rewriting instructions - instead of deleting and adding a new
+         * InstructionInfo, we can just rest the Instruction. This will not
+         * clear any labelNext/labelCurrent data - If we are replacing an
+         * Instruction then the label methods should still happen on the new
+         * instruction that replaced the old one.
+         */
+        void setInstruction(Instruction i)
+        {
+            this.insn = i;
+        }
+
+        /**
+         * @return the Instruction this instance holds
+         */
+        public Instruction getInstruction()
+        {
+            return insn;
+        }
+
+        /**
+         * Add a Label to be used as an argument for labelCurrent when this
+         * instruction is passed on to the next visitor.
+         * 
+         * @param l the label
+         */
+        public void addLabelCurrent(Label l)
+        {
+            this.labelCurrents.add(l);
+        }
+
+        /**
+         * Add a Label to be used as an argument for labelNext when this
+         * instruction is passed on to the next visitor.
+         * 
+         * @param l the label
+         */
+        public void addLabelNext(Label l)
+        {
+            this.labelNexts.add(l);
+        }
+
+        /**
+         * @return A List of Labels to be used for labelCurrent, returns the
+         * empty list if there are none
+         */
+        public List<Label> getLabelCurrents()
+        {
+            return labelCurrents;
+        }
+
+        /**
+         * @return A List of Labels to be used for labelNext, returns the empty
+         * list if there are none
+         */
+        public List<Label> getLabelNexts()
+        {
+            return labelNexts;
+        }
+
+        /**
+         * @return the opcode of the Instruction, or -1 if there is no
+         * instruction
+         */
+        public int getOpcode()
+        {
+            return insn != null ? insn.getOpcode() : -1;
+        }
+
+        /**
+         * @return the immediate for the instruction, or -1 if there is no
+         * instruction
+         */
+        public int getImmediate()
+        {
+            return insn != null ? insn.getImmediate() : -1;
+        }
+
+        /**
+         * Get the operand at index i from the underlying instruction
+         * 
+         * @param i the index of the operand to fetch
+         * @return the operand at index i, or null if there is no instruction
+         */
+        public Object getOperand(int i)
+        {
+            return insn != null ? insn.getOperand(i) : null;
+        }
+    }
+
+    /**
+     * Interface so we can do different things when we are done with an
+     * instruction
+     */
+    static interface InstructionFinisher
+    {
+        void visitInstruction(Instruction i);
+
+        void labelNext(Label l);
+
+        void labelCurrent(Label l);
+    }
+
+    /**
+     * Passes the instruction and any label calls on to the next
+     * IMethodBodyVisitor
+     */
+    class DelegateFinisher implements InstructionFinisher
+    {
+        public void visitInstruction(Instruction i)
+        {
+            PeepholeOptimizerMethodBodyVisitor.super.visitInstruction(i);
+        }
+
+        public void labelNext(Label l)
+        {
+            PeepholeOptimizerMethodBodyVisitor.super.labelNext(l);
+        }
+
+        public void labelCurrent(Label l)
+        {
+            PeepholeOptimizerMethodBodyVisitor.super.labelCurrent(l);
+        }
+    }
+
+    /**
+     * Puts the instructions into a InstructionList instead of passing them on
+     * to the next IMethodBodyVisitor
+     */
+    static class InstructionListFinisher implements InstructionFinisher
+    {
+        public InstructionListFinisher(InstructionList list)
+        {
+            this.list = list;
+        }
+
+        private InstructionList list;
+
+        public void visitInstruction(Instruction i)
+        {
+            list.addInstruction(i);
+        }
+
+        public void labelNext(Label l)
+        {
+            list.labelNext(l);
+        }
+
+        public void labelCurrent(Label l)
+        {
+            list.labelCurrent(l);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/59f6373b/compiler/src/main/java/org/apache/flex/abc/optimize/package.html
----------------------------------------------------------------------
diff --git a/compiler/src/main/java/org/apache/flex/abc/optimize/package.html b/compiler/src/main/java/org/apache/flex/abc/optimize/package.html
new file mode 100644
index 0000000..d52c83c
--- /dev/null
+++ b/compiler/src/main/java/org/apache/flex/abc/optimize/package.html
@@ -0,0 +1,36 @@
+<!--
+
+  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.
+
+-->
+
+<html>
+<body>
+
+This package contains specialized visitors that transform their input
+according to some figure of merit.
+
+<p>
+Typical figures of merit are:
+<ul>
+<li>Code size and estimated cost to execute instructions<li>
+<li>Graph normalization to exclude unreachable regions
+(dead code) and to remove unnecessary branch instructions.</li>
+</ul>
+</p>
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/59f6373b/compiler/src/main/java/org/apache/flex/abc/package.html
----------------------------------------------------------------------
diff --git a/compiler/src/main/java/org/apache/flex/abc/package.html b/compiler/src/main/java/org/apache/flex/abc/package.html
new file mode 100644
index 0000000..3ef148d
--- /dev/null
+++ b/compiler/src/main/java/org/apache/flex/abc/package.html
@@ -0,0 +1,41 @@
+<!--
+
+  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.
+
+-->
+
+<html>
+<body>
+
+This package and its subpackages contain a support library
+for manipulating ActionScript bytecode (ABC).
+
+<p>
+ABC is the bytecode executed by the ActionScript Virtual Machine
+in Flash Player.
+The format and semantics of ABC is described in the document
+<a href="http://learn.adobe.com/wiki/display/AVM2/ActionScript+Virtual+Machine+2"><i>ActionScript Virtual Machine 2 (AVM2) Overview</i></a>.
+This library uses a set of visitor-pattern interfaces to
+expose the structure of ABC.
+</p>
+
+<p>
+The immediate contents of this package are classes for reading and writing ABC,
+such as <code>ABCParser</code> and <codde>ABCEmitter</code>.
+</p>
+
+</body>
+</html>