Nice! Opcodes are working too... I just weaved in the "setHandler"
method along with opcodes to trace a message from Loom. describeType()
output and Loom API code for weaving the method are listed below.
Clearly the API needs some usability work, but it's getting the job
done.
<type name="loom.template::BaseClass" base="Class" isDynamic="true"
isFinal="true" isStatic="true">
<extendsClass type="Class"/>
<extendsClass type="Object"/>
<accessor name="prototype" access="readonly" type="*"
declaredBy="Class"/>
<factory type="loom.template::BaseClass">
<extendsClass type="Object"/>
<constructor>
<parameter index="1" type="*" optional="false"/>
<parameter index="2" type="*" optional="false"/>
</constructor>
<method name="methodCallOne" declaredBy="loom.template::BaseClass"
returnType="int">
<parameter index="1" type="String" optional="false"/>
<parameter index="2" type="Number" optional="false"/>
</method>
<method name="setHandler" declaredBy="loom.template::BaseClass"
returnType="void" uri="
http://loom.ninjitsoft.com">
<parameter index="1" type="String" optional="false"/>
<parameter index="2" type="Function" optional="false"/>
</method>
<method name="methodCallThree"
declaredBy="loom.template::BaseClass" returnType="String">
<parameter index="1" type="String" optional="false"/>
<parameter index="2" type="Number" optional="false"/>
</method>
<method name="methodCallTwo" declaredBy="loom.template::BaseClass"
returnType="void">
<parameter index="1" type="String" optional="false"/>
<parameter index="2" type="Number" optional="false"/>
<parameter index="3" type="Object" optional="false"/>
</method>
<variable name="handlerMappings" type="flash.utils::Dictionary"
uri="
http://loom.ninjitsoft.com"/>
</factory>
</type>
// Add the setHandler method info
var setHandlerMethodInfo : MethodInfo = new MethodInfo();
setHandlerMethodInfo.loomName = setHandlerQName;
setHandlerMethodInfo.methodName = "";
setHandlerMethodInfo.argumentCollection.push(new Argument
(QualifiedName.STRING));
setHandlerMethodInfo.argumentCollection.push(new Argument
(QualifiedName.FUNCTION));
setHandlerMethodInfo.returnType = QualifiedName.VOID;
abcFile.methodInfo.push(setHandlerMethodInfo);
// Add the setHandler method trait
var setHandlerTrait : MethodTrait = new MethodTrait();
setHandlerTrait.traitMultiname = setHandlerQName;
setHandlerTrait.traitKind = TraitKind.METHOD;
setHandlerTrait.isOverride = false;
setHandlerTrait.dispositionId = 0;
setHandlerTrait.traitMethod = setHandlerMethodInfo;
instance.traits.push(setHandlerTrait);
// Add the setHandler method body
var setHandlerBody : MethodBody = new MethodBody();
setHandlerBody.initScopeDepth = 4;
setHandlerBody.localCount = 4;
setHandlerBody.maxScopeDepth = 5;
setHandlerBody.maxStack = 2;
setHandlerBody.methodSignature = setHandlerMethodInfo;
var traceMultinamePosition : int =
abcFile.constantPool.getMultinamePositionByName("trace");
var message : String = "This is a message woven in by Loom!";
abcFile.constantPool.addString(message);
setHandlerBody.opcodes = [
Opcode.getlocal_0.op(),
Opcode.pushscope.op(),
Opcode.findpropstrict.op([abcFile.constantPool.multinamePool
[traceMultinamePosition]]),
Opcode.pushstring.op([message]),
Opcode.callproperty.op([1, abcFile.constantPool.multinamePool
[traceMultinamePosition]]),
Opcode.pop.op(),
Opcode.returnvoid.op()
];
abcFile.methodBodies.push(setHandlerBody);
Here's the code for loading the class ref and executing the method
call (still asynchronous since I haven't written the SWF enhancer
yet).
var classLoader : AbcClassLoader = new AbcClassLoader();
classLoader.addEventListener(
Event.COMPLETE,
function (event : Event) : void
{
var classRef : * = getDefinitionByName
("loom.template::BaseClass");
trace(describeType(classRef));
var instance : * = new classRef(null, null);
instance.loom_namespace::handlerMappings = new Dictionary();
instance.loom_namespace::handlerMappings["hello"] = "Hello
Loom!";
trace(instance.loom_namespace::handlerMappings["hello"]);
instance.loom_namespace::setHandler(null, null);
}
);
classLoader.loadClassDefinitionsFromBytecode([
new AbcSerializer().serializeAbcFile(proxyFile)
]);