author Eric Bruneton
  import { Opcodes } from "./Opcodes" ; import { ClassWriter } from "./ClassWriter" ; import { MethodWriter } from "./MethodWriter" ; import { Type } from "./Type" ; import { Label } from "./Label" ; import { Item } from "./Item" ; import { assert } from "./utils" ; export class Frame { static __static_initialized : boolean = false ; static __static_initialize ( ) { if ( ! Frame . __static_initialized ) { Frame . __static_initialized = true ; Frame . __static_initializer_0 ( ) ; } } /**
     * Mask to get the dimension of a frame type. This dimension is a signed
     * integer between -8 and 7.
     */ static DIM : number = - 268435456 ; /**
     * Constant to be added to a type to get a type with one more dimension.
     */ static ARRAY_OF : number = 268435456 ; /**
     * Constant to be added to a type to get a type with one less dimension.
     */ static ELEMENT_OF : number = - 268435456 ; see see see static KIND : number = 251658240 ; /**
     * Flag used for LOCAL and STACK types. Indicates that if this type happens
     * to be a long or double type (during the computations of input frames),
     * then it must be set to TOP because the second word of this value has been
     * reused to store other data in the basic block. Hence the first word no
     * longer stores a valid long or double value.
     */ static TOP_IF_LONG_OR_DOUBLE : number = 8388608 ; /**
     * Mask to get the value of a frame type.
     */ static VALUE : number = 8388607 ; /**
     * Mask to get the kind of base types.
     */ static BASE_KIND : number = 267386880 ; /**
     * Mask to get the value of base types.
     */ static BASE_VALUE : number = 1048575 ; /**
     * Kind of the types that are not relative to an input stack map frame.
     */ static BASE : number = 16777216 ; /**
     * Base kind of the base reference types. The BASE_VALUE of such types is an
     * index into the type table.
     */ static OBJECT : number ; public static OBJECT_$LI$ ( ) { Frame . __static_initialize ( ) ; if ( Frame . OBJECT == null ) { Frame . OBJECT = Frame . BASE | 7340032 ; } return Frame . OBJECT ; } ; /**
     * Base kind of the uninitialized base types. The BASE_VALUE of such types
     * in an index into the type table (the Item at that index contains both an
     * instruction offset and an internal class name).
     */ static UNINITIALIZED : number ; public static UNINITIALIZED_$LI$ ( ) { Frame . __static_initialize ( ) ; if ( Frame . UNINITIALIZED == null ) { Frame . UNINITIALIZED = Frame . BASE | 8388608 ; } return Frame . UNINITIALIZED ; } ; /**
     * Kind of the types that are relative to the local variable types of an
     * input stack map frame. The value of such types is a local variable index.
     */ static LOCAL : number = 33554432 ; /**
     * Kind of the the types that are relative to the stack of an input stack
     * map frame. The value of such types is a position relatively to the top of
     * this stack.
     */ static STACK : number = 50331648 ; /**
     * The TOP type. This is a BASE type.
     */ static TOP : number ; public static TOP_$LI$ ( ) { Frame . __static_initialize ( ) ; if ( Frame . TOP == null ) { Frame . TOP = Frame . BASE | 0 ; } return Frame . TOP ; } ; /**
     * The BOOLEAN type. This is a BASE type mainly used for array types.
     */ static BOOLEAN : number ; public static BOOLEAN_$LI$ ( ) { Frame . __static_initialize ( ) ; if ( Frame . BOOLEAN == null ) { Frame . BOOLEAN = Frame . BASE | 9 ; } return Frame . BOOLEAN ; } ; /**
     * The BYTE type. This is a BASE type mainly used for array types.
     */ static BYTE : number ; public static BYTE_$LI$ ( ) { Frame . __static_initialize ( ) ; if ( Frame . BYTE == null ) { Frame . BYTE = Frame . BASE | 10 ; } return Frame . BYTE ; } ; /**
     * The CHAR type. This is a BASE type mainly used for array types.
     */ static CHAR : number ; public static CHAR_$LI$ ( ) { Frame . __static_initialize ( ) ; if ( Frame . CHAR == null ) { Frame . CHAR = Frame . BASE | 11 ; } return Frame . CHAR ; } ; /**
     * The SHORT type. This is a BASE type mainly used for array types.
     */ static SHORT : number ; public static SHORT_$LI$ ( ) { Frame . __static_initialize ( ) ; if ( Frame . SHORT == null ) { Frame . SHORT = Frame . BASE | 12 ; } return Frame . SHORT ; } ; /**
     * The INTEGER type. This is a BASE type.
     */ static INTEGER : number ; public static INTEGER_$LI$ ( ) { Frame . __static_initialize ( ) ; if ( Frame . INTEGER == null ) { Frame . INTEGER = Frame . BASE | 1 ; } return Frame . INTEGER ; } ; /**
     * The FLOAT type. This is a BASE type.
     */ static FLOAT : number ; public static FLOAT_$LI$ ( ) { Frame . __static_initialize ( ) ; if ( Frame . FLOAT == null ) { Frame . FLOAT = Frame . BASE | 2 ; } return Frame . FLOAT ; } ; /**
     * The DOUBLE type. This is a BASE type.
     */ static DOUBLE : number ; public static DOUBLE_$LI$ ( ) { Frame . __static_initialize ( ) ; if ( Frame . DOUBLE == null ) { Frame . DOUBLE = Frame . BASE | 3 ; } return Frame . DOUBLE ; } ; /**
     * The LONG type. This is a BASE type.
     */ static LONG : number ; public static LONG_$LI$ ( ) { Frame . __static_initialize ( ) ; if ( Frame . LONG == null ) { Frame . LONG = Frame . BASE | 4 ; } return Frame . LONG ; } ; /**
     * The NULL type. This is a BASE type.
     */ static NULL : number ; public static NULL_$LI$ ( ) { Frame . __static_initialize ( ) ; if ( Frame . NULL == null ) { Frame . NULL = Frame . BASE | 5 ; } return Frame . NULL ; } ; /**
     * The UNINITIALIZED_THIS type. This is a BASE type.
     */ static UNINITIALIZED_THIS : number ; public static UNINITIALIZED_THIS_$LI$ ( ) { Frame . __static_initialize ( ) ; if ( Frame . UNINITIALIZED_THIS == null ) { Frame . UNINITIALIZED_THIS = Frame . BASE | 6 ; } return Frame . UNINITIALIZED_THIS ; } ; /**
     * The stack size variation corresponding to each JVM instruction. This
     * stack variation is equal to the size of the values produced by an
     * instruction, minus the size of the values consumed by this instruction.
     */ static SIZE : number [ ] ; public static SIZE_$LI$ ( ) { Frame . __static_initialize ( ) ; return Frame . SIZE ; } ; static __static_initializer_0 ( ) { let i ; let b = new Array ( 202 ) ; let s = "EFFFFFFFFGGFFFGGFFFEEFGFGFEEEEEEEEEEEEEEEEEEEEDEDEDDDDDCDCDEEEEEEEEEEEEEEEEEEEEBABABBBBDCFFFGGGEDCDCDCDCDCDCDCDCDCDCEEEEDDDDDDDCDCDCEFEFDDEEFFDEDEEEBDDBBDDDDDDCCCCCCCCEFEDDDCDCDEEEEEEEEEEFEEEEEEDDEEDDEE" ; for ( i = 0 ; i < b . length ; ++ i ) { b [ i ] = ( s . charAt ( i ) ) . charCodeAt ( 0 ) - ( "E" ) . charCodeAt ( 0 ) ; } Frame . SIZE = b ; } /**
     * The label (i.e. basic block) to which these input and output stack map
     * frames correspond.
     */ owner : Label ; /**
     * The input stack map frame locals.
     */ inputLocals : number [ ] = [ ] ; /**
     * The input stack map frame stack.
     */ inputStack : number [ ] = [ ] ; /**
     * The output stack map frame locals.
     */ private outputLocals : number [ ] = [ ] ; /**
     * The output stack map frame stack.
     */ private outputStack : number [ ] = [ ] ; /**
     * Relative size of the output stack. The exact semantics of this field
     * depends on the algorithm that is used.
     *
     * When only the maximum stack size is computed, this field is the size of
     * the output stack relatively to the top of the input stack.
     *
     * When the stack map frames are completely computed, this field is the
     * actual number of types in  {@link #outputStack} .
      outputStackTop : number ; see private initializationCount : number ; /**
     * The types that are initialized in the basic block. A constructor
     * invocation on an UNINITIALIZED or UNINITIALIZED_THIS type must replace
     * <i>every occurence</i> of this type in the local variables and in the
     * operand stack. This cannot be done during the first phase of the
     * algorithm since, during this phase, the local variables and the operand
     * stack are not completely computed. It is therefore necessary to store the
     * types on which constructors are invoked in the basic block, in order to
     * do this replacement during the second phase of the algorithm, where the
     * frames are fully computed. Note that this array can contain types that
     * are relative to input locals or to the input stack (see below for the
     * description of the algorithm).
     */ private initializations : number [ ] | null = null ; param cw param nLocal param local the local variable types. Primitive types are represented by
     *  Opcodes ,  Opcodes ,
     *  Opcodes ,  Opcodes ,
     *  Opcodes , Opcodes or
     *  Opcodes (long and double are
     * represented by a single element). Reference types are
     * represented by String objects (representing internal names),
     * and uninitialized types by Label objects (this label
     * designates the NEW instruction that created this uninitialized
     * value).
     *  param nStack param stack public set ( cw ? , nLocal ? , local ? , nStack ? , stack ? ) { if ( ( ( cw != null && cw instanceof ClassWriter ) || cw === null ) && ( ( typeof nLocal === "number" ) || nLocal === null ) && ( ( local != null && local instanceof Array ) || local === null ) && ( ( typeof nStack === "number" ) || nStack === null ) && ( ( stack != null && stack instanceof Array ) || stack === null ) ) { let __args = Array . prototype . slice . call ( arguments ) ; return < any > ( ( ) => { let i = Frame . convert ( cw , nLocal , local , this . inputLocals ) ; while ( ( i < local . length ) ) { this . inputLocals [ i ++ ] = Frame . TOP_$LI$ ( ) ; } ; let nStackTop = 0 ; for ( let j = 0 ; j < nStack ; ++ j ) { if ( stack [ j ] === Opcodes . LONG || stack [ j ] === Opcodes . DOUBLE ) { ++ nStackTop ; } } this . inputStack = new Array ( nStack + nStackTop ) ; Frame . convert ( cw , nStack , stack , this . inputStack ) ; this . outputStackTop = 0 ; this . initializationCount = 0 ; } ) ( ) ; } else if ( ( ( typeof cw === "number" ) || cw === null ) && ( ( typeof nLocal === "number" ) || nLocal === null ) && local === undefined && nStack === undefined && stack === undefined ) { return < any > this . set$int$int ( cw , nLocal ) ; } else if ( ( ( cw != null && cw instanceof Frame ) || cw === null ) && nLocal === undefined && local === undefined && nStack === undefined && stack === undefined ) { return < any > this . set$Frame ( cw ) ; } else { throw new Error ( "invalid overload" ) ; } } param cw param nInput param input the types to convert. Primitive types are represented by
     *  Opcodes ,  Opcodes ,
     *  Opcodes ,  Opcodes ,
     *  Opcodes , Opcodes or
     *  Opcodes (long and double are
     * represented by a single element). Reference types are
     * represented by String objects (representing internal names),
     * and uninitialized types by Label objects (this label
     * designates the NEW instruction that created this uninitialized
     * value).
     *  param output return private static convert ( cw , nInput , input , output ) { let i = 0 ; for ( let j = 0 ; j < nInput ; ++ j ) { if ( typeof input [ j ] === "number" ) { output [ i ++ ] = Frame . BASE | ( ( < number > input [ j ] ) | 0 ) ; if ( input [ j ] === Opcodes . LONG || input [ j ] === Opcodes . DOUBLE ) { output [ i ++ ] = Frame . TOP_$LI$ ( ) ; } } else if ( typeof input [ j ] === "string" ) { output [ i ++ ] = Frame . type ( cw , Type . getObjectType ( < string > input [ j ] ) . getDescriptor ( ) ) ; } else { output [ i ++ ] = Frame . UNINITIALIZED_$LI$ ( ) | cw . addUninitializedType ( "" , ( < Label > input [ j ] ) . position ) ; } } return i ; } param f set$Frame ( f ) { this . inputLocals = f . inputLocals ; this . inputStack = f . inputStack ; this . outputLocals = f . outputLocals ; this . outputStack = f . outputStack ; this . outputStackTop = f . outputStackTop ; this . initializationCount = f . initializationCount ; this . initializations = f . initializations ; } param local return private get ( local ) { if ( this . outputLocals == null || local >= this . outputLocals . length ) { return Frame . LOCAL | local ; } else { let type = this . outputLocals [ local ] ; if ( type === 0 ) { type = this . outputLocals [ local ] = Frame . LOCAL | local ; } return type ; } } param local param type private set$int$int ( local , type ) { if ( this . outputLocals == null ) { this . outputLocals = new Array ( 10 ) ; } let n = this . outputLocals . length ; if ( local >= n ) { let t = new Array ( Math . max ( local + 1 , 2 * n ) ) ; for ( let i = 0 ; i < n ; i ++ ) { t [ i ] = this . outputLocals [ i ] ; } this . outputLocals = t ; } this . outputLocals [ local ] = type ; } param type private push$int ( type ) { if ( this . outputStack == null ) { this . outputStack = new Array ( 10 ) ; } let n = this . outputStack . length ; if ( this . outputStackTop >= n ) { let t = new Array ( Math . max ( this . outputStackTop + 1 , 2 * n ) ) ; for ( let i = 0 ; i < n ; i ++ ) { t [ i ] = this . outputStack [ i ] ; } this . outputStack = t ; } this . outputStack [ this . outputStackTop ++ ] = type ; assert ( this . owner ) ; let top = this . owner . inputStackTop + this . outputStackTop ; if ( top > this . owner . outputStackMax ) { this . owner . outputStackMax = top ; } } param cw param desc public push ( cw ? , desc ? ) { if ( ( ( cw != null && cw instanceof ClassWriter ) || cw === null ) && ( ( typeof desc === "string" ) || desc === null ) ) { let __args = Array . prototype . slice . call ( arguments ) ; return < any > ( ( ) => { let type = Frame . type ( cw , desc ) ; if ( type !== 0 ) { this . push ( type ) ; if ( type === Frame . LONG_$LI$ ( ) || type === Frame . DOUBLE_$LI$ ( ) ) { this . push ( Frame . TOP_$LI$ ( ) ) ; } } } ) ( ) ; } else if ( ( ( typeof cw === "number" ) || cw === null ) && desc === undefined ) { return < any > this . push$int ( cw ) ; } else { throw new Error ( "invalid overload" ) ; } } param cw param desc return private static type ( cw , desc ) { let t ; let index = desc . charAt ( 0 ) === "(" ? desc . indexOf ( ")" ) + 1 : 0 ; switch ( ( desc . charAt ( index ) ) ) { case "V" : return 0 ; case "Z" : case "C" : case "B" : case "S" : case "I" : return Frame . INTEGER_$LI$ ( ) ; case "F" : return Frame . FLOAT_$LI$ ( ) ; case "J" : return Frame . LONG_$LI$ ( ) ; case "D" : return Frame . DOUBLE_$LI$ ( ) ; case "L" : t = desc . substring ( index + 1 , desc . length - 1 ) ; return Frame . OBJECT_$LI$ ( ) | cw . addType ( t ) ; default : let data ; let dims = index + 1 ; while ( ( desc . charAt ( dims ) === "[" ) ) { ++ dims ; } ; switch ( ( desc . charAt ( dims ) ) ) { case "Z" : data = Frame . BOOLEAN_$LI$ ( ) ; break ; case "C" : data = Frame . CHAR_$LI$ ( ) ; break ; case "B" : data = Frame . BYTE_$LI$ ( ) ; break ; case "S" : data = Frame . SHORT_$LI$ ( ) ; break ; case "I" : data = Frame . INTEGER_$LI$ ( ) ; break ; case "F" : data = Frame . FLOAT_$LI$ ( ) ; break ; case "J" : data = Frame . LONG_$LI$ ( ) ; break ; case "D" : data = Frame . DOUBLE_$LI$ ( ) ; break ; default : t = desc . substring ( dims + 1 , desc . length - 1 ) ; data = Frame . OBJECT_$LI$ ( ) | cw . addType ( t ) ; } return ( dims - index ) << 28 | data ; } } return private pop$ ( ) { if ( this . outputStackTop > 0 ) { return this . outputStack [ -- this . outputStackTop ] ; } else { return Frame . STACK | - ( -- this . owner . inputStackTop ) ; } } param elements private pop$int ( elements ) { if ( this . outputStackTop >= elements ) { this . outputStackTop -= elements ; } else { this . owner . inputStackTop -= elements - this . outputStackTop ; this . outputStackTop = 0 ; } } param desc public pop ( desc ? ) { if ( ( ( typeof desc === "string" ) || desc === null ) ) { let __args = Array . prototype . slice . call ( arguments ) ; return < any > ( ( ) => { let c = desc . charAt ( 0 ) ; if ( c === "(" ) { this . pop ( ( Type . getArgumentsAndReturnSizes ( desc ) >> 2 ) - 1 ) ; } else if ( c === "J" || c === "D" ) { this . pop ( 2 ) ; } else { this . pop ( 1 ) ; } } ) ( ) ; } else if ( ( ( typeof desc === "number" ) || desc === null ) ) { return this . pop$int ( desc ) ; } else if ( desc === undefined ) { return this . pop$ ( ) ; } else { throw new Error ( "invalid overload" ) ; } } param var private init$int ( __var ) { if ( this . initializations == null ) { this . initializations = new Array ( 2 ) ; } let n = this . initializations . length ; if ( this . initializationCount >= n ) { let t = new Array ( Math . max ( this . initializationCount + 1 , 2 * n ) ) ; for ( let i = 0 ; i < n ; i ++ ) { t [ i ] = this . initializations [ i ] ; } this . initializations = t ; } this . initializations [ this . initializationCount ++ ] = __var ; } param cw param t return public init ( cw ? , t ? ) { if ( ( ( cw != null && cw instanceof ClassWriter ) || cw === null ) && ( ( typeof t === "number" ) || t === null ) ) { let __args = Array . prototype . slice . call ( arguments ) ; return ( ( ) => { let s ; if ( t === Frame . UNINITIALIZED_THIS_$LI$ ( ) ) { s = Frame . OBJECT_$LI$ ( ) | cw . addType ( cw . thisName ) ; } else if ( ( t & ( Frame . DIM | Frame . BASE_KIND ) ) === Frame . UNINITIALIZED_$LI$ ( ) ) { let type = cw . typeTable [ t & Frame . BASE_VALUE ] . strVal1 ; s = Frame . OBJECT_$LI$ ( ) | cw . addType ( type ) ; } else { return t ; } for ( let j = 0 ; j < this . initializationCount ; ++ j ) { let u = this . initializations ! [ j ] ; let dim = u & Frame . DIM ; let kind = u & Frame . KIND ; if ( kind === Frame . LOCAL ) { u = dim + this . inputLocals [ u & Frame . VALUE ] ; } else if ( kind === Frame . STACK ) { u = dim + this . inputStack [ this . inputStack . length - ( u & Frame . VALUE ) ] ; } if ( t === u ) { return s ; } } return t ; } ) ( ) ; } else if ( ( ( typeof cw === "number" ) || cw === null ) && t === undefined ) { return < any > this . init$int ( cw ) ; } else { throw new Error ( "invalid overload" ) ; } } param cw param access param args param maxLocals initInputFrame ( cw , access , args , maxLocals ) { this . inputLocals = new Array ( maxLocals ) ; this . inputStack = new Array ( 0 ) ; let i = 0 ; if ( ( access & Opcodes . ACC_STATIC ) === 0 ) { if ( ( access & MethodWriter . ACC_CONSTRUCTOR ) === 0 ) { this . inputLocals [ i ++ ] = Frame . OBJECT_$LI$ ( ) | cw . addType ( cw . thisName ) ; } else { this . inputLocals [ i ++ ] = Frame . UNINITIALIZED_THIS_$LI$ ( ) ; } } for ( let j = 0 ; j < args . length ; ++ j ) { let t = Frame . type ( cw , args [ j ] . getDescriptor ( ) ) ; this . inputLocals [ i ++ ] = t ; if ( t === Frame . LONG_$LI$ ( ) || t === Frame . DOUBLE_$LI$ ( ) ) { this . inputLocals [ i ++ ] = Frame . TOP_$LI$ ( ) ; } } while ( ( i < maxLocals ) ) { this . inputLocals [ i ++ ] = Frame . TOP_$LI$ ( ) ; } ; } param opcode param arg param cw param item execute ( opcode , arg , cw , item ) { let t1 ; let t2 ; let t3 ; let t4 ; switch ( ( opcode ) ) { case Opcodes . NOP : case Opcodes . INEG : case Opcodes . LNEG : case Opcodes . FNEG : case Opcodes . DNEG : case Opcodes . I2B : case Opcodes . I2C : case Opcodes . I2S : case Opcodes . GOTO : case Opcodes . RETURN : break ; case Opcodes . ACONST_NULL : this . push ( Frame . NULL_$LI$ ( ) ) ; break ; case Opcodes . ICONST_M1 : case Opcodes . ICONST_0 : case Opcodes . ICONST_1 : case Opcodes . ICONST_2 : case Opcodes . ICONST_3 : case Opcodes . ICONST_4 : case Opcodes . ICONST_5 : case Opcodes . BIPUSH : case Opcodes . SIPUSH : case Opcodes . ILOAD : this . push ( Frame . INTEGER_$LI$ ( ) ) ; break ; case Opcodes . LCONST_0 : case Opcodes . LCONST_1 : case Opcodes . LLOAD : this . push ( Frame . LONG_$LI$ ( ) ) ; this . push ( Frame . TOP_$LI$ ( ) ) ; break ; case Opcodes . FCONST_0 : case Opcodes . FCONST_1 : case Opcodes . FCONST_2 : case Opcodes . FLOAD : this . push ( Frame . FLOAT_$LI$ ( ) ) ; break ; case Opcodes . DCONST_0 : case Opcodes . DCONST_1 : case Opcodes . DLOAD : this . push ( Frame . DOUBLE_$LI$ ( ) ) ; this . push ( Frame . TOP_$LI$ ( ) ) ; break ; case Opcodes . LDC : assert ( cw ) ; assert ( item ) ; switch ( ( item . type ) ) { case ClassWriter . INT : this . push ( Frame . INTEGER_$LI$ ( ) ) ; break ; case ClassWriter . LONG : this . push ( Frame . LONG_$LI$ ( ) ) ; this . push ( Frame . TOP_$LI$ ( ) ) ; break ; case ClassWriter . FLOAT : this . push ( Frame . FLOAT_$LI$ ( ) ) ; break ; case ClassWriter . DOUBLE : this . push ( Frame . DOUBLE_$LI$ ( ) ) ; this . push ( Frame . TOP_$LI$ ( ) ) ; break ; case ClassWriter . CLASS : this . push ( Frame . OBJECT_$LI$ ( ) | cw . addType ( "java/lang/Class" ) ) ; break ; case ClassWriter . STR : this . push ( Frame . OBJECT_$LI$ ( ) | cw . addType ( "java/lang/String" ) ) ; break ; case ClassWriter . MTYPE : this . push ( Frame . OBJECT_$LI$ ( ) | cw . addType ( "java/lang/invoke/MethodType" ) ) ; break ; default : this . push ( Frame . OBJECT_$LI$ ( ) | cw . addType ( "java/lang/invoke/MethodHandle" ) ) ; } break ; case Opcodes . ALOAD : this . push ( this . get ( arg ) ) ; break ; case Opcodes . IALOAD : case Opcodes . BALOAD : case Opcodes . CALOAD : case Opcodes . SALOAD : this . pop ( 2 ) ; this . push ( Frame . INTEGER_$LI$ ( ) ) ; break ; case Opcodes . LALOAD : case Opcodes . D2L : this . pop ( 2 ) ; this . push ( Frame . LONG_$LI$ ( ) ) ; this . push ( Frame . TOP_$LI$ ( ) ) ; break ; case Opcodes . FALOAD : this . pop ( 2 ) ; this . push ( Frame . FLOAT_$LI$ ( ) ) ; break ; case Opcodes . DALOAD : case Opcodes . L2D : this . pop ( 2 ) ; this . push ( Frame . DOUBLE_$LI$ ( ) ) ; this . push ( Frame . TOP_$LI$ ( ) ) ; break ; case Opcodes . AALOAD : this . pop ( 1 ) ; t1 = this . pop ( ) ; this . push ( Frame . ELEMENT_OF + t1 ) ; break ; case Opcodes . ISTORE : case Opcodes . FSTORE : case Opcodes . ASTORE : t1 = this . pop ( ) ; this . set ( arg , t1 ) ; if ( arg > 0 ) { t2 = this . get ( arg - 1 ) ; if ( t2 === Frame . LONG_$LI$ ( ) || t2 === Frame . DOUBLE_$LI$ ( ) ) { this . set ( arg - 1 , Frame . TOP_$LI$ ( ) ) ; } else if ( ( t2 & Frame . KIND ) !== Frame . BASE ) { this . set ( arg - 1 , t2 | Frame . TOP_IF_LONG_OR_DOUBLE ) ; } } break ; case Opcodes . LSTORE : case Opcodes . DSTORE : this . pop ( 1 ) ; t1 = this . pop ( ) ; this . set ( arg , t1 ) ; this . set ( arg + 1 , Frame . TOP_$LI$ ( ) ) ; if ( arg > 0 ) { t2 = this . get ( arg - 1 ) ; if ( t2 === Frame . LONG_$LI$ ( ) || t2 === Frame . DOUBLE_$LI$ ( ) ) { this . set ( arg - 1 , Frame . TOP_$LI$ ( ) ) ; } else if ( ( t2 & Frame . KIND ) !== Frame . BASE ) { this . set ( arg - 1 , t2 | Frame . TOP_IF_LONG_OR_DOUBLE ) ; } } break ; case Opcodes . IASTORE : case Opcodes . BASTORE : case Opcodes . CASTORE : case Opcodes . SASTORE : case Opcodes . FASTORE : case Opcodes . AASTORE : this . pop ( 3 ) ; break ; case Opcodes . LASTORE : case Opcodes . DASTORE : this . pop ( 4 ) ; break ; case Opcodes . POP : case Opcodes . IFEQ : case Opcodes . IFNE : case Opcodes . IFLT : case Opcodes . IFGE : case Opcodes . IFGT : case Opcodes . IFLE : case Opcodes . IRETURN : case Opcodes . FRETURN : case Opcodes . ARETURN : case Opcodes . TABLESWITCH : case Opcodes . LOOKUPSWITCH : case Opcodes . ATHROW : case Opcodes . MONITORENTER : case Opcodes . MONITOREXIT : case Opcodes . IFNULL : case Opcodes . IFNONNULL : this . pop ( 1 ) ; break ; case Opcodes . POP2 : case Opcodes . IF_ICMPEQ : case Opcodes . IF_ICMPNE : case Opcodes . IF_ICMPLT : case Opcodes . IF_ICMPGE : case Opcodes . IF_ICMPGT : case Opcodes . IF_ICMPLE : case Opcodes . IF_ACMPEQ : case Opcodes . IF_ACMPNE : case Opcodes . LRETURN : case Opcodes . DRETURN : this . pop ( 2 ) ; break ; case Opcodes . DUP : t1 = this . pop ( ) ; this . push ( t1 ) ; this . push ( t1 ) ; break ; case Opcodes . DUP_X1 : t1 = this . pop ( ) ; t2 = this . pop ( ) ; this . push ( t1 ) ; this . push ( t2 ) ; this . push ( t1 ) ; break ; case Opcodes . DUP_X2 : t1 = this . pop ( ) ; t2 = this . pop ( ) ; t3 = this . pop ( ) ; this . push ( t1 ) ; this . push ( t3 ) ; this . push ( t2 ) ; this . push ( t1 ) ; break ; case Opcodes . DUP2 : t1 = this . pop ( ) ; t2 = this . pop ( ) ; this . push ( t2 ) ; this . push ( t1 ) ; this . push ( t2 ) ; this . push ( t1 ) ; break ; case Opcodes . DUP2_X1 : t1 = this . pop ( ) ; t2 = this . pop ( ) ; t3 = this . pop ( ) ; this . push ( t2 ) ; this . push ( t1 ) ; this . push ( t3 ) ; this . push ( t2 ) ; this . push ( t1 ) ; break ; case Opcodes . DUP2_X2 : t1 = this . pop ( ) ; t2 = this . pop ( ) ; t3 = this . pop ( ) ; t4 = this . pop ( ) ; this . push ( t2 ) ; this . push ( t1 ) ; this . push ( t4 ) ; this . push ( t3 ) ; this . push ( t2 ) ; this . push ( t1 ) ; break ; case Opcodes . SWAP : t1 = this . pop ( ) ; t2 = this . pop ( ) ; this . push ( t1 ) ; this . push ( t2 ) ; break ; case Opcodes . IADD : case Opcodes . ISUB : case Opcodes . IMUL : case Opcodes . IDIV : case Opcodes . IREM : case Opcodes . IAND : case Opcodes . IOR : case Opcodes . IXOR : case Opcodes . ISHL : case Opcodes . ISHR : case Opcodes . IUSHR : case Opcodes . L2I : case Opcodes . D2I : case Opcodes . FCMPL : case Opcodes . FCMPG : this . pop ( 2 ) ; this . push ( Frame . INTEGER_$LI$ ( ) ) ; break ; case Opcodes . LADD : case Opcodes . LSUB : case Opcodes . LMUL : case Opcodes . LDIV : case Opcodes . LREM : case Opcodes . LAND : case Opcodes . LOR : case Opcodes . LXOR : this . pop ( 4 ) ; this . push ( Frame . LONG_$LI$ ( ) ) ; this . push ( Frame . TOP_$LI$ ( ) ) ; break ; case Opcodes . FADD : case Opcodes . FSUB : case Opcodes . FMUL : case Opcodes . FDIV : case Opcodes . FREM : case Opcodes . L2F : case Opcodes . D2F : this . pop ( 2 ) ; this . push ( Frame . FLOAT_$LI$ ( ) ) ; break ; case Opcodes . DADD : case Opcodes . DSUB : case Opcodes . DMUL : case Opcodes . DDIV : case Opcodes . DREM : this . pop ( 4 ) ; this . push ( Frame . DOUBLE_$LI$ ( ) ) ; this . push ( Frame . TOP_$LI$ ( ) ) ; break ; case Opcodes . LSHL : case Opcodes . LSHR : case Opcodes . LUSHR : this . pop ( 3 ) ; this . push ( Frame . LONG_$LI$ ( ) ) ; this . push ( Frame . TOP_$LI$ ( ) ) ; break ; case Opcodes . IINC : this . set ( arg , Frame . INTEGER_$LI$ ( ) ) ; break ; case Opcodes . I2L : case Opcodes . F2L : this . pop ( 1 ) ; this . push ( Frame . LONG_$LI$ ( ) ) ; this . push ( Frame . TOP_$LI$ ( ) ) ; break ; case Opcodes . I2F : this . pop ( 1 ) ; this . push ( Frame . FLOAT_$LI$ ( ) ) ; break ; case Opcodes . I2D : case Opcodes . F2D : this . pop ( 1 ) ; this . push ( Frame . DOUBLE_$LI$ ( ) ) ; this . push ( Frame . TOP_$LI$ ( ) ) ; break ; case Opcodes . F2I : case Opcodes . ARRAYLENGTH : case Opcodes . INSTANCEOF : this . pop ( 1 ) ; this . push ( Frame . INTEGER_$LI$ ( ) ) ; break ; case Opcodes . LCMP : case Opcodes . DCMPL : case Opcodes . DCMPG : this . pop ( 4 ) ; this . push ( Frame . INTEGER_$LI$ ( ) ) ; break ; case Opcodes . JSR : case Opcodes . RET : throw new Error ( "JSR/RET are not supported with computeFrames option" ) ; case Opcodes . GETSTATIC : assert ( item ) ; this . push ( cw , item . strVal3 ) ; break ; case Opcodes . PUTSTATIC : assert ( item ) ; this . pop ( item . strVal3 ) ; break ; case Opcodes . GETFIELD : assert ( item ) ; this . pop ( 1 ) ; this . push ( cw , item . strVal3 ) ; break ; case Opcodes . PUTFIELD : assert ( item ) ; this . pop ( item . strVal3 ) ; this . pop ( ) ; break ; case Opcodes . INVOKEVIRTUAL : case Opcodes . INVOKESPECIAL : case Opcodes . INVOKESTATIC : case Opcodes . INVOKEINTERFACE : assert ( item ) ; this . pop ( item . strVal3 ) ; if ( opcode !== Opcodes . INVOKESTATIC ) { t1 = this . pop ( ) ; if ( opcode === Opcodes . INVOKESPECIAL && item . strVal2 . charAt ( 0 ) === "<" ) { this . init ( t1 ) ; } } this . push ( cw , item . strVal3 ) ; break ; case Opcodes . INVOKEDYNAMIC : assert ( item ) ; this . pop ( item . strVal2 ) ; this . push ( cw , item . strVal2 ) ; break ; case Opcodes . NEW : assert ( item ) ; assert ( cw ) ; this . push ( Frame . UNINITIALIZED_$LI$ ( ) | cw . addUninitializedType ( item . strVal1 , arg ) ) ; break ; case Opcodes . NEWARRAY : this . pop ( ) ; switch ( ( arg ) ) { case Opcodes . T_BOOLEAN : this . push ( Frame . ARRAY_OF | Frame . BOOLEAN_$LI$ ( ) ) ; break ; case Opcodes . T_CHAR : this . push ( Frame . ARRAY_OF | Frame . CHAR_$LI$ ( ) ) ; break ; case Opcodes . T_BYTE : this . push ( Frame . ARRAY_OF | Frame . BYTE_$LI$ ( ) ) ; break ; case Opcodes . T_SHORT : this . push ( Frame . ARRAY_OF | Frame . SHORT_$LI$ ( ) ) ; break ; case Opcodes . T_INT : this . push ( Frame . ARRAY_OF | Frame . INTEGER_$LI$ ( ) ) ; break ; case Opcodes . T_FLOAT : this . push ( Frame . ARRAY_OF | Frame . FLOAT_$LI$ ( ) ) ; break ; case Opcodes . T_DOUBLE : this . push ( Frame . ARRAY_OF | Frame . DOUBLE_$LI$ ( ) ) ; break ; default : this . push ( Frame . ARRAY_OF | Frame . LONG_$LI$ ( ) ) ; break ; } break ; case Opcodes . ANEWARRAY : assert ( item ) ; assert ( cw ) ; let s = item . strVal1 ; this . pop ( ) ; if ( s . charAt ( 0 ) === "[" ) { this . push ( cw , "[" + s ) ; } else { this . push ( Frame . ARRAY_OF | Frame . OBJECT_$LI$ ( ) | cw . addType ( s ) ) ; } break ; case Opcodes . CHECKCAST : assert ( item ) ; s = item . strVal1 ; this . pop ( ) ; if ( s . charAt ( 0 ) === "[" ) { this . push ( cw , s ) ; } else { assert ( cw ) ; this . push ( Frame . OBJECT_$LI$ ( ) | cw . addType ( s ) ) ; } break ; default : assert ( item ) ; this . pop ( arg ) ; this . push ( cw , item . strVal1 ) ; break ; } } param cw param frame param edge the kind of the  Edge between this label and 'label'.
     * See  Edge .
     *  return merge ( cw , frame , edge ) { let changed = false ; let i ; let s ; let dim ; let kind ; let t ; let nLocal = this . inputLocals . length ; let nStack = this . inputStack . length ; if ( frame . inputLocals == null ) { frame . inputLocals = new Array ( nLocal ) ; changed = true ; } for ( i = 0 ; i < nLocal ; ++ i ) { if ( this . outputLocals != null && i < this . outputLocals . length ) { s = this . outputLocals [ i ] ; if ( s === 0 ) { t = this . inputLocals [ i ] ; } else { dim = s & Frame . DIM ; kind = s & Frame . KIND ; if ( kind === Frame . BASE ) { t = s ; } else { if ( kind === Frame . LOCAL ) { t = dim + this . inputLocals [ s & Frame . VALUE ] ; } else { t = dim + this . inputStack [ nStack - ( s & Frame . VALUE ) ] ; } if ( ( s & Frame . TOP_IF_LONG_OR_DOUBLE ) !== 0 && ( t === Frame . LONG_$LI$ ( ) || t === Frame . DOUBLE_$LI$ ( ) ) ) { t = Frame . TOP_$LI$ ( ) ; } } } } else { t = this . inputLocals [ i ] ; } if ( this . initializations != null ) { t = this . init ( cw , t ) ; } changed = changed || Frame . merge ( cw , t , frame . inputLocals , i ) ; } if ( edge > 0 ) { for ( i = 0 ; i < nLocal ; ++ i ) { t = this . inputLocals [ i ] ; changed = changed || Frame . merge ( cw , t , frame . inputLocals , i ) ; } if ( frame . inputStack == null ) { frame . inputStack = new Array ( 1 ) ; changed = true ; } changed = changed || Frame . merge ( cw , edge , frame . inputStack , 0 ) ; return changed ; } let nInputStack = this . inputStack . length + this . owner . inputStackTop ; if ( frame . inputStack == null ) { frame . inputStack = new Array ( nInputStack + this . outputStackTop ) ; changed = true ; } for ( i = 0 ; i < nInputStack ; ++ i ) { t = this . inputStack [ i ] ; if ( this . initializations != null ) { t = this . init ( cw , t ) ; } changed = changed || Frame . merge ( cw , t , frame . inputStack , i ) ; } for ( i = 0 ; i < this . outputStackTop ; ++ i ) { s = this . outputStack [ i ] ; dim = s & Frame . DIM ; kind = s & Frame . KIND ; if ( kind === Frame . BASE ) { t = s ; } else { if ( kind === Frame . LOCAL ) { t = dim + this . inputLocals [ s & Frame . VALUE ] ; } else { t = dim + this . inputStack [ nStack - ( s & Frame . VALUE ) ] ; } if ( ( s & Frame . TOP_IF_LONG_OR_DOUBLE ) !== 0 && ( t === Frame . LONG_$LI$ ( ) || t === Frame . DOUBLE_$LI$ ( ) ) ) { t = Frame . TOP_$LI$ ( ) ; } } if ( this . initializations != null ) { t = this . init ( cw , t ) ; } changed = changed || Frame . merge ( cw , t , frame . inputStack , nInputStack + i ) ; } return changed ; } param cw param t param types param index return private static merge ( cw , t , types , index ) { let u = types [ index ] ; if ( u === t ) { return false ; } if ( ( t & ~ Frame . DIM ) === Frame . NULL_$LI$ ( ) ) { if ( u === Frame . NULL_$LI$ ( ) ) { return false ; } t = Frame . NULL_$LI$ ( ) ; } if ( u === 0 ) { types [ index ] = t ; return true ; } let v ; if ( ( u & Frame . BASE_KIND ) === Frame . OBJECT_$LI$ ( ) || ( u & Frame . DIM ) !== 0 ) { if ( t === Frame . NULL_$LI$ ( ) ) { return false ; } else if ( ( t & ( Frame . DIM | Frame . BASE_KIND ) ) === ( u & ( Frame . DIM | Frame . BASE_KIND ) ) ) { if ( ( u & Frame . BASE_KIND ) === Frame . OBJECT_$LI$ ( ) ) { v = ( t & Frame . DIM ) | Frame . OBJECT_$LI$ ( ) | cw . getMergedType ( t & Frame . BASE_VALUE , u & Frame . BASE_VALUE ) ; } else { let vdim = Frame . ELEMENT_OF + ( u & Frame . DIM ) ; v = vdim | Frame . OBJECT_$LI$ ( ) | cw . addType ( "java/lang/Object" ) ; } } else if ( ( t & Frame . BASE_KIND ) === Frame . OBJECT_$LI$ ( ) || ( t & Frame . DIM ) !== 0 ) { let tdim = ( ( ( t & Frame . DIM ) === 0 || ( t & Frame . BASE_KIND ) === Frame . OBJECT_$LI$ ( ) ) ? 0 : Frame . ELEMENT_OF ) + ( t & Frame . DIM ) ; let udim = ( ( ( u & Frame . DIM ) === 0 || ( u & Frame . BASE_KIND ) === Frame . OBJECT_$LI$ ( ) ) ? 0 : Frame . ELEMENT_OF ) + ( u & Frame . DIM ) ; v = Math . min ( tdim , udim ) | Frame . OBJECT_$LI$ ( ) | cw . addType ( "java/lang/Object" ) ; } else { v = Frame . TOP_$LI$ ( ) ; } } else if ( u === Frame . NULL_$LI$ ( ) ) { v = ( t & Frame . BASE_KIND ) === Frame . OBJECT_$LI$ ( ) || ( t & Frame . DIM ) !== 0 ? t : Frame . TOP_$LI$ ( ) ; } else { v = Frame . TOP_$LI$ ( ) ; } if ( u !== v ) { types [ index ] = v ; return true ; } return false ; } constructor ( owner ) { this . outputStackTop = 0 ; this . initializationCount = 0 ; this . owner = owner ; } } Frame . SIZE_$LI$ ( ) ; Frame . UNINITIALIZED_THIS_$LI$ ( ) ; Frame . NULL_$LI$ ( ) ; Frame . LONG_$LI$ ( ) ; Frame . DOUBLE_$LI$ ( ) ; Frame . FLOAT_$LI$ ( ) ; Frame . INTEGER_$LI$ ( ) ; Frame . SHORT_$LI$ ( ) ; Frame . CHAR_$LI$ ( ) ; Frame . BYTE_$LI$ ( ) ; Frame . BOOLEAN_$LI$ ( ) ; Frame . TOP_$LI$ ( ) ; Frame . UNINITIALIZED_$LI$ ( ) ; Frame . OBJECT_$LI$ ( ) ; Frame . __static_initialize ( ) ;