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

apparat.tools.coverage.Coverage.scala Maven / Gradle / Ivy

package apparat.tools.coverage

import apparat.utils.TagContainer
import apparat.actors.Futures._
import java.io.{File => JFile}
import apparat.tools.{ApparatConfiguration, ApparatTool, ApparatApplication}
import apparat.bytecode.operations._
import apparat.bytecode.combinator._
import apparat.bytecode.combinator.BytecodeChains._
import java.io.{File => JFile}
import apparat.abc.{AbcConstantPool, AbcQName, AbcNamespace, Abc}
import compat.Platform
import apparat.swf.{SwfTag, SwfTags, DoABC}

object Coverage {
	def main(args: Array[String]): Unit = ApparatApplication(new CoverageTool, args)

	class CoverageTool extends ApparatTool {
		val debugLine = partial { case DebugLine(line) => line }
		val coverageQName = AbcQName('Coverage, AbcNamespace(22, Symbol("apparat.coverage")))
		val coverageOnSample = AbcQName('onSample, AbcNamespace(22, Symbol("")))
		val coverageScope = GetLex(coverageQName)
		val coverageMethod = CallPropVoid(coverageOnSample, 2)
		
		var input: JFile = _
		var output: JFile = _
		var sourcePath = List.empty[String]

		var observers = List.empty[CoverageObserver]

		override def name = "Coverage"

		override def help = """  -i [file]	Input file
  -o [file]	Output file (optional)
  -s [dir]	Source path to instrument"""

		override def configure(config: ApparatConfiguration): Unit = configure(CoverageConfigurationFactory fromConfiguration config)

		def configure(config: CoverageConfiguration): Unit = {
			input = config.input
			output = config.output
			sourcePath = config.sourcePath
		}
		
		override def run() = {
			SwfTags.tagFactory = (kind: Int) => kind match {
				case SwfTags.DoABC => Some(new DoABC)
				case SwfTags.DoABC1 => Some(new DoABC)
				case _ => None
			}

			val cont = TagContainer fromFile input
			cont foreachTagSync coverage
			cont write output
		}

		def addObserver(observer: CoverageObserver) = {
			observers = observer :: observers
		}

		def removeObserver(observer: CoverageObserver) = {
			observers = observers filterNot (_ == observer)
		}

		private def coverage: PartialFunction[SwfTag, Unit] = {
			case doABC: DoABC => {
				var abcModified = false
				val abc = Abc fromDoABC doABC

				abc.loadBytecode()

				for {
					method <- abc.methods
					body <- method.body
					bytecode <- body.bytecode
				} {
					bytecode.ops find (_.opCode == Op.debugfile) match {
						case Some(op) => {
							val debugFile = op.asInstanceOf[DebugFile]
							val file = debugFile.file
							if(sourcePath.isEmpty || (sourcePath exists (file.name startsWith _))) {
								abcModified = true

								bytecode.replaceFrom(4, debugLine) {
									x =>
										observers foreach (_.instrument(file.name, x))

										DebugLine(x) ::
										coverageScope ::
										PushString(file) ::
										pushLine(x) ::
										coverageMethod :: Nil
								}

								body.maxStack += 3
							}
						}
						case None =>
					}
				}

				if(abcModified) {
					abc.cpool = (abc.cpool add coverageQName) add coverageOnSample
					abc.saveBytecode()
					abc write doABC
				}
			}
		}

		private def pushLine(line: Int) = line match {
			case x if x < 0x80 => PushByte(x)
			case x if x < 0x8000 => PushShort(x)
			case x => error("Too many lines.")
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy