[RT] Compile-time-data injection

Summary

Introduction of new Metadata Tags that instruct the compiler to fill-in arguments or properties with data that is available at compile-time.

Why?

Code is right now introspected using describeType, exception stack-traces (that only work in the debug players) and passing data by hand. Also: Developers need to set up ant tasks to pass in data like the build version or compiler flags or need to do some code twisting for it to work. If some of the data was compiled into the bytecode then performance could be traded for swf size. This is specially interesting for low-level apis like logging or dependency injection. All this could be achieved by including all compiler data into a swf but this would result in unnecessarily bloated swfs. An approach using meta-data would allow selective injection for those parts that are needed.

Mailinglist discussions

Trace & Log
Proposal Compile-time-data-injection

Available data

Type

Information about classes, their methods and those arguments. Basically things that are right now available with describeType and getQualifiedClassName.

Compiler Flags

Information about how, where and when the bytecode was generated.

key

description

type

example

compiler.version

version of the compiler

String

4.7

compiler.name

name of the compiler

String

mxmlc

compiler.os

operating system the compiler was running in

String

windows 32bit

compiler.setting.targetplayer

the targetplayer flag of the compiler

int

12

compiler.setting....

all other compiler flags

...

...

compile.constant.<customFlag>

Constant as defined in the execution

String

"true"

compile.time

utc-time since 1.1.1970 in ms

int

1328521237534

Caller

Information about the location a method was called from,

key

description

type

caller.type

Type in which the calling method was located

Type

caller.args

The arguments that have been passed to the caller

Array

call.clean

Called clean like foo.bar() or not (like foo["bar"]() or foo.bar.call(null))

Boolean

call.lineNo

The line number of the file of the type where the method has been called

int

call.preferedReturnType

Type that the code wants to work with afterwards

Type

call.args

Types passed in for all arguments

Array

call.arg.<argument>

Type for a particular argument

Type

Type Constant declarations

Information that the compiler has can not be changed during run-time thus should be only allowed to be set on constants.

[Fill(data="type")]
private static const typeInfo:XML;

This would be equal to writing:

private static const typeInfo:XML = describeType(Foo);

To preset a property if the compiler doesn't recognize (or ignore) that meta-data it is possible to set data like:

[Fill(data="compile.time")]
private static const compileTime:int=-1;

This way the code does have a standard content even when its not compiled with this system.
Variables do not have caller information available.

Method argument declarations

Method arguments should also be inject-able. The syntax is slightly different as it doesn't utilize the "data" property but naming the arguments in the meta data:

[Fill(args="caller.args")]
function foo(args:Array=null) {}

This means that the argument will be filled on call:

[Fill(args="caller.args")]
function foo(args:Array=null) {}
function bar(a:String, b:int) {
   foo();
}

will be transformed to an equivalent of

function foo(args:Array=null) {}
function bar(a:String, b:int) {
   foo([a,b]);
}

This means: always the calling code is rewritten, not the method itself!

Handling data

All the injected data would need to be made accessible using regular ActionScript3 data types. While a XML can be nicely edited and stepped through it also is a quite heavy in its consumption and ultimately unnecessary if you use other code. To make life easier, there should be a possible way of automatic type conversion.

[Fill(data="type")]
const type: XML; // Type as in describe-type

[Fill(data="type")]
const type: Object; // describe-type xml in a object tree

[Fill(data="compile.time")]
const time: int; // Time as Integer;

[Fill(data="compile.time")]
const time: String; // Time as String;

[Fill(data="compile.time")]
const time: Date; // Time as Date;

[Fill(bar="call.arg.content")]
function foo(content:*, bar:Class=null); // Content type as class

[Fill(bar="call.arg.content")]
function foo(content:*, bar:String=null); // Content type as String

[Fill(bar="call.arg.content")]
function foo(content:*, bar:XML=null); // Content type as XML

Treating swc's

The meta-data has to be preserved at the compilation to bytecode. Within the swc the bytecode is not additionally compiled. This means all code that accesses the compiled meta-data can know about how its fill but the parts are not "re-compiled" to avoid breaking logic of the former compilation.

Warnings and errors

Activity warning

As this is a new compiler feature it might be reasonable to notify developers that use this feature at compile time this feature is used once its used.

Some compile-time-data has been compiled into the swf. Set -auto-fill=true to not see this message again.

Type error

Of course if the type of the data can not be converted properly into the declared type there should be a compile error:

[Fill(data="compiler.version")]
private static const version: Foo; // "compiler.version" is of type "String" and can not be converted to "Foo"
Dynamic method warning

If a method that requires compiler filled data is referenced dynamically there should be a warning stating that the compiler will not be able to pre-fill the data.

[Fill(a="call.argument.a")]
function foo(a:Class) {}
var a: Function = foo; // The method "foo" is assigned to a variable. It will not be possible for the compiler to prefill the variable calls properly
Missing information

References to information that is not available should result in errors:

[Fill(data="bunny")]// There is no property "bunny" available in this context.

Compiler flags

flag

value

meaning

auto-fill

true/false/undefined

Sets the activity state of filling data