Merge remote-tracking branch 'redux/master' into sh4-pool
[tamarin-stm.git] / esc / src / abc.es
blobce3768486d9f25c475e7ae6b96a4a8fb8a868bdc
1 /* -*- mode: java; tab-width: 4; insert-tabs-mode: nil; indent-tabs-mode: nil -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  * http://www.mozilla.org/MPL/
9  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the
13  * License.
14  *
15  * The Original Code is [Open Source Virtual Machine.].
16  *
17  * The Initial Developer of the Original Code is
18  * Adobe System Incorporated.
19  * Portions created by the Initial Developer are Copyright (C) 2004-2006
20  * the Initial Developer. All Rights Reserved.
21  *
22  * Contributor(s):
23  *   Adobe AS3 Team
24  *
25  * Alternatively, the contents of this file may be used under the terms of
26  * either the GNU General Public License Version 2 or later (the "GPL"), or
27  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28  * in which case the provisions of the GPL or the LGPL are applicable instead
29  * of those above. If you wish to allow use of your version of this file only
30  * under the terms of either the GPL or the LGPL, and not to allow others to
31  * use your version of this file under the terms of the MPL, indicate your
32  * decision by deleting the provisions above and replace them with the notice
33  * and other provisions required by the GPL or the LGPL. If you do not delete
34  * the provisions above, a recipient may use your version of this file under
35  * the terms of any one of the MPL, the GPL or the LGPL.
36  *
37  * ***** END LICENSE BLOCK ***** */
39 use default namespace Abc,
40     namespace Abc;
42 use namespace Asm,
43     namespace Util;
45 /* ABCFile container & helper class.
46  *
47  * Every argument to an addWhatever() method is retained by
48  * reference.  When getBytes() is finally called, each object is
49  * serialized.  The order of serialization is the order they will
50  * have in the ABCFile, and the order among items of the same type
51  * is the order in which they were added.
52  *
53  * Performance ought to be good; nothing is serialized more than
54  * once and no data are copied except during serialization.
55  */
57 class ABCFile
59     const major_version = 46;
60     const minor_version = 16;
62     const methods = [];
63     const metadatas = [];
64     const instances = [];
65     const classes = [];
66     const scripts = [];
67     const bodies = [];
68     var constants : ABCConstantPool;
70     function getBytes(): * /* same type as ABCByteStream.getBytes() */ {
71         function emitArray(a, len) {
72             if (len)
73                 bytes.uint30(a.length);
74             for ( let i=0, limit=a.length ; i < limit ; i++ )
75                 a[i].serialize(bytes);
76         }
78         let bytes = new ABCByteStream;
80         Util::assert(constants);
81         Util::assert(scripts.length != 0);
82         Util::assert(methods.length != 0);
83         Util::assert(bodies.length != 0);
84         Util::assert(classes.length == instances.length);
86         bytes.uint16(minor_version);
87         bytes.uint16(major_version);
88         constants.serialize(bytes);
89         emitArray(methods,true);
90         emitArray(metadatas,true);
91         emitArray(instances,true);
92         emitArray(classes, false);
93         emitArray(scripts,true);
94         emitArray(bodies,true);
95         return bytes.getBytes();
96     }
98     function addConstants(cpool: ABCConstantPool): void {
99         constants = cpool;
100     }
102     function addMethod(m: ABCMethodInfo)/*: uint*/ {
103         return methods.push(m)-1;
104     }
106     function addMetadata(m: ABCMetadataInfo)/*: uint*/ {
107         return metadatas.push(m)-1;
108     }
110     function addClassAndInstance(cls, inst)/*: uint*/ {
111         let x = addClass(cls);
112         let y = addInstance(inst);
113         Util::assert( x == y );
114         return x;
115     }
117     function addInstance(i: ABCInstanceInfo)/*: uint*/ {
118         return instances.push(i)-1;
119     }
121     function addClass(c: ABCClassInfo)/*: uint*/ {
122         return classes.push(c)-1;
123     }
125     function addScript(s: ABCScriptInfo)/*: uint*/ {
126         return scripts.push(s)-1;
127     }
129     function addMethodBody(b: ABCMethodBodyInfo)/*: uint*/ {
130         return bodies.push(b)-1;
131     }
132         
135 class ABCConstantPool
137     function ABCConstantPool() {
138         function eq_numbers(n1, n2)
139             n1 == n2;
141         function eq_strings(s1, s2)
142             s1 == s2; 
144         function hash_namespace(ns)
145             ns.kind ^ ns.name;          // Fairly arbitrary
147         function eq_namespaces(ns1, ns2)
148             ns1.kind == ns2.kind && ns1.name == ns2.name;
150         function hash_multiname(m)
151             m.kind ^ m.name ^ m.ns;     // Fairly arbitrary
153         function eq_multinames(m1, m2)
154             m1.kind == m2.kind && m1.ns == m2.ns && m1.name == m2.name;
156         function hash_namespaceset(nss) {
157             let hash = nss.length;
158             for ( let i=0, limit=nss.length ; i < limit ; i++ )
159                 hash = ((hash << 5) + hash) + nss[i];
160             return hash >>> 0;
161         }
163         function eq_namespacesets(nss1, nss2) {
164             if (nss1.length != nss2.length)
165                 return false;
166             for (let i=0, limit=nss1.length ; i < limit ; i++)
167                 if (nss1[i] != nss2[i])
168                     return false;
169             return true;
170         }
172         function hash_name(n: Token::Tok)
173             n.hash;
175         function eq_names(n1: Token::Tok, n2: Token::Tok)
176             n1 === n2;
178         // All pools and counts start at 1.  Counts are
179         // initialized in the property definitions.
181         multiname_pool.length = 1;
183         int_map = new Hashtable(Util::hash_number, eq_numbers, 0);
184         uint_map = new Hashtable(Util::hash_number, eq_numbers, 0);
185         double_map = new Hashtable(Util::hash_number, eq_numbers, 0);
186         utf8_map = new Hashtable(hash_name, eq_names, 0);
187         namespace_map = new Hashtable(hash_namespace, eq_namespaces, 0);
188         namespaceset_map = new Hashtable(hash_namespaceset, eq_namespacesets, 0);
189         multiname_map = new Hashtable(hash_multiname, eq_multinames, 0);
190     }
192     function int32(n:int):uint {
193         let probe = int_map.read(n);
194         if (probe == 0) {
195             probe = int_count++;
196             int_map.write(n, probe);
197             int_bytes.int32(n);
198         }
199         return probe;
200     }
202     function uint32(n:uint):uint {
203         let probe = uint_map.read(n);
204         if (probe == 0) {
205             probe = uint_count++;
206             uint_map.write(n, probe);
207             uint_bytes.uint32(n);
208         }
209         return probe;
210     }
212     function float64(n: Number):uint {
213         let probe = double_map.read(n);
214         if (probe == 0) {
215             probe = double_count++;
216             double_map.write(n, probe);
217             double_bytes.float64(n);
218         }
219         return probe;
220     }
222     function symbolUtf8(s) {
223         if (!(s is Token::Tok))
224             throw new Error("Not a token: <" + s + ">: " + (s is String) + " " + (s is Number));
225         let probe = utf8_map.read(s);
226         if (probe == 0) {
227             probe = utf8_count++;
228             utf8_map.write(s, probe);
229             utf8_bytes.uint30(utf8length(s.text));
230             utf8_bytes.utf8(s.text);
231         }
232         return probe;
233     }
235     function stringUtf8(s) {
236         if (!(s is String))
237             throw new Error("Not a string: <" + s + ">");
238         return symbolUtf8(Token::intern(s));
239     }
241     // The virtue of this solution is that it caters to the common
242     // case and does not need to know anything about utf8 apart
243     // from the ASCII range.  The uncommon case can be optimized,
244     // if we care.
246     function utf8length(s) {
247         let i;
248         let limit=s.length; 
250         for ( i=0 ; i < limit && s.charCodeAt(i) < 128 ; i++ )
251             ;
252         if (i == limit)
253             return limit;
255         let bs = new ABCByteStream;
256         bs.utf8(s);
257         return bs.length;
258     }
260     var tmp_namespace = {"kind": 0, "name": 0 };  // avoids allocation when we don't need it
262     function namespace(kind/*:uint*/, name/*:uint*/) {
263         tmp_namespace.kind = kind;
264         tmp_namespace.name = name;
265         let probe = namespace_map.read(tmp_namespace);
266         if (probe == 0) {
267             probe = namespace_count++;
268             namespace_map.write({"kind": tmp_namespace.kind, "name": tmp_namespace.name}, probe);
269             namespace_bytes.uint8(tmp_namespace.kind);
270             namespace_bytes.uint30(tmp_namespace.name);
271         }
272         return probe;
273     }
275     function namespaceset(namespaces:Array) {
276         let probe = namespaceset_map.read(namespaces);
277         if (probe == 0) {
278             probe = namespaceset_count++;
279             // Not necessary to copy here at the moment, as the array is a fresh
280             // copy created from flattening a NamespaceSetList.
281             namespaceset_map.write(/*Util::copyArray*/(namespaces), probe);
282             namespaceset_bytes.uint30(namespaces.length);
283             for ( let i=0, limit=namespaces.length ; i < limit ; i++ )
284                 namespaceset_bytes.uint30(namespaces[i]);
285         }
286         return probe;
287     }
289     /* Look up a multiname entry with kind, name, and namespace
290      * set.  Allocate an entry for it if it does not exist.  If an
291      * entry were allocated, then the negative of the entry index
292      * is returned (and the caller should emit data to the
293      * multiname_bytes stream), otherwise the entry index is
294      * returned.  (If this seems a little contorted, it reduces
295      * allocation of closures in the caller.)
296      */
298     // Temporary structure (avoids allocation of structures that already exist).
299     var tmp_multiname = { "kind": 0, "name": 0, "ns": 0 };
301     function multinameLookup(kind, name, ns) {
302         tmp_multiname.kind = kind;
303         tmp_multiname.name = name;
304         tmp_multiname.ns = ns;
305         let probe = multiname_map.read(tmp_multiname);
306         if (probe != 0)
307             return probe;
309         // Allocate
310         probe = multiname_pool.length;
311         let entry = {"kind":tmp_multiname.kind, "name":tmp_multiname.name, "ns":tmp_multiname.ns}
312         multiname_pool.push(entry);           // need "kind" for later, could optimize here --
313         multiname_map.write(entry, probe);    //   but need to save the whole entry anyway
314         return -probe;
315     }
317     function QName(ns/*: uint*/, name/*: uint*/, is_attr: Boolean) {
318         let kind = is_attr ? CONSTANT_QNameA : CONSTANT_QName;
319         let idx = multinameLookup( kind, name, ns );
320         if (idx < 0) {
321             multiname_bytes.uint8(kind);
322             multiname_bytes.uint30(ns);
323             multiname_bytes.uint30(name);
324             idx = -idx;
325         }
326         return idx;
327     }
329     function RTQName(name/*: uint*/, is_attr: Boolean) {
330         let kind = is_attr ? CONSTANT_RTQNameA : CONSTANT_RTQName;
331         let idx = multinameLookup( kind, name, 0 );
332         if (idx < 0) {
333             multiname_bytes.uint8(kind);
334             multiname_bytes.uint30(name); 
335             idx = -idx;
336         }
337         return idx;
338     }
340     function RTQNameL(is_attr: Boolean) {
341         let kind = is_attr ? CONSTANT_RTQNameLA : CONSTANT_RTQNameL;
342         let idx = multinameLookup( kind, 0, 0 );
343         if (idx < 0) {
344             multiname_bytes.uint8(kind);
345             idx = -idx;
346         }
347         return idx;
348     }
350     function Multiname(nsset/*: uint*/, name/*: uint*/, is_attr: Boolean) {
351         let kind = is_attr ? CONSTANT_MultinameA : CONSTANT_Multiname;
352         let idx = multinameLookup(kind, name, nsset );
353         if (idx < 0) {
354             multiname_bytes.uint8(kind);
355             multiname_bytes.uint30(name);
356             multiname_bytes.uint30(nsset); 
357             idx = -idx;
358         }
359         return idx;
360     }
362     function MultinameL(nsset/*: uint*/, is_attr: Boolean) {
363         let kind = is_attr ? CONSTANT_MultinameLA : CONSTANT_MultinameL;
364         let idx = multinameLookup(kind, 0, nsset);
365         if (idx < 0) {
366             multiname_bytes.uint8(kind);
367             multiname_bytes.uint30(nsset);
368             idx = -idx;
369         }
370         return idx;
371     }
373     function hasRTNS(index) {
374         let kind = multiname_pool[index].kind;
375         let result;
376         switch (kind) {
377         case CONSTANT_RTQName:
378         case CONSTANT_RTQNameA:
379         case CONSTANT_RTQNameL:
380         case CONSTANT_RTQNameLA:
381             result = true;
382         default:
383             result = false;
384         }
385         return result;
386     }
388     function hasRTName(index) {
389         let kind = multiname_pool[index].kind;
390         let result;
391         switch (multiname_pool[index].kind) {
392         case CONSTANT_RTQNameL:
393         case CONSTANT_RTQNameLA:
394         case CONSTANT_MultinameL:
395         case CONSTANT_MultinameLA:
396             result = true;
397         default:
398             result = false;
399         }
400         return result;
401     }
403     function printPoolStats() {
404         print("  Ints: n=" + int_count + ", bytes=" + int_bytes.length);
405         print("  Uints: n=" + uint_count + ", bytes=" + uint_bytes.length);
406         print("  Doubles: n=" + double_count + ", bytes=" + double_bytes.length);
407         print("  Strings: n=" + utf8_count + ", bytes=" + utf8_bytes.length);
408         print("  Namespaces: n=" + namespace_count + ", bytes=" + namespace_bytes.length);
409         print("  Namespace sets: n=" + namespaceset_count + ", bytes=" + namespaceset_bytes.length);
410         print("  Multinames: n=" + multiname_pool.length + ", bytes=" + multiname_bytes.length);
411     }
413     function serialize(bs) {
414         bs.uint30(int_count);
415         bs.byteStream(int_bytes);
417         bs.uint30(uint_count);
418         bs.byteStream(uint_bytes);
420         bs.uint30(double_count);
421         bs.byteStream(double_bytes);
423         bs.uint30(utf8_count);
424         bs.byteStream(utf8_bytes);
426         bs.uint30(namespace_count);
427         bs.byteStream(namespace_bytes);
429         bs.uint30(namespaceset_count);
430         bs.byteStream(namespaceset_bytes);
432         bs.uint30(multiname_pool.length);
433         bs.byteStream(multiname_bytes);
435         //printPoolStats();
437         return bs;
438     }
440     // abc-parse.es grubs around here.
442     /*private*/ var   int_count = 1;
443     /*private*/ var   uint_count = 1;
444     /*private*/ var   double_count = 1;
445     /*private*/ var   utf8_count = 1;
446     /*private*/ var   namespace_count = 1;
447     /*private*/ var   namespaceset_count = 1;
448     /*private*/ const multiname_pool = new Array; // its length is the count
450     /*private*/ const int_bytes = new ABCByteStream;
451     /*private*/ const uint_bytes = new ABCByteStream;
452     /*private*/ const double_bytes = new ABCByteStream;
453     /*private*/ const utf8_bytes = new ABCByteStream;
454     /*private*/ const namespace_bytes = new ABCByteStream;
455     /*private*/ const namespaceset_bytes = new ABCByteStream;
456     /*private*/ const multiname_bytes = new ABCByteStream;
458     var utf8_map;
459     var multiname_map;
460     var namespace_map;
461     var namespaceset_map;
464 class ABCMethodInfo
466     /* \param name         string index
467      * \param param_types  array of multiname indices.  May not be null.
468      * \param return_type  multiname index.
469      * \param flags        bitwise or of NEED_ARGUMENTS, NEED_ACTIVATION, HAS_REST, SET_DXNS
470      * \param options      [{val:uint, kind:uint}], if present.
471      * \param param_names  array of param_info structures, if present.
472      */
473     function ABCMethodInfo(name/*:uint*/, param_types:Array, return_type/*:uint*/, flags/*:uint*/,
474                            options:Array, param_names:Array) {
475         this.name = name;
476         if (flags & METHOD_Needrest) {
477             this.param_types = copyArray(param_types);
478             this.param_types.pop();
479         }
480         else
481             this.param_types = param_types;
482         this.return_type = return_type;
483         this.flags = flags;
484         this.options = options;
485         this.param_names = param_names;
486     }
488     function setFlags(flags) {
489         this.flags = flags;
490     }
492     function serialize(bs) {
493         let i, limit;
494         bs.uint30(param_types.length);
495         bs.uint30(return_type);
496         for ( i=0, limit=param_types.length ; i < limit ; i++ )
497             bs.uint30(param_types[i]);
498         bs.uint30(name);
499         if (options != null) {
500             flags = flags | METHOD_HasOptional;
501         }
502         if (param_names != null) {
503             flags = flags | METHOD_HasParamNames;
504         }
505         bs.uint8(flags);
506         if (options != null) {
507             bs.uint30(options.length);
508             for ( i=0, limit=options.length ; i < limit ; i++ ) {
509                 bs.uint30(options[i].val);
510                 bs.uint8(options[i].kind);
511             }
512         }
513         if (param_names != null) {
514             Util::assert( param_names.length == param_types.length );
515             for ( i=0, limit=param_names.length ; i < limit ; i++ )
516                 bs.uint30(param_names[i]);
517         }
518     }
520     // abc-parse.es grubs around here.
521     /*private*/ var name, param_types, return_type, flags, options, param_names;
524 class ABCMetadataInfo
526     function ABCMetadataInfo( name/*: uint*/, items: Array ) {
527         Util::assert( name != 0 );
528         this.name = name;
529         this.items = items;
530     }
532     function serialize(bs) {
533         bs.uint30(name);
534         bs.uint30(items.length);
535         for ( let i=0, limit=items.length ; i < limit ; i++ ) {
536             bs.uint30(items[i].key);
537             bs.uint30(items[i].value);
538         }
539     }
541     // abc-parse.es grubs around here.
542     /*private*/ var name, items;
545 class ABCInstanceInfo
547     function ABCInstanceInfo(name, super_name, flags, protectedNS, interfaces) {
548         this.name = name;
549         this.super_name = super_name;
550         this.flags = flags;
551         this.protectedNS = protectedNS;
552         this.interfaces = interfaces;
553         this.traits = [];
554     }
556     function setIInit(x) {
557         iinit = x;
558     }
560     function addTrait(t) {
561         return traits.push(t)-1;
562     }
564     function serialize(bs) {
565         let i, limit;
567         Util::assert( iinit != undefined || (flags & CONSTANT_ClassInterface) != 0);
569         bs.uint30(name);
570         bs.uint30(super_name);
571         bs.uint8(flags);
572         if (flags & CONSTANT_ClassProtectedNs)
573             bs.uint30(protectedNS);
574         bs.uint30(interfaces.length);
575         for ( i=0, limit=interfaces.length ; i < limit ; i++ ) {
576             Util::assert( interfaces[i] != 0 );
577             bs.uint30(interfaces[i]);
578         }
579         bs.uint30(iinit);
580         bs.uint30(traits.length);
581         for ( i=0, limit=traits.length ; i < limit ; i++ )
582             traits[i].serialize(bs);
583     }
585     // abc-parse.es grubs around here.
586     /*private*/ var name, super_name, flags, protectedNS, interfaces, iinit, traits;
589 class ABCTrait
591     /* FIXME #101: super not implemented; subclasses must do implementation themselves;
592        the constructor must not be defined here (for the sake of AS3).  */
593     /*
594       function ABCTrait(name, kind) {
595       this.name = name;
596       this.kind = kind;
597       }
598     */
602 class ABCSlotTrait /// extends ABCTrait
604     function ABCSlotTrait(name, attrs, is_const, slot_id, type_name, vindex, vkind) {
605         /*FIXME #101: super not implemented*/
606         //super(name, (attrs << 4) | TRAIT_Slot);
607         this.name = name;
608         this.kind = (attrs << 4) | (is_const ? TRAIT_Const : TRAIT_Slot);
609         this.metadata = [];
610         //End of fixme
611         this.slot_id = slot_id;
612         this.type_name = type_name;
613         this.vindex = vindex;
614         this.vkind = vkind;
615     }
617     function inner_serialize(bs) {
618         bs.uint30(slot_id);
619         bs.uint30(type_name);
620         bs.uint30(vindex);
621         if (vindex != 0)
622             bs.uint8(vkind);
623     }
625     // abc-parse.es grubs around here.
626     /*private*/ var slot_id, type_name, vindex, vkind;
628     // from ABCTrait
630     function addMetadata(n) {
631         return metadata.push(n)-1;
632     }
634     function serialize(bs) {
635         if (metadata.length > 0)
636             kind = kind | ATTR_Metadata;
637         bs.uint30(name);
638         bs.uint30(kind);
639         inner_serialize(bs);
640         if (metadata.length > 0) {
641             bs.uint30(metadata.length);
642             for ( let i=0, limits=metadata.length ; i < limit ; i++ )
643                 bs.uint30(metadata[i]);
644         }
645     }
647     var name, kind, metadata;
650 class ABCOtherTrait /// extends ABCTrait  // removed for esc
652     /* TAG is one of the TRAIT_* values, except TRAIT_Slot */
653     function ABCOtherTrait(name, attrs, tag, id, val) {
654         /*FIXME #101: super not implemented*/
655         //super(name, (attrs << 4) | tag);
656         this.name = name;
657         this.kind = (attrs << 4) | tag;
658         this.metadata = [];
659         //End of fixme
660         this.id = id;
661         this.val = val;
662     }
664     // esc doesn't support override yet
665     function inner_serialize(bs) {
666         bs.uint30(id);
667         bs.uint30(val);
668     }
670     // abc-parse.es grubs around here.
671     /*private*/ var id, val;
673     // from ABCTrait
675     function addMetadata(n) {
676         return metadata.push(n)-1;
677     }
679     function serialize(bs) {
680         if (metadata.length > 0)
681             kind = kind | ATTR_Metadata;
682         bs.uint30(name);
683         bs.uint30(kind);
684         inner_serialize(bs);
685         if (metadata.length > 0) {
686             bs.uint30(metadata.length);
687             for ( let i=0, limit=metadata.length ; i < limit ; i++ )
688                 bs.uint30(metadata[i]);
689         }
690     }
692     var name, kind, metadata;
697 class ABCClassInfo
699     function setCInit(cinit) {
700         this.cinit = cinit;
701     }
703     function addTrait(t) {
704         return traits.push(t)-1;
705     }
707     function serialize(bs) {
708         Util::assert( cinit != undefined );
709         bs.uint30(cinit);
710         bs.uint30(traits.length);
711         for ( let i=0, limit=traits.length ; i < limit ; i++ )
712             traits[i].serialize(bs);
713     }
715     // abc-parse.es grubs around here.
716     /*private*/ var cinit, traits = [];
719 class ABCScriptInfo
721     function ABCScriptInfo(init) {
722         this.init = init;
723     }
725     function setInit(init) {
726         this.init = init;
727     }
729     function addTrait(t) {
730         return traits.push(t)-1;
731     }
733     function serialize(bs) {
734         Util::assert( init != undefined );
735         bs.uint30(init);
736         bs.uint30(traits.length);
737         for ( let i=0, limit=traits.length ; i < limit ; i++ )
738             traits[i].serialize(bs);
739     }
741     // abc-parse.es grubs around here.
742     /*private*/ var init, traits = [];
745 class ABCMethodBodyInfo
747     function ABCMethodBodyInfo(method) {
748         this.method = method;
749     }
750     function setMaxStack(ms) { max_stack = ms }
751     function setLocalCount(lc) { local_count = lc }
752     function setInitScopeDepth(sd) { init_scope_depth = sd }
753     function setMaxScopeDepth(msd) { max_scope_depth = msd }
754     function setCode(insns) { code = insns }
756     function addException(exn) {
757         return exceptions.push(exn)-1;
758     }
760     function addTrait(t) {
761         return traits.push(t)-1;
762     }
764     function serialize(bs) {
765         Util::assert( max_stack != undefined && local_count != undefined );
766         Util::assert( init_scope_depth != undefined && max_scope_depth != undefined );
767         Util::assert( code != undefined );
769         bs.uint30(method);
770         bs.uint30(max_stack);
771         bs.uint30(local_count);
772         bs.uint30(init_scope_depth);
773         bs.uint30(max_scope_depth);
774         bs.uint30(code.length);
775         code.serialize(bs);
776         bs.uint30(exceptions.length);
777         for ( let i=0, limit=exceptions.length ; i < limit ; i++ )
778             exceptions[i].serialize(bs);
779         bs.uint30(traits.length);
780         for ( let i=0, limit=traits.length ; i < limit ; i++ )
781             traits[i].serialize(bs);
782     }
784     // abc-parse.es grubs around here.
785     /*private*/ var init_scope_depth = 0, exceptions = [], traits = [];
786     /*private*/ var method, max_stack, local_count, max_scope_depth, code;
789 class ABCException
791     function ABCException(first_pc, last_pc, target_pc, exc_type, var_name) {
792         this.first_pc = first_pc;
793         this.last_pc = last_pc;
794         this.target_pc = target_pc;
795         this.exc_type = exc_type;
796         this.var_name = var_name;
797     }
799     function serialize(bs) {
800         bs.uint30(first_pc);
801         bs.uint30(last_pc);
802         bs.uint30(target_pc);
803         bs.uint30(exc_type);
804         bs.uint30(var_name);
805     }
807     // abc-parse.es grubs around here.
808     /*private*/ var first_pc, last_pc, target_pc, exc_type, var_name;