X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fas3%2Finitcode.c;h=eebfa132a4a9b80e0420d4f65620e54c9aea3831;hb=c63b2bf21dc1df9a736f0b4c08f6cba828cdab92;hp=59d2efca7eacc79b24df52e784ed58311dfd7a20;hpb=b8aa0577aae67db4da5221459102202febc5c103;p=swftools.git diff --git a/lib/as3/initcode.c b/lib/as3/initcode.c index 59d2efc..eebfa13 100644 --- a/lib/as3/initcode.c +++ b/lib/as3/initcode.c @@ -1,23 +1,221 @@ +/* initcode.c + + Routines for handling/compiling Flash2 AVM2 ABC Actionscript + + Extension module for the rfxswf library. + Part of the swftools package. + + Copyright (c) 2008,2009 Matthias Kramm + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include +#include "../q.h" #include "abc.h" #include "code.h" +#include "common.h" #include "registry.h" #include "initcode.h" -void initcode_add_classlist(abc_script_t*init, parsedclass_list_t*classes) +int compare_parsedclass(const void *_v1, const void *_v2) +{ + parsedclass_t*p1 = *(parsedclass_t**)_v1; + parsedclass_t*p2 = *(parsedclass_t**)_v2; + if((p1->cls->flags^p2->cls->flags)&FLAG_INTERFACE) { + return (int)(p2->cls->flags&FLAG_INTERFACE) - (int)(p1->cls->flags&FLAG_INTERFACE); + } + classinfo_t*c2 = dict_lookup(&p1->parents, p2); + classinfo_t*c1 = dict_lookup(&p2->parents, p1); + assert(!c1 || !c2); // otherwise we would have a loop + assert(!c1 || c1==p1->cls); + assert(!c2 || c2==p2->cls); + + if(c1) { + return -1; + } + if(c2) { + return 1; + } + + c2 = dict_lookup(&p1->usedclasses_deep, p2); + c1 = dict_lookup(&p2->usedclasses_deep, p1); + assert(!c1 || !c2); + assert(!c1 || c1==p1->cls); + assert(!c2 || c2==p2->cls); + if(c1) { + return -1; + } + if(c2) { + return 1; + } + + return 0; +} + +static void add_parent(parsedclass_t*p, classinfo_t*c, dict_t*s2p, char soft) +{ + dict_t*parents = soft?(&p->usedclasses_deep):(&p->parents); + int t; + if(dict_contains(parents, p)) { + if(soft) { + as3_warning("circular reference: class %s references self (through static code)", p->cls->name); + return; + } else { + syntaxerror("circular reference: class %s references self", p->cls->name); + } + } + + if(c) { + parsedclass_t*n = dict_lookup(s2p, c); + if(n && !dict_contains(parents, n)) { + assert(n->cls == c); + dict_put(parents, n, c); + } + } else { + c = p->cls; + } + + if(soft && dict_contains(s2p, c)) { + parsedclass_t*pp = dict_lookup(s2p, c); + DICT_ITERATE_KEY(&pp->usedclasses, classinfo_t*, cc) { + add_parent(p, cc, s2p, soft); + } + } + if(c->superclass) { + add_parent(p, c->superclass, s2p, soft); + } + for(t=0;c->interfaces[t];t++) { + add_parent(p, c->interfaces[t], s2p, soft); + } +} + +parsedclass_t* parsedclass_new(classinfo_t*cls, abc_class_t*abc) +{ + NEW(parsedclass_t,p); + p->cls = cls; + p->abc = abc; + dict_init2(&p->parents, &ptr_type, 1); + dict_init2(&p->usedclasses, &ptr_type, 1); + dict_init2(&p->usedclasses_deep, &ptr_type, 1); + return p; +} + +/* sort classes so that + (a) interfaces appear before classes + (b) base classes always appear before their subclasses + (c) classes appear after the classes they use in static code +*/ +parsedclass_t** initcode_sort_classlist(parsedclass_list_t*classes) +{ + dict_t* s2p = dict_new2(&ptr_type); + + /* create hash tables */ + int count = 0; + parsedclass_list_t*l; + for(l=classes;l;l=l->next) { + dict_put(s2p, l->parsedclass->cls, l->parsedclass); + count++; + } + for(l=classes;l;l=l->next) { + add_parent(l->parsedclass, 0, s2p, 0); + DICT_ITERATE_KEY(&l->parsedclass->usedclasses, classinfo_t*, c) { + add_parent(l->parsedclass, c, s2p, 1); + } + } + + parsedclass_t**list = malloc(sizeof(parsedclass_t*)*count); + + /* build an array for each class */ + int i = 0; + for(l=classes;l;l=l->next) { + list[i++] = l->parsedclass; + } + + /* sort and flatten. + We unfortunately need to do insertion sort O(n^2) as + our dependencies are only partially ordered */ + int j; + for(i=0;i0) { + parsedclass_t*p1 = list[i]; + parsedclass_t*p2 = list[j]; + list[i] = p2; + list[j] = p1; + } + } + } + + parsedclass_t**list2 = malloc(sizeof(parsedclass_t*)*(count+1)); + for(i=0;icls->name); + if(p->cls->superclass) + printf(" extends %s\n", p->cls->superclass->name); + int t; + for(t=0;p->cls->interfaces[t];t++) + printf(" interface %s\n", p->cls->interfaces[t]->name); + DICT_ITERATE_KEY(&p->usedclasses, classinfo_t*, c) { + printf(" uses %s\n", c->name); + } + DICT_ITERATE_KEY(&p->parents, parsedclass_t*, pp) { + printf(" depends on (deep) %s\n", pp->cls->name); + } + DICT_ITERATE_KEY(&p->usedclasses_deep, parsedclass_t*, px) { + printf(" uses (deep) %s\n", px->cls->name); + } + printf("\n"); +#endif + } + list2[count]=0; + free(list); + + dict_destroy(s2p); + return list2; +} + +void parsedclass_add_dependency(parsedclass_t*p, classinfo_t*c) +{ + if(!dict_contains(&p->usedclasses, c)) { + dict_put(&p->usedclasses, c, c); + } +} + +void initcode_add_classlist(abc_script_t*init, parsedclass_list_t*_classes) { code_t*c = 0; c = abc_getlocal_0(c); c = abc_pushscope(c); + + parsedclass_t**classes = initcode_sort_classlist(_classes); - for(;classes;classes=classes->next) { - abc_class_t*abc = classes->parsedclass->abc; - classinfo_t*cls = classes->parsedclass->cls; + int t; + for(t=0;classes[t];t++) { + abc_class_t*abc = classes[t]->abc; + classinfo_t*cls = classes[t]->cls; + + array_append(init->file->classes, "", abc); /* write the construction code for this class to the global init function */ MULTINAME(classname2,cls); - int slotindex = abc_initscript_addClassTrait(init, &classname2, abc); + trait_t*trait = abc_initscript_addClassTrait(init, &classname2, abc); c = abc_getglobalscope(c); classinfo_t*s = cls->superclass; @@ -62,11 +260,12 @@ void initcode_add_classlist(abc_script_t*init, parsedclass_list_t*classes) while(count--) { c = abc_popscope(c); } - c = abc_setslot(c, slotindex); + c = abc_setslot(c, trait->slot_id); multiname_destroy(extends2); } c = abc_returnvoid(c); + free(classes); + init->method->body->code = c; } -