All Downloads are FREE. Search and download functionalities are using the official Maven repository.

apparat.bytecode.BytecodeDecoder.scala Maven / Gradle / Ivy

/*
 * This file is part of Apparat.
 *
 * Apparat is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Apparat is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Apparat. If not, see .
 *
 * Copyright (C) 2009 Joa Ebert
 * http://www.joa-ebert.com/
 *
 */
package apparat.bytecode

import annotation.tailrec
import collection.immutable.{TreeMap, SortedMap}
import collection.mutable.ListBuffer
import java.io.{ByteArrayInputStream => JByteArrayInputStream}
import operations._
import apparat.abc.{AbcMethodBody, AbcInputStream, AbcExceptionHandler, Abc}

object BytecodeDecoder {
	def apply(bytecode: Array[Byte], abcExceptions: Array[AbcExceptionHandler], body: AbcMethodBody)(implicit abc: Abc) = {
		val input = new AbcInputStream(new JByteArrayInputStream(bytecode))
		val cpool = abc.cpool
		val markers = new MarkerManager()
		val exceptions = abcExceptions map {
			handler => new BytecodeExceptionHandler(
				markers.putMarkerAt(handler.from),
				markers.putMarkerAt(handler.to),
				markers.putMarkerAt(handler.target),
				handler.typeName, handler.varName)
		}

		@inline def u08 = input.readU08()
		@inline def s08 = input.readS08()
		@inline def s24 = input.readS24()
		@inline def u30 = input.readU30()
		@inline def s30 = input.readS30()
		@inline def name = cpool.names(u30)
		@inline def string = cpool.strings(u30)
		@inline def numArguments = u30
		@inline def register = u30
		@inline def slot = u30
		@inline def property = name
		@inline def marker(implicit position: Int) = markers putMarkerAt (position + 0x04 + s24)
		@inline def readOp(implicit position: Int): AbstractOp = input.readU08() match {
			case Op.add => Add()
			case Op.add_i => AddInt()
			case Op.add_p => error("add_p")
			case Op.applytype => ApplyType(numArguments)
			case Op.astype => AsType(name)
			case Op.astypelate => AsTypeLate()
			case Op.bitand => BitAnd()
			case Op.bitnot => BitNot()
			case Op.bitor => BitOr()
			case Op.bitxor => BitXor()
			case Op.bkpt => Breakpoint()
			case Op.bkptline => BreakpointLine()
			case Op.call => Call(numArguments)
			case Op.callmethod => CallMethod(u30, numArguments)
			case Op.callproperty => CallProperty(property, numArguments)
			case Op.callproplex => CallPropLex(property, numArguments)
			case Op.callpropvoid => CallPropVoid(property, numArguments)
			case Op.callstatic => CallStatic(abc methods u30, numArguments)
			case Op.callsuper => CallSuper(property, numArguments)
			case Op.callsupervoid => CallSuperVoid(property, numArguments)
			case Op.checkfilter => CheckFilter()
			case Op.coerce => Coerce(name)
			case Op.coerce_a => CoerceAny()
			case Op.coerce_b => CoerceBoolean()
			case Op.coerce_d => CoerceDouble()
			case Op.coerce_i => CoerceInt()
			case Op.coerce_o => CoerceObject()
			case Op.coerce_s => CoerceString()
			case Op.coerce_u => CoerceUInt()
			case Op.construct => Construct(numArguments)
			case Op.constructprop => ConstructProp(property, numArguments)
			case Op.constructsuper => ConstructSuper(numArguments)
			case Op.convert_b => ConvertBoolean()
			case Op.convert_d => ConvertDouble()
			case Op.convert_i => ConvertInt()
			case Op.convert_m => error("convert_m")
			case Op.convert_m_p => error("convet_m_p")
			case Op.convert_o => ConvertObject()
			case Op.convert_s => ConvertString()
			case Op.convert_u => ConvertUInt()
			case Op.debug => Debug(u08, string, u08, u30)
			case Op.debugfile => DebugFile(string)
			case Op.debugline => DebugLine(u30)
			case Op.declocal => DecLocal(register)
			case Op.declocal_i => DecLocalInt(register)
			case Op.declocal_p => error("declocal_p")
			case Op.decrement => Decrement()
			case Op.decrement_i => DecrementInt()
			case Op.decrement_p => error("decrement_p")
			case Op.deldescendants => error("deldescendants")
			case Op.deleteproperty => DeleteProperty(property)
			case Op.divide => Divide()
			case Op.divide_p => error("divide_p")
			case Op.dup => Dup()
			case Op.dxns => DefaultXMLNamespace(string)
			case Op.dxnslate => DefaultXMLNamespaceLate()
			case Op.equals => Equals()
			case Op.esc_xattr => EscapeXMLAttribute()
			case Op.esc_xelem => EscapeXMLElement()
			case Op.finddef => error("finddef")
			case Op.findproperty => FindProperty(property)
			case Op.findpropstrict => FindPropStrict(property)
			case Op.getdescendants => GetDescendants(property)
			case Op.getglobalscope => GetGlobalScope()
			case Op.getglobalslot => GetGlobalSlot(slot)
			case Op.getlex => GetLex(name)
			case Op.getlocal => GetLocal(register)
			case Op.getlocal0 => GetLocal(0)
			case Op.getlocal1 => GetLocal(1)
			case Op.getlocal2 => GetLocal(2)
			case Op.getlocal3 => GetLocal(3)
			case Op.getproperty => GetProperty(property)
			case Op.getscopeobject => GetScopeObject(u08)
			case Op.getslot => GetSlot(slot)
			case Op.getsuper => GetSuper(property)
			case Op.greaterequals => GreaterEquals()
			case Op.greaterthan => GreaterThan()
			case Op.hasnext => HasNext()
			case Op.hasnext2 => HasNext2(register, register)
			case Op.ifeq => IfEqual(marker)
			case Op.iffalse => IfFalse(marker)
			case Op.ifge => IfGreaterEqual(marker)
			case Op.ifgt => IfGreaterThan(marker)
			case Op.ifle => IfLessEqual(marker)
			case Op.iflt => IfLessThan(marker)
			case Op.ifne => IfNotEqual(marker)
			case Op.ifnge => IfNotGreaterEqual(marker)
			case Op.ifngt => IfNotGreaterThan(marker)
			case Op.ifnle => IfNotLessEqual(marker)
			case Op.ifnlt => IfNotLessThan(marker)
			case Op.ifstricteq => IfStrictEqual(marker)
			case Op.ifstrictne => IfStrictNotEqual(marker)
			case Op.iftrue => IfTrue(marker)
			case Op.in => In()
			case Op.inclocal => IncLocal(register)
			case Op.inclocal_i => IncLocalInt(register)
			case Op.inclocal_p => error("inclocal_p")
			case Op.increment => Increment()
			case Op.increment_i => IncrementInt()
			case Op.increment_p => error("increment_p")
			case Op.initproperty => InitProperty(property)
			case Op.instanceof => InstanceOf()
			case Op.istype => IsType(name)
			case Op.istypelate => IsTypeLate()
			case Op.jump => Jump(marker)
			case Op.kill => Kill(register)
			case Op.label => Label()
			case Op.lessequals => LessEquals()
			case Op.lessthan => LessThan()
			case Op.lf32 => GetFloat()
			case Op.lf64 => GetDouble()
			case Op.li16 => GetShort()
			case Op.li32 => GetInt()
			case Op.li8 => GetByte()
			case Op.lookupswitch => LookupSwitch(markers putMarkerAt (position + s24), Array.fill(u30 + 1) { markers putMarkerAt (position + s24) })
			case Op.lshift => ShiftLeft()
			case Op.modulo => Modulo()
			case Op.modulo_p => error("modulo_p")
			case Op.multiply => Multiply()
			case Op.multiply_i => MultiplyInt()
			case Op.multiply_p => error("multiply_p")
			case Op.negate => Negate()
			case Op.negate_i => NegateInt()
			case Op.negate_p => error("negate_p")
			case Op.newactivation => NewActivation()
			case Op.newarray => NewArray(numArguments)
			case Op.newcatch => NewCatch(exceptions(u30))
			case Op.newclass => NewClass(abc types u30)
			case Op.newfunction => NewFunction(abc methods u30)
			case Op.newobject => NewObject(numArguments)
			case Op.nextname => NextName()
			case Op.nextvalue => NextValue()
			case Op.nop => Nop()
			case Op.not => Not()
			case Op.pop => Pop()
			case Op.popscope => PopScope()
			case Op.pushbyte => PushByte(s08)
			case Op.pushdecimal => error("pushdecimal")
			case Op.pushdnan => error("pushdnan")//push decimal nan
			case Op.pushdouble => PushDouble(cpool doubles u30)
			case Op.pushfalse => PushFalse()
			case Op.pushint => PushInt(cpool ints u30)
			case Op.pushnamespace => PushNamespace(cpool namespaces u30)
			case Op.pushnan => PushNaN()
			case Op.pushnull => PushNull()
			case Op.pushscope => PushScope()
			case Op.pushshort => PushShort(s30) // pushshort is signed
			case Op.pushstring => PushString(string)
			case Op.pushtrue => PushTrue()
			case Op.pushuint => PushUInt(cpool uints u30)
			case Op.pushundefined => PushUndefined()
			case Op.pushuninitialized => error("pushuninitialized")
			case Op.pushwith => PushWith()
			case Op.returnvalue => ReturnValue()
			case Op.returnvoid => ReturnVoid()
			case Op.rshift => ShiftRight()
			case Op.setglobalslot => SetGlobalSlot(slot)
			case Op.setlocal => SetLocal(register)
			case Op.setlocal0 => SetLocal(0)
			case Op.setlocal1 => SetLocal(1)
			case Op.setlocal2 => SetLocal(2)
			case Op.setlocal3 => SetLocal(3)
			case Op.setproperty => SetProperty(property)
			case Op.setslot => SetSlot(slot)
			case Op.setsuper => SetSuper(property)
			case Op.sf32 => SetFloat()
			case Op.sf64 => SetDouble()
			case Op.si16 => SetShort()
			case Op.si32 => SetInt()
			case Op.si8 => SetByte()
			case Op.strictequals => StrictEquals()
			case Op.subtract => Subtract()
			case Op.subtract_i => SubtractInt()
			case Op.subtract_p => error("subtract_p")
			case Op.swap => Swap()
			case Op.sxi1 => Sign1()
			case Op.sxi16 => Sign16()
			case Op.sxi8 => Sign8()
			case Op.`throw` => Throw()
			case Op.timestamp => error("timestamp")
			case Op.typeof => TypeOf()
			case Op.urshift => ShiftRightUnsigned()
			case x => error("Unknown opcode " + x + ".")
		}

		@tailrec def build(list: List[AbstractOp], map: SortedMap[Int, AbstractOp]): (List[AbstractOp], SortedMap[Int, AbstractOp]) = input.available match {
			case 0 => (list, map)
			case _ => {
				val pos = input.position
				val op = readOp(pos)

				build(op :: list, map + (pos -> op))
			}
		}

		try {
			val (ops, map) = build(Nil, TreeMap())
			new Bytecode(ops.reverse, markers solve map, exceptions, Some(body))
		}
		finally {
			try { input.close() } catch { case _ => {} }
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy