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
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/
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
15 * The Original Code is [Open Source Virtual Machine.].
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.
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.
37 * ***** END LICENSE BLOCK ***** */
39 use default namespace Abc,
45 /* ABCFile container & helper class.
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.
53 * Performance ought to be good; nothing is serialized more than
54 * once and no data are copied except during serialization.
59 const major_version = 46;
60 const minor_version = 16;
68 var constants : ABCConstantPool;
70 function getBytes(): * /* same type as ABCByteStream.getBytes() */ {
71 function emitArray(a, len) {
73 bytes.uint30(a.length);
74 for ( let i=0, limit=a.length ; i < limit ; i++ )
75 a[i].serialize(bytes);
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();
98 function addConstants(cpool: ABCConstantPool): void {
102 function addMethod(m: ABCMethodInfo)/*: uint*/ {
103 return methods.push(m)-1;
106 function addMetadata(m: ABCMetadataInfo)/*: uint*/ {
107 return metadatas.push(m)-1;
110 function addClassAndInstance(cls, inst)/*: uint*/ {
111 let x = addClass(cls);
112 let y = addInstance(inst);
113 Util::assert( x == y );
117 function addInstance(i: ABCInstanceInfo)/*: uint*/ {
118 return instances.push(i)-1;
121 function addClass(c: ABCClassInfo)/*: uint*/ {
122 return classes.push(c)-1;
125 function addScript(s: ABCScriptInfo)/*: uint*/ {
126 return scripts.push(s)-1;
129 function addMethodBody(b: ABCMethodBodyInfo)/*: uint*/ {
130 return bodies.push(b)-1;
135 class ABCConstantPool
137 function ABCConstantPool() {
138 function eq_numbers(n1, n2)
141 function eq_strings(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];
163 function eq_namespacesets(nss1, nss2) {
164 if (nss1.length != nss2.length)
166 for (let i=0, limit=nss1.length ; i < limit ; i++)
167 if (nss1[i] != nss2[i])
172 function hash_name(n: Token::Tok)
175 function eq_names(n1: Token::Tok, n2: Token::Tok)
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);
192 function int32(n:int):uint {
193 let probe = int_map.read(n);
196 int_map.write(n, probe);
202 function uint32(n:uint):uint {
203 let probe = uint_map.read(n);
205 probe = uint_count++;
206 uint_map.write(n, probe);
207 uint_bytes.uint32(n);
212 function float64(n: Number):uint {
213 let probe = double_map.read(n);
215 probe = double_count++;
216 double_map.write(n, probe);
217 double_bytes.float64(n);
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);
227 probe = utf8_count++;
228 utf8_map.write(s, probe);
229 utf8_bytes.uint30(utf8length(s.text));
230 utf8_bytes.utf8(s.text);
235 function stringUtf8(s) {
237 throw new Error("Not a string: <" + s + ">");
238 return symbolUtf8(Token::intern(s));
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,
246 function utf8length(s) {
250 for ( i=0 ; i < limit && s.charCodeAt(i) < 128 ; i++ )
255 let bs = new ABCByteStream;
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);
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);
275 function namespaceset(namespaces:Array) {
276 let probe = namespaceset_map.read(namespaces);
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]);
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.)
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);
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
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 );
321 multiname_bytes.uint8(kind);
322 multiname_bytes.uint30(ns);
323 multiname_bytes.uint30(name);
329 function RTQName(name/*: uint*/, is_attr: Boolean) {
330 let kind = is_attr ? CONSTANT_RTQNameA : CONSTANT_RTQName;
331 let idx = multinameLookup( kind, name, 0 );
333 multiname_bytes.uint8(kind);
334 multiname_bytes.uint30(name);
340 function RTQNameL(is_attr: Boolean) {
341 let kind = is_attr ? CONSTANT_RTQNameLA : CONSTANT_RTQNameL;
342 let idx = multinameLookup( kind, 0, 0 );
344 multiname_bytes.uint8(kind);
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 );
354 multiname_bytes.uint8(kind);
355 multiname_bytes.uint30(name);
356 multiname_bytes.uint30(nsset);
362 function MultinameL(nsset/*: uint*/, is_attr: Boolean) {
363 let kind = is_attr ? CONSTANT_MultinameLA : CONSTANT_MultinameL;
364 let idx = multinameLookup(kind, 0, nsset);
366 multiname_bytes.uint8(kind);
367 multiname_bytes.uint30(nsset);
373 function hasRTNS(index) {
374 let kind = multiname_pool[index].kind;
377 case CONSTANT_RTQName:
378 case CONSTANT_RTQNameA:
379 case CONSTANT_RTQNameL:
380 case CONSTANT_RTQNameLA:
388 function hasRTName(index) {
389 let kind = multiname_pool[index].kind;
391 switch (multiname_pool[index].kind) {
392 case CONSTANT_RTQNameL:
393 case CONSTANT_RTQNameLA:
394 case CONSTANT_MultinameL:
395 case CONSTANT_MultinameLA:
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);
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);
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;
461 var namespaceset_map;
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.
473 function ABCMethodInfo(name/*:uint*/, param_types:Array, return_type/*:uint*/, flags/*:uint*/,
474 options:Array, param_names:Array) {
476 if (flags & METHOD_Needrest) {
477 this.param_types = copyArray(param_types);
478 this.param_types.pop();
481 this.param_types = param_types;
482 this.return_type = return_type;
484 this.options = options;
485 this.param_names = param_names;
488 function setFlags(flags) {
492 function serialize(bs) {
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]);
499 if (options != null) {
500 flags = flags | METHOD_HasOptional;
502 if (param_names != null) {
503 flags = flags | METHOD_HasParamNames;
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);
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]);
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 );
532 function serialize(bs) {
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);
541 // abc-parse.es grubs around here.
542 /*private*/ var name, items;
545 class ABCInstanceInfo
547 function ABCInstanceInfo(name, super_name, flags, protectedNS, interfaces) {
549 this.super_name = super_name;
551 this.protectedNS = protectedNS;
552 this.interfaces = interfaces;
556 function setIInit(x) {
560 function addTrait(t) {
561 return traits.push(t)-1;
564 function serialize(bs) {
567 Util::assert( iinit != undefined || (flags & CONSTANT_ClassInterface) != 0);
570 bs.uint30(super_name);
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]);
580 bs.uint30(traits.length);
581 for ( i=0, limit=traits.length ; i < limit ; i++ )
582 traits[i].serialize(bs);
585 // abc-parse.es grubs around here.
586 /*private*/ var name, super_name, flags, protectedNS, interfaces, iinit, traits;
591 /* FIXME #101: super not implemented; subclasses must do implementation themselves;
592 the constructor must not be defined here (for the sake of AS3). */
594 function ABCTrait(name, kind) {
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);
608 this.kind = (attrs << 4) | (is_const ? TRAIT_Const : TRAIT_Slot);
611 this.slot_id = slot_id;
612 this.type_name = type_name;
613 this.vindex = vindex;
617 function inner_serialize(bs) {
619 bs.uint30(type_name);
625 // abc-parse.es grubs around here.
626 /*private*/ var slot_id, type_name, vindex, vkind;
630 function addMetadata(n) {
631 return metadata.push(n)-1;
634 function serialize(bs) {
635 if (metadata.length > 0)
636 kind = kind | ATTR_Metadata;
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]);
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);
657 this.kind = (attrs << 4) | tag;
664 // esc doesn't support override yet
665 function inner_serialize(bs) {
670 // abc-parse.es grubs around here.
671 /*private*/ var id, val;
675 function addMetadata(n) {
676 return metadata.push(n)-1;
679 function serialize(bs) {
680 if (metadata.length > 0)
681 kind = kind | ATTR_Metadata;
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]);
692 var name, kind, metadata;
699 function setCInit(cinit) {
703 function addTrait(t) {
704 return traits.push(t)-1;
707 function serialize(bs) {
708 Util::assert( cinit != undefined );
710 bs.uint30(traits.length);
711 for ( let i=0, limit=traits.length ; i < limit ; i++ )
712 traits[i].serialize(bs);
715 // abc-parse.es grubs around here.
716 /*private*/ var cinit, traits = [];
721 function ABCScriptInfo(init) {
725 function setInit(init) {
729 function addTrait(t) {
730 return traits.push(t)-1;
733 function serialize(bs) {
734 Util::assert( init != undefined );
736 bs.uint30(traits.length);
737 for ( let i=0, limit=traits.length ; i < limit ; i++ )
738 traits[i].serialize(bs);
741 // abc-parse.es grubs around here.
742 /*private*/ var init, traits = [];
745 class ABCMethodBodyInfo
747 function ABCMethodBodyInfo(method) {
748 this.method = method;
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;
760 function addTrait(t) {
761 return traits.push(t)-1;
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 );
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);
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);
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;
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;
799 function serialize(bs) {
802 bs.uint30(target_pc);
807 // abc-parse.es grubs around here.
808 /*private*/ var first_pc, last_pc, target_pc, exc_type, var_name;