def initialize_classes(self): asm = assembler.CodeAssembler([]) clstraits = [] for name in self.order: rib, bases = self.tracking[name] if constants.QName("Object") not in bases: bases.append(constants.QName("Object")) asm.emit('getscopeobject', 0) for base in reversed(bases): asm.emit('getlex', base) asm.emit('pushscope') asm.emit('getlex', rib.super_name) asm.emit('newclass', rib.index) asm.emit('initproperty', rib.name) clstraits.append(traits.ClassTrait(name, rib.classobj)) for base in bases: asm.emit('popscope') return asm, clstraits
def dump_class(self, cls): inst = cls.instance line = [] line.append("interface " if inst.is_interface else "class ") line.append(str(cls.name)) if inst.super_name: line.append(" extends %s" % (cls.instance.super_name, )) if inst.interfaces: if inst.is_interface: line.append(" extends ") else: line.append(" implements ") line.append(', '.join(interface.name for interface in inst.interfaces)) self.output(''.join(line)) self.output("{") self.indent() cls.cinit.name = "%s$cinit" % (cls.name.name, ) cls.cinit.return_type = constants.QName("void") cls.instance.iinit.name = "%s$iinit" % (cls.name.name, ) self.dump_method(cls.cinit, ["static"]) self.dump_method(inst.iinit, []) self.dump_traits(cls, ["static"]) self.dump_traits(inst, []) self.outdent() self.output("}") self.output()
def test_multinames(): asm = assembler.CodeAssembler([]) asm.emit("getlex", "String") const = constants.ConstantPool() const.write(asm) assert const.multiname.value_at(1) == constants.QName("String")
def dump_abc(self): self.output("constants:") pool = self.abc.constants self.indent() self.dump_pool("ints", pool.int) self.dump_pool("uints", pool.uint) self.dump_pool("doubles", pool.double) self.dump_pool("utf8", pool.utf8) self.dump_pool("namespaces", pool.namespace) self.dump_pool("nssets", pool.nsset) self.dump_pool("multinames", pool.multiname) self.outdent() self.output() for i, script in enumerate(self.abc.scripts): self.output("script" + str(i)) self.output("{") self.indent() script.init.name = constants.QName("script%d$init" % (i, )) script.init.return_type = constants.QName("*") self.dump_method(script.init, []) self.dump_traits(script, []) self.outdent() self.output("}") self.output() # Leftover methods like closures. for method in set(self.abc.methods) - self.methods_seen: self.dump_method(method, []) self.output("// stats:") self.output("// %d methods, %d bodies" % (self.meth_count, self.body_count)) self.output("// %d properties" % (self.prop_count, )) self.output("// %d slots" % (self.slot_count, ))
def make_iinit(self, params=None, varargs=None, defaults=None, optimize=None): params = params or () if not self.iinit: self.iinit = Method("$iinit", params, constants.QName("void")) self.iinit.asm.emit('getlocal0') self.iinit.asm.emit('constructsuper', 0) rib = MethodRib(self.iinit) rib.constructor = True return rib
class CodeGenerator(object): """ CodeGenerator is a nice generator interface for generating common idioms in methods. """ def __init__(self, abc, optimize=False): self.abc = abc self.constants = self.abc.constants self.optimize = optimize # Stack of old ribs. self.ribs = [] # Current rib, not on rib stack. self.current_rib = None self.pending_nodes = [] self.current_node = None def enter_rib(self, rib): self.ribs.append(self.current_rib) self.current_rib = rib return rib def exit_current_rib(self): self.current_rib.finalize(self) self.current_rib = self.ribs.pop() def get_current_assembler(self): return self.current_rib.method.asm current_assembler = property(get_current_assembler) def begin_class(self, name, base="Object"): """ Create a new class with the name `name` and superclass `base`. """ return self.enter_rib(self.current_rib.new_class(name, base)) def begin_method(self, name, params, rettype, static=False, override=False): return self.enter_rib( self.current_rib.new_method(name, params, rettype, static, override)) def begin_script(self): return self.enter_rib(ScriptRib()) def render_nodes(self): done = set() while self.pending_nodes: node = self.pending_nodes.pop() for dep in node.dependencies(): if dep not in done: self.current_node = dep dep.render(self) done.add(dep) self.current_node = node node.render(self) done.add(node) self.current_node = None def finish(self): """ Finalize this generator, by rendering all nodes and exiting all contexts. If you don't finalize before serializing, some code may be missing from the final result. """ while self.current_rib: self.exit_current_rib() self.render_nodes() def emit(self, name, *a, **kw): """ Emit an instruction, with given arguments. """ self.current_rib.method.asm.emit(name, *a, **kw) def pop(self): """ Pop an item from the stack. """ self.emit('pop') def dup(self, TYPE=None): """ Duplicate the top item on the stack. In Tamarin, this just duplicates the pointer, it doesn't duplicate the actual object. """ self.emit('dup') if TYPE: self.downcast(TYPE) def throw(self): """ Throw the top item on the stack. """ self.emit('throw') def swap(self): """ Swap the top two items on the stack. """ self.emit('swap') def set_label(self, lblname): """ Set the current label to be "lblname". The branching machinery should be taken care of for you. """ self.emit('label', lblname) def branch_unconditionally(self, lblname): """ Branch unconditionally to "lblname", also called a "jump". Note: if a jump results in a net zero offset, a jump instruction won't be generated. """ self.emit('jump', lblname) def branch_conditionally(self, iftrue, lblname): """ Branch to "lblname" if the top of the stack, converted to a boolean, is the same as "iftrue", converted to a boolean. """ if iftrue: self.branch_if_true(lblname) else: self.branch_if_false(lblname) def branch_if_true(self, lblname): self.emit('iftrue', lblname) def branch_if_false(self, lblname): self.emit('iffalse', lblname) def branch_if_equal(self, lblname): self.emit('ifeq', lblname) def branch_if_strict_equal(self, lblname): self.emit('ifstricteq', lblname) def branch_if_not_equal(self, lblname): self.emit('ifne', lblname) def branch_if_strict_not_equal(self, lblname): self.emit('ifstrictne', lblname) def branch_if_greater_than(self, lblname): self.emit('ifgt', lblname) def branch_if_greater_equals(self, lblname): self.emit('ifge', lblname) def branch_if_less_than(self, lblname): self.emit('iflt', lblname) def branch_if_less_equals(self, lblname): self.emit('ifle', lblname) def branch_if_not_greater_than(self, lblname): self.emit('ifngt', lblname) def branch_if_not_greater_equals(self, lblname): self.emit('ifnge', lblname) def branch_if_not_less_than(self, lblname): self.emit('ifnlt', lblname) def branch_if_not_less_equals(self, lblname): self.emit('ifnle', lblname) def call_function(self, name, args, TYPE=None, void=False): """ Call the global function "name" with the constant arguments "args". Find the owner of the function "name", push every element of "args" onto the stack, and call the function. If a keyword argument "void" that is passed in is True, it will use callpropvoid instead of callproperty, which discards the undefined return value that exists on the stack. """ self.emit('findpropstrict', name) self.call_method(name, None, args, TYPE, void) def call_method(self, name, receiver, args=(), TYPE=None, void=False): """ Call the method "name" on "receiver" with args. If "TYPE" is passed in, it will attempt to cast the value on the top of the stack before returning the value. If "void" is True, no object will be on the stack after. """ if receiver: self.load(receiver) self.load_many(args) if void: instruction = 'callpropvoid' else: instruction = 'callproperty' self.emit(instruction, name, len(args)) if TYPE: self.downcast(TYPE) def construct_type(self, name, args=()): self.emit('findpropstrict', name) self.load_many(args) self.emit('constructprop', name, len(args)) def return_value(self): """ Return the top value on the stack. """ self.emit('returnvalue') def return_void(self): """ Return nothing. """ self.emit('returnvoid') def store_var(self, name): """ Stores a local variable. Pop a value off the stack and store it in the local occupied to "name" :param name: the name the local variable """ index = self.current_rib.method.asm.set_local(name) self.emit('setlocal', index) return index def load(self, value): """ Load an ILoadable on to the stack. """ ILoadable(value).load(self) def load_many(self, values): """ Load multiple ILoadables on to the stack. """ for value in values: self.load(value) def init_array(self, members=None): """ Initialize an Array with the list "members". """ if members: self.load_many(members) self.emit('newarray', len(members)) def new_array(self, length=1): """ Creates an Array with the given length. """ self.emit('findpropstrict', "Array") self.load(length) self.emit('constructprop', "Array", 1) def init_object(self, members=None): """ Initialize an Object with the dictionary "members". """ for key, val in members.iteritems(): self.load(key) self.load(val) self.emit('newobject', len(members)) def _get_vector_type(self, TYPE): """ Returns a TypeName of Vector with the given TYPE. """ from fusion.avm2 import playerglobal TYPE = IMultiname(TYPE) Vector = playerglobal.__AS3__.vec.Vector if TYPE in Vector.SpecializedFast: return Vector.SpecializedFast[TYPE] return constants.TypeName(Vector, (TYPE, )) def init_vector(self, TYPE, members=None): """ Initializes a Vector of TYPE with the list "members". """ typename = self._get_vector_type(TYPE) self.load(typename) self.load_many(members) self.emit('construct', len(members)) self.downcast(typename) def new_vector(self, TYPE, length=1): """ Creates a strongly typed Vector of the type "TYPE". """ typename = self._get_vector_type(TYPE) self.load(typename) self.load(length) self.emit('construct', 1) self.downcast(typename) def set_field(self, fieldname, TYPE=None): """ Sets the field "fieldname" on an object. If "TYPE" is passed in, it will attempt to cast the value on the top of the stack before setting the field. Pops "value" from the stack. Pops "obj" from the stack. Sets the field named "fieldname" on "obj" with the value "value". """ if TYPE: self.downcast(TYPE) self.emit('setproperty', fieldname) fast_cast = { constants.QName("String"): 'coerce_s', constants.QName("*"): 'coerce_a', constants.QName("uint"): 'convert_u', constants.QName("int"): 'convert_i', constants.QName("Number"): 'convert_d', constants.QName("Object"): 'convert_o', constants.QName("Boolean"): 'convert_b', } def downcast(self, TYPE): """ Attempts to downcast an object to "TYPE". Pops an object "obj" from the top of the stack, checks if it inherits or implements TYPE. If it does, it pushes "obj" back on the top of the stack. Otherwise, it pushes the constant null on the top of the stack. """ TYPE = IMultiname(TYPE) if TYPE in self.fast_cast: self.emit(self.fast_cast[TYPE]) else: self.emit('coerce', TYPE) def isinstance(self, TYPE): """ Checks if an object is an instance of TYPE. Pops an object from the top of the stack, checks if it inherits or implements TYPE, and pushes that boolean onto the stack. """ self.emit('istype', IMultiname(TYPE)) def gettype(self): """ Takes the top object on the stack, and replaces it with the type (constructor) of that object. """ self.load(loadable.Field("constructor")) def begin_try(self): """ Begin a try block. """ self.emit('begintry', self.current_rib) def end_try(self): """ End a try block. """ self.emit('endtry', self.current_rib) def begin_catch(self, TYPE): """ Begin a catch block, attempting to catch TYPE. """ name = IMultiname(TYPE) rib = CatchRib(self.current_rib) idx = self.current_rib.add_exception(name) self.current_rib.restore_scopes() self.enter_rib(rib) self.emit('begincatch') self.emit('newcatch', idx) self.dup() self.store_var(rib.local) self.dup() self.emit('pushscope') self.swap() self.emit('setslot', 1) def push_exception(self, nest=None): """ Attempt to push the current exception. """ self.emit('getscopeobject', nest or self.current_rib.scope_nest) self.load(loadable.Slot(1)) def end_catch(self): """ End a catch block. """ self.emit('popscope') self.emit( 'kill', self.current_rib.method.asm.kill_local(self.current_rib.local)) self.exit_current_rib() def add_node(self, node): """ Add a node to the pending nodes of this code generator. """ self.pending_nodes.append(INode(node))