Exemple #1
0
    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
Exemple #2
0
    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()
Exemple #3
0
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")
Exemple #4
0
    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, ))
Exemple #5
0
    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
Exemple #6
0
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))