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

apparat.bytecode.BytecodeEncoder.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 apparat.abc.{Abc, AbcExceptionHandler, AbcName, AbcOutputStream, AbcOutputUtil}
import collection.immutable.TreeMap
import java.io.{ByteArrayOutputStream => JByteArrayOutputStream}
import operations._

object BytecodeEncoder {
	def apply(bytecode: Bytecode)(implicit abc: Abc) = {
		val byteArrayOutputStream = new JByteArrayOutputStream()
		val output = new AbcOutputStream(byteArrayOutputStream)
		val cpool = abc.cpool
		var patches = TreeMap[Int, AbstractOp]()
		val markers = bytecode.markers

		@inline def u08(value: Int) = output writeU08 value
		@inline def s08(value: Int) = output writeS08 value
		@inline def s24(value: Int) = output writeS24 value
		@inline def u30(value: Int) = output writeU30 value
		@inline def s30(value: Int) = output writeS30 value
		@inline def name(value: AbcName) = u30(cpool indexOf value)
		@inline def string(value: Symbol) = u30(cpool indexOf value)
		@inline def position = output.position
		@inline def patch(op: AbstractOp) = {
			patches = patches + ((position - 1) -> op)
			s24(0)
		}
		@inline def writeOp(op: AbstractOp) = {
			markers(op) match {
				case Some(marker) => marker.position = position
				case None =>
			}
			u08(op.opCode)
			op match {
				case Add() | AddInt() =>
				case ApplyType(numArguments) => u30(numArguments)
				case AsType(typeName) => name(typeName)
				case AsTypeLate() =>
				case BitAnd() | BitNot() | BitOr() | BitXor() =>
				case Breakpoint() | BreakpointLine() =>
				case Call(numArguments) => u30(numArguments)
				case CallMethod(index, numArguments) => {
					u30(index)
					u30(numArguments)
				}
				case CallProperty(property, numArguments) => {
					name(property)
					u30(numArguments)
				}
				case CallPropLex(property, numArguments) => {
					name(property)
					u30(numArguments)
				}
				case CallPropVoid(property, numArguments) => {
					name(property)
					u30(numArguments)
				}
				case CallStatic(method, numArguments) => {
					u30(abc.methods indexOf method)
					u30(numArguments)
				}
				case CallSuper(property, numArguments) => {
					name(property)
					u30(numArguments)
				}
				case CallSuperVoid(property, numArguments) => {
					name(property)
					u30(numArguments)
				}
				case CheckFilter() =>
				case Coerce(typeName) => name(typeName)
				case CoerceAny() | CoerceBoolean() | CoerceDouble() | CoerceInt() | CoerceObject() | CoerceString() | CoerceUInt() =>
				case Construct(numArguments) => u30(numArguments)
				case ConstructProp(property, numArguments) => {
					name(property)
					u30(numArguments)
				}
				case ConstructSuper(numArguments) => u30(numArguments)
				case ConvertBoolean() | ConvertDouble() | ConvertInt() | ConvertObject() | ConvertString() | ConvertUInt() =>
			 	case Debug(kind, name, register, extra) => {
					 u08(kind)
					 string(name)
					 u08(register)
					 u30(extra)
				}
				case DebugFile(file) => string(file)
				case DebugLine(line) => u30(line)
				case DecLocal(register) => u30(register)
				case DecLocalInt(register) => u30(register)
				case Decrement() | DecrementInt() =>
				case DeleteProperty(property) => name(property)
				case Divide() =>
				case Dup() =>
				case DefaultXMLNamespace(uri) => string(uri)
				case DefaultXMLNamespaceLate() =>
				case Equals() =>
				case EscapeXMLAttribute() =>
				case EscapeXMLElement() =>
				case FindProperty(property) => name(property)
				case FindPropStrict(property) => name(property)
				case GetDescendants(property) => name(property)
				case GetGlobalScope() =>
				case GetGlobalSlot(slot) => u30(slot)
				case GetLex(typeName) => name(typeName)
				case GetLocal(register: Int) => if(register > 3) u30(register)//note: keep the if and do not put it in the case
				case GetProperty(property) => name(property)
				case GetScopeObject(index) => u08(index)
				case GetSlot(slot) => u30(slot)
				case GetSuper(property) => name(property)
				case GreaterEquals() | GreaterThan() =>
				case HasNext() =>
				case HasNext2(objectRegister, indexRegister) => {
					u30(objectRegister)
					u30(indexRegister)
				}
				case IfEqual(marker) => patch(op)
				case IfFalse(marker) => patch(op)
				case IfGreaterEqual(marker) => patch(op)
				case IfGreaterThan(marker) => patch(op)
				case IfLessEqual(marker) => patch(op)
				case IfLessThan(marker) => patch(op)
				case IfNotEqual(marker) => patch(op)
				case IfNotGreaterEqual(marker) => patch(op)
				case IfNotGreaterThan(marker) => patch(op)
				case IfNotLessEqual(marker) => patch(op)
				case IfNotLessThan(marker) => patch(op)
				case IfStrictEqual(marker) => patch(op)
				case IfStrictNotEqual(marker) => patch(op)
				case IfTrue(marker) => patch(op)
				case In() =>
				case IncLocal(register) => u30(register)
				case IncLocalInt(register) => u30(register)
				case Increment() | IncrementInt() =>
				case InitProperty(property) => name(property)
				case InstanceOf() =>
				case IsType(typeName) => name(typeName)
				case IsTypeLate() =>
				case Jump(marker) => patch(op)
				case Kill(register) => u30(register)
				case Label() =>
				case LessEquals() | LessThan() =>
				case LookupSwitch(defaultCase, cases) => {
					patch(op)
					u30(cases.length - 1)
					(0 until cases.length) foreach { i => s24(0) }
				}
				case ShiftLeft() | Modulo() | Multiply() | MultiplyInt() | Negate() | NegateInt() =>
				case NewActivation() =>
				case NewArray(numArguments) => u30(numArguments)
				case NewCatch(exceptionHandler) => u30(bytecode.exceptions indexOf exceptionHandler)
				case NewClass(nominalType) => u30(abc.types indexOf nominalType)
				case NewFunction(function) => u30(abc.methods indexOf function)
				case NewObject(numArguments) => u30(numArguments)
				case NextName() | NextValue() | Nop() | Not() | Pop() | PopScope() =>
				case PushByte(value) => s08(value) // pushbyte is signed
				case PushDouble(value) => u30(cpool indexOf value)
				case PushFalse() =>
				case PushInt(value) => u30(cpool indexOf value)
				case PushNamespace(value) => u30(cpool indexOf value)
				case PushNaN() | PushNull() | PushScope() =>
				case PushShort(value) => s30(value) // pushshort is signed
				case PushString(value) => string(value)
				case PushTrue() =>
				case PushUInt(value) => u30(cpool indexOf value)
				case PushUndefined() | PushWith() =>
				case ReturnValue() | ReturnVoid() =>
				case ShiftRight() =>
				case SetLocal(register) => if(register > 3) u30(register)
				case SetGlobalSlot(slot) => u30(slot)
				case SetProperty(property) => name(property)
				case SetSlot(slot) => u30(slot)
				case SetSuper(property) => name(property)
				case StrictEquals() | Subtract() | SubtractInt() | Swap() =>
				case Throw() | TypeOf() | ShiftRightUnsigned() =>
				case SetByte() | SetShort() | SetInt() | SetFloat() | SetDouble() =>
				case GetByte() | GetShort() | GetInt() | GetFloat() | GetDouble() =>
				case Sign1() | Sign8() | Sign16() =>
			}
		}
		try {
			bytecode.ops foreach writeOp

			output.close()

			val buffer = byteArrayOutputStream.toByteArray

			for((position, op) <- patches) {
				op match {
					case LookupSwitch(defaultCase, cases) => {
						val offset = position + 4 + AbcOutputUtil.lengthOf(cases.length - 1)

						AbcOutputUtil.writeS24(buffer, position + 1, defaultCase.position - position)

						for(i <- 0 until cases.length)
							AbcOutputUtil.writeS24(buffer, offset + i * 3, cases(i).position - position );
					}
					case opWithMarker: OpWithMarker => AbcOutputUtil.writeS24(buffer, position + 1, opWithMarker.marker.position - (position + 4))
					case other => error("Unexpected operation " + other)
				}
			}

			val exceptions = bytecode.exceptions map {
				handler => {
					new AbcExceptionHandler(
						handler.from.position,
						handler.to.position,
						handler.target.position,
						handler.typeName, handler.varName)
				}
			}

			(buffer, exceptions)
		}
		finally {
			try { output.close() } catch { case _ =>  }
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy