Skip to content
This repository has been archived by the owner on Nov 9, 2017. It is now read-only.

Commit

Permalink
Fixing the NullTrace method
Browse files Browse the repository at this point in the history
  • Loading branch information
Simon Richardson committed Mar 29, 2012
1 parent c6c0f50 commit b342000
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 50 deletions.
22 changes: 20 additions & 2 deletions src/com/codeazur/as3swf/SWFActionScriptContainer.as
Expand Up @@ -21,6 +21,7 @@ package com.codeazur.as3swf
*/
public class SWFActionScriptContainer extends SWFTimelineContainer {

private static const NUM_MERGE_PASSES:uint = 3;
private static const ABC_THRESHOLD:uint = 50;
private static const TAG_DO_ABC_MERGE_NAME:String = "tags/merge";

Expand Down Expand Up @@ -81,8 +82,10 @@ package com.codeazur.as3swf
if(total > 1) {
_tmpIndex = total;
_timeout = setTimeout(readABCTagAsyncHandler, 1);
dispatchMergeProgress(0);
} else {
dispatchEvent(new SWFMergeProgressEvent(SWFMergeProgressEvent.MERGE_COMPLETE, 1, 1));
dispatchMergeProgress(0);
dispatchMergeComplete();
}
}

Expand All @@ -107,6 +110,7 @@ package com.codeazur.as3swf
private function readABCTagAsyncHandler():void {
if(--_tmpIndex > -1) {
readABCTag(_tmpIndex);
dispatchMergeProgress(_tmpIndex);
_timeout = setTimeout(readABCTagAsyncHandler, 1);
} else {
mergeDataSetAsync();
Expand All @@ -131,6 +135,7 @@ package com.codeazur.as3swf
private function mergeDataSetAsyncHandler():void {
if(--_tmpIndex > -1) {
mergeDataSet(_tmpIndex);
dispatchMergeProgress(_tmpIndex);
_timeout = setTimeout(mergeDataSetAsyncHandler, 1);
} else {
writeDataSetAsync();
Expand Down Expand Up @@ -158,9 +163,11 @@ package com.codeazur.as3swf
private function writeDataSetAsyncHandler():void {
if(--_tmpIndex > -1) {
writeDataSet(_tmpIndex);
dispatchMergeProgress(_tmpIndex);
_timeout = setTimeout(writeDataSetAsyncHandler, 1);
} else {
dispatchEvent(new SWFMergeProgressEvent(SWFMergeProgressEvent.MERGE_COMPLETE, 1, 1));
dispatchMergeProgress(_tmpIndex);
dispatchMergeComplete();
}
}

Expand All @@ -180,5 +187,16 @@ package com.codeazur.as3swf
}
return result;
}

private function dispatchMergeProgress(value:uint):void {
const total:uint = _estimatedDataSetLength * NUM_MERGE_PASSES;
const inverted:int = total - value;
dispatchEvent(new SWFMergeProgressEvent(SWFMergeProgressEvent.MERGE_PROGRESS, inverted, total));
}

private function dispatchMergeComplete():void {
const total:uint = _estimatedDataSetLength * NUM_MERGE_PASSES;
dispatchEvent(new SWFMergeProgressEvent(SWFMergeProgressEvent.MERGE_COMPLETE, total, total));
}
}
}
17 changes: 17 additions & 0 deletions src/com/codeazur/as3swf/data/abc/ABCTraitSet.as
@@ -1,5 +1,6 @@
package com.codeazur.as3swf.data.abc
{
import com.codeazur.as3swf.data.abc.bytecode.traits.ABCTraitMethodInfo;
import com.codeazur.as3swf.SWFData;
import com.codeazur.as3swf.data.abc.bytecode.IABCMultiname;
import com.codeazur.as3swf.data.abc.bytecode.traits.ABCTraitInfo;
Expand Down Expand Up @@ -74,6 +75,22 @@ package com.codeazur.as3swf.data.abc
}
}

public function hasTrait(kind:ABCTraitInfoKind, multiname:IABCMultiname):Boolean {
var result:Boolean = false;
const total:uint = traits.length;

for(var i:uint=0; i<total; i++) {
const trait:ABCTraitInfo = traits[i];
if(ABCTraitInfoKind.isType(trait.kind, kind)) {
if(trait.multiname.equals(multiname)){
result = true;
}
}
}

return result;
}

public function get numMethodTraits():uint {
var result:uint = 0;
var index:int = traits.length;
Expand Down
15 changes: 15 additions & 0 deletions src/com/codeazur/as3swf/data/abc/bytecode/ABCInstanceInfoSet.as
Expand Up @@ -78,6 +78,21 @@ package com.codeazur.as3swf.data.abc.bytecode
return instanceInfos[index];
}

public function getByMultiname(multiname:IABCMultiname):ABCInstanceInfo {
var result:ABCInstanceInfo;

const total:uint = instanceInfos.length;
for(var i:uint=0; i<total; i++) {
const instanceInfo:ABCInstanceInfo = instanceInfos[i];
if(instanceInfo.qname.equals(multiname)) {
result = instanceInfo;
break;
}
}

return result;
}

override public function get name() : String { return "ABCInstanceInfoSet"; }
override public function get length():uint { return instanceInfos.length; }

Expand Down
Expand Up @@ -33,7 +33,7 @@ package com.codeazur.as3swf.data.abc.bytecode
for(var i:uint=0; i<total; i++) {
const m:ABCMethodBody = methodBodies[i];
if(methodName == m.methodInfo.methodName) {
throw new Error('Method name already exists');
throw new Error('Method name already exists (recieved:' + methodName + ')');
}
}
abcData.methodInfoSet.addAt(methodInfo, index);
Expand Down
Expand Up @@ -33,7 +33,12 @@ package com.codeazur.as3swf.data.abc.bytecode.multiname
}

public function equals(ns:ABCNamespace):Boolean {
return (this == ns) || (byte == ns.byte && value == ns.value && kind.equals(ns.kind));
if(this == ns) {
return true;
} else if(byte == ns.byte && value == ns.value && kind.equals(ns.kind)) {
return true;
}
return false;
}

public function clone():ABCNamespace {
Expand Down
Expand Up @@ -12,6 +12,7 @@ package com.codeazur.as3swf.data.abc.bytecode.multiname
const ns:ABCNamespace = ABCNamespace.create(nsType.type, parts.join('.'));
const qname:ABCQualifiedName = ABCQualifiedName.create(name, ns);
qname.byte = ABCMultinameKind.QNAME.type;
qname.ns.byte = nsType.type;
return qname;
}

Expand Down
107 changes: 61 additions & 46 deletions src/com/codeazur/as3swf/data/abc/tools/ABCRemoveTraceOpcodes.as
@@ -1,10 +1,10 @@
package com.codeazur.as3swf.data.abc.tools
{
import flash.utils.getTimer;
import com.codeazur.as3swf.data.abc.bytecode.ABCInstanceInfo;
import com.codeazur.as3swf.data.abc.bytecode.traits.ABCTraitInfoKind;
import com.codeazur.as3swf.data.abc.bytecode.multiname.ABCNamespaceKind;
import com.codeazur.as3swf.data.abc.bytecode.multiname.ABCNamespaceType;
import com.codeazur.as3swf.data.abc.ABCData;
import com.codeazur.as3swf.data.abc.bytecode.ABCExceptionInfoSet;
import com.codeazur.as3swf.data.abc.bytecode.ABCInstanceInfo;
import com.codeazur.as3swf.data.abc.bytecode.ABCMethodBody;
import com.codeazur.as3swf.data.abc.bytecode.ABCMethodInfo;
import com.codeazur.as3swf.data.abc.bytecode.ABCMethodInfoFlags;
Expand All @@ -16,8 +16,11 @@ package com.codeazur.as3swf.data.abc.tools
import com.codeazur.as3swf.data.abc.bytecode.attributes.ABCOpcodeAttribute;
import com.codeazur.as3swf.data.abc.bytecode.attributes.ABCOpcodeMultinameAttribute;
import com.codeazur.as3swf.data.abc.bytecode.attributes.ABCOpcodeMultinameUIntAttribute;
import com.codeazur.as3swf.data.abc.bytecode.multiname.ABCQualifiedName;
import com.codeazur.as3swf.data.abc.bytecode.multiname.ABCQualifiedNameBuilder;
import com.codeazur.as3swf.data.abc.bytecode.traits.ABCTraitInfoFactory;
import com.codeazur.as3swf.data.abc.bytecode.traits.ABCTraitInfoFlags;
import com.codeazur.as3swf.data.abc.bytecode.traits.ABCTraitInfoKind;
import com.codeazur.as3swf.data.abc.bytecode.traits.ABCTraitMethodInfo;
/**
* @author Simon Richardson - simon@ustwo.co.uk
Expand All @@ -31,12 +34,12 @@ package com.codeazur.as3swf.data.abc.tools
public function ABCRemoveTraceOpcodes() {
}

public function visit(value : ABCData) : void {
const total:uint = value.methodBodySet.length;
public function visit(abcData : ABCData) : void {
const total:uint = abcData.methodBodySet.length;
for(var i:uint=0; i<total; i++){
const traceOpcodes:Vector.<ABCOpcode> = new Vector.<ABCOpcode>();

const methodBody:ABCMethodBody = value.methodBodySet.getAt(i);
const methodBody:ABCMethodBody = abcData.methodBodySet.getAt(i);
const opcodes:ABCOpcodeSet = methodBody.opcodes;
var multiname:IABCMultiname;
var index:int = opcodes.length;
Expand All @@ -49,6 +52,7 @@ package com.codeazur.as3swf.data.abc.tools
const multinameAttribute:ABCOpcodeMultinameAttribute = ABCOpcodeMultinameAttribute(attribute);
multiname = multinameAttribute.multiname;
if(multiname.fullName == TRACE_NAME) {
// Swap out the findpropstrict for a getlocal0
const getLocal0:ABCOpcode = ABCOpcode.create(abcData, ABCOpcodeKind.GETLOCAL_0, ABCOpcodeAttribute.create(abcData));
opcodes.opcodes.splice(index, 1, getLocal0);
}
Expand All @@ -67,46 +71,7 @@ package com.codeazur.as3swf.data.abc.tools
// Inject a new method into the mix
const traceTotal:uint = traceOpcodes.length;
if(traceTotal > 0) {
const abcData:ABCData = methodBody.abcData;
const empty:ABCMethodBody = ABCMethodBody.create(methodBody.abcData);

// TODO: change this so that we can use a builder.
empty.methodInfo = ABCMethodInfo.create(abcData);
empty.methodInfo.returnType = ABCQualifiedNameBuilder.create("void");
empty.methodInfo.methodNameLabel = NULL_TRACE_NAME + getTimer();
empty.methodInfo.scopeName = methodBody.methodInfo.scopeName;
empty.methodInfo.methodName = empty.methodInfo.scopeName + "/" + empty.methodInfo.methodNameLabel;
empty.methodInfo.multiname = ABCQualifiedNameBuilder.create(empty.methodInfo.methodName);
empty.methodInfo.methodBody = empty;
empty.methodInfo.flags = ABCMethodInfoFlags.NEED_REST.type;
empty.methodInfo.parameters = new Vector.<ABCParameter>();

empty.exceptionInfo = ABCExceptionInfoSet.create(abcData);

empty.maxStack = 1;
empty.localCount = 1;
empty.initScopeDepth = 9;
empty.maxScopeDepth = 10;

empty.opcodes = ABCOpcodeSet.create(abcData);
empty.opcodes.opcodes.push(ABCOpcode.create(abcData, ABCOpcodeKind.GETLOCAL_0, ABCOpcodeAttribute.create(abcData)));
empty.opcodes.opcodes.push(ABCOpcode.create(abcData, ABCOpcodeKind.PUSHSCOPE, ABCOpcodeAttribute.create(abcData)));

value.methodBodySet.addAt(empty, value.methodBodySet.length - 1);

const traitQName:IABCMultiname = ABCQualifiedNameBuilder.create(empty.methodInfo.methodNameLabel);
abcData.constantPool.addMultiname(traitQName);
const trait:ABCTraitMethodInfo = ABCTraitMethodInfo(ABCTraitInfoFactory.create(abcData, ABCTraitInfoKind.METHOD.type, traitQName));
trait.id = 1;
trait.methodInfo = empty.methodInfo;

for(var k:uint=0; k<value.instanceInfoSet.length; k++) {
const instanceInfo:ABCInstanceInfo = value.instanceInfoSet.getAt(k);
if(instanceInfo.qname.fullName == methodBody.methodInfo.scopeName) {
instanceInfo.addTrait(trait);
break;
}
}
const traitQName:IABCMultiname = createEmptyMethod(abcData, methodBody.methodInfo.scopeName);

// Create a new multiname
for(var j:uint=0; j<traceTotal; j++) {
Expand All @@ -121,5 +86,55 @@ package com.codeazur.as3swf.data.abc.tools
}
}
}

private function createEmptyMethod(abcData:ABCData, scopeName:String):IABCMultiname {
const qname:ABCQualifiedName = ABCQualifiedNameBuilder.create(scopeName);
const instanceInfo:ABCInstanceInfo = abcData.instanceInfoSet.getByMultiname(qname);

if(!instanceInfo) {
throw new Error('Invalid Instance Info');
}

// Seems we already have a null trace method, use it!
const traitQName:IABCMultiname = ABCQualifiedNameBuilder.create(NULL_TRACE_NAME, ABCNamespaceKind.PRIVATE_NAMESPACE.type);
if(instanceInfo.hasTrait(ABCTraitInfoKind.METHOD, traitQName)) {
return traitQName;
}

// TODO: change this so that we can use a builder.
const empty:ABCMethodBody = ABCMethodBody.create(abcData);

empty.methodInfo = ABCMethodInfo.create(abcData);
empty.methodInfo.returnType = ABCQualifiedNameBuilder.create("void");
empty.methodInfo.methodNameLabel = traitQName.fullName;
empty.methodInfo.scopeName = scopeName;
empty.methodInfo.methodName = empty.methodInfo.scopeName + "/" + empty.methodInfo.methodNameLabel;
empty.methodInfo.multiname = ABCQualifiedNameBuilder.create(empty.methodInfo.methodName);
empty.methodInfo.methodBody = empty;
empty.methodInfo.flags = ABCMethodInfoFlags.NEED_REST.type;
empty.methodInfo.parameters = new Vector.<ABCParameter>();

empty.exceptionInfo = ABCExceptionInfoSet.create(abcData);

empty.maxStack = 1;
empty.localCount = 1;
empty.initScopeDepth = 9;
empty.maxScopeDepth = 10;

empty.opcodes = ABCOpcodeSet.create(abcData);
empty.opcodes.opcodes.push(ABCOpcode.create(abcData, ABCOpcodeKind.GETLOCAL_0, ABCOpcodeAttribute.create(abcData)));
empty.opcodes.opcodes.push(ABCOpcode.create(abcData, ABCOpcodeKind.PUSHSCOPE, ABCOpcodeAttribute.create(abcData)));

abcData.methodBodySet.addAt(empty, abcData.methodBodySet.length - 1);

abcData.constantPool.addMultiname(traitQName);
const trait:ABCTraitMethodInfo = ABCTraitMethodInfo(ABCTraitInfoFactory.create(abcData, ABCTraitInfoKind.METHOD.type, traitQName));
trait.id = 1;
trait.methodInfo = empty.methodInfo;

instanceInfo.addTrait(trait);

return traitQName;
}
}
}

0 comments on commit b342000

Please sign in to comment.