2 # -*- Mode: Python; indent-tabs-mode: nil -*-
3 # vi: set ts=4 sw=4 expandtab:
4 # ***** BEGIN LICENSE BLOCK *****
5 # Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 # The contents of this file are subject to the Mozilla Public License Version
8 # 1.1 (the "License"); you may not use this file except in compliance with
9 # the License. You may obtain a copy of the License at
10 # http://www.mozilla.org/MPL/
12 # Software distributed under the License is distributed on an "AS IS" basis,
13 # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 # for the specific language governing rights and limitations under the
17 # The Original Code is [Open Source Virtual Machine].
19 # The Initial Developer of the Original Code is
20 # Adobe System Incorporated.
21 # Portions created by the Initial Developer are Copyright (C) 2007
22 # the Initial Developer. All Rights Reserved.
27 # Alternatively, the contents of this file may be used under the terms of
28 # either the GNU General Public License Version 2 or later (the "GPL"), or
29 # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 # in which case the provisions of the GPL or the LGPL are applicable instead
31 # of those above. If you wish to allow use of your version of this file only
32 # under the terms of either the GPL or the LGPL, and not to allow others to
33 # use your version of this file under the terms of the MPL, indicate your
34 # decision by deleting the provisions above and replace them with the notice
35 # and other provisions required by the GPL or the LGPL. If you do not delete
36 # the provisions above, a recipient may use your version of this file under
37 # the terms of any one of the MPL, the GPL or the LGPL.
39 # ***** END LICENSE BLOCK *****
41 # Documentation for native annotations.
43 # Classes can be annotated with 'native' metainformation:
45 # [native(cls="...", ...)]
46 # public class Fnord extends FnordBase { ... }
51 # public class Fnord extends FnordBase { ... }
53 # The latter form is equivalent to the former with a single cls attribute (?).
55 # The named attributes are:
57 # cls the C++ name for the class object's class (required)
58 # instance the C++ name for the instance object's class (required)
59 # gc the GC method for both class and instance objects
60 # classgc the GC method for the class object
61 # instancegc the GC method for the instance object
63 # construct indicates that the class has a nonstandard construction pipeline:
65 # "none": the class cannot be instantiated, nor can subclasses; we will generate a stub
66 # that throws kCantInstantiateError. (Typically used for classes that provide only
67 # static members and/or static methods.)
69 # "check": the class is expected to provide a function of the form
71 # static void FASTCALL preCreateInstanceCheck(ClassClosure* cls)
73 # which will be called prior to creation of an instance; this function is
74 # allowed to throw an exception to prevent object creation. (Throwing
75 # an exception in the C++ ctor is discouraged, as our current longjmp implementation
76 # of exception handling can result in a half-constructed object, which could cause
77 # issues at object destruction time.)
79 # "restricted": subclasses must be defined in the same ABC chunk as the baseclass (otherwise they will
80 # throw kCantInstantiateError). This is an odd beast, used by Flash for classes
81 # which can't be subclassed by user code (only by builtin code.)
83 # "restricted-check": Like restricted, but with a preCreateInstanceCheck function required as well.
85 # "abstract": the class cannot be instantiated, but its subclasses can (ie, an Abstract Base Class);
86 # we will generate a stub that throws kCantInstantiateError when appropriate.
88 # "abstract-restricted": is the union of of abstract+restricted: the class can't be instantiated,
89 # and subclasses can only from from the same ABC chunk.
91 # * THE FOLLOWING VALUES FOR construct ARE ONLY LEGAL FOR USE IN THE BASE VM BUILTINS *
93 # "override": the Class must provide an override of the ScriptObject::construct() method.
94 # (We will autogenerate a createInstanceProc stub that asserts if called.)
96 # "instance": the Class *and* Instance must provide an override of the ScriptObject::construct() method.
97 # (We will autogenerate a createInstanceProc stub that asserts if called.)
99 # instancebase if the instance inherits from a C++ class that can't be inferred from the AS3 inheritance,
100 # it must be specified here. this is not supported for new code; it's provided for temporary support
103 # The allowable values for "gc", "classgc", and "instancegc" are "exact"
104 # and "conservative"; the default is "conservative". If the value is "exact"
105 # then tracers are autogenerated based on annotations on the C++ class and
106 # on the pointer fields in the C++ class.
108 # For more information about GC see the documentation in utils/exactgc.as.
110 import optparse
, struct
, os
, sys
, StringIO
111 from optparse
import OptionParser
114 from math
import floor
115 from sys
import stderr
119 parser
= OptionParser(usage
="usage: %prog [importfile [, importfile]...] file...")
120 parser
.add_option("-v", "--thunkvprof", action
="store_true", default
=False)
121 parser
.add_option("-e", "--externmethodandclassetables", action
="store_true", default
=False, help="generate extern decls for method and class tables")
122 parser
.add_option("--native-id-namespace", dest
="nativeIDNS", default
="avmplus::NativeID", help="Specifies the C++ namespace in which all generated should be in.")
123 parser
.add_option("--root-implementation-namespace", dest
="rootImplNS", default
="avmplus", help="Specifies the C++ namespace in under which all implementation classes can be found.")
124 opts
, args
= parser
.parse_args()
130 NEED_ARGUMENTS
= 0x01
131 NEED_ACTIVATION
= 0x02
136 HAS_ParamNames
= 0x80
141 CONSTANT_PrivateNs
= 0x05
142 CONSTANT_Double
= 0x06
143 CONSTANT_Qname
= 0x07
144 CONSTANT_Namespace
= 0x08
145 CONSTANT_Multiname
= 0x09
146 CONSTANT_False
= 0x0A
149 CONSTANT_QnameA
= 0x0D
150 CONSTANT_MultinameA
= 0x0E
151 CONSTANT_RTQname
= 0x0F
152 CONSTANT_RTQnameA
= 0x10
153 CONSTANT_RTQnameL
= 0x11
154 CONSTANT_RTQnameLA
= 0x12
155 CONSTANT_NameL
= 0x13
156 CONSTANT_NameLA
= 0x14
157 CONSTANT_NamespaceSet
= 0x15
158 CONSTANT_PackageNs
= 0x16
159 CONSTANT_PackageInternalNs
= 0x17
160 CONSTANT_ProtectedNs
= 0x18
161 CONSTANT_ExplicitNamespace
= 0x19
162 CONSTANT_StaticProtectedNs
= 0x1A
163 CONSTANT_MultinameL
= 0x1B
164 CONSTANT_MultinameLA
= 0x1C
165 CONSTANT_TypeName
= 0x1D
189 MIN_API_MARK
= 0xE000
190 MAX_API_MARK
= 0xF8FF
192 MPL_HEADER
= "/* ***** BEGIN LICENSE BLOCK *****\n" \
193 " * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n" \
195 " * The contents of this file are subject to the Mozilla Public License Version\n" \
196 " * 1.1 (the \"License\"); you may not use this file except in compliance with\n" \
197 " * the License. You may obtain a copy of the License at\n" \
198 " * http://www.mozilla.org/MPL/\n" \
200 " * Software distributed under the License is distributed on an \"AS IS\" basis,\n" \
201 " * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n" \
202 " * for the specific language governing rights and limitations under the\n" \
205 " * The Original Code is [Open Source Virtual Machine].\n" \
207 " * The Initial Developer of the Original Code is\n" \
208 " * Adobe System Incorporated.\n" \
209 " * Portions created by the Initial Developer are Copyright (C) 2008\n" \
210 " * the Initial Developer. All Rights Reserved.\n" \
212 " * Contributor(s):\n" \
213 " * Adobe AS3 Team\n" \
215 " * Alternatively, the contents of this file may be used under the terms of\n" \
216 " * either the GNU General Public License Version 2 or later (the \"GPL\"), or\n" \
217 " * the GNU Lesser General Public License Version 2.1 or later (the \"LGPL\"),\n" \
218 " * in which case the provisions of the GPL or the LGPL are applicable instead\n" \
219 " * of those above. If you wish to allow use of your version of this file only\n" \
220 " * under the terms of either the GPL or the LGPL, and not to allow others to\n" \
221 " * use your version of this file under the terms of the MPL, indicate your\n" \
222 " * decision by deleting the provisions above and replace them with the notice\n" \
223 " * and other provisions required by the GPL or the LGPL. If you do not delete\n" \
224 " * the provisions above, a recipient may use your version of this file under\n" \
225 " * the terms of any one of the MPL, the GPL or the LGPL.\n" \
227 " * ***** END LICENSE BLOCK ***** */"
229 # Python 2.5 and earlier didn't reliably handle float("nan") and friends uniformly
230 # across all platforms. This is a workaround that appears to be more reliable.
231 # if/when we require Python 2.6 or later we can use a less hack-prone approach
234 kNaN
= kPosInf
/ kPosInf
237 strValLower
= str(val
).lower()
238 return strValLower
== "nan"
241 # [-]1.#INF on Windows in Python 2.5.2!
242 strValLower
= str(val
).lower()
243 return strValLower
.endswith("inf") and not strValLower
.startswith("-")
246 # [-]1.#INF on Windows in Python 2.5.2!
247 strValLower
= str(val
).lower()
248 return strValLower
.endswith("inf") and strValLower
.startswith("-")
250 class Error(Exception):
252 def __init__(self
, n
):
257 BASE_CLASS_NAME
= "avmplus::ClassClosure"
258 BASE_INSTANCE_NAME
= "avmplus::ScriptObject"
262 CTYPE_ATOM
: "avmplus::Atom",
264 CTYPE_BOOLEAN
: "bool",
265 CTYPE_INT
: "int32_t",
266 CTYPE_UINT
: "uint32_t",
267 CTYPE_DOUBLE
: "double",
268 CTYPE_STRING
: "avmplus::String*",
269 CTYPE_NAMESPACE
: "avmplus::Namespace*",
272 TYPEMAP_RETTYPE_GCREF
= {
273 CTYPE_OBJECT
: lambda type: "GCRef<%s>" % type,
274 CTYPE_ATOM
: lambda type: "avmplus::Atom",
275 CTYPE_VOID
: lambda type: "void",
276 CTYPE_BOOLEAN
: lambda type: "bool",
277 CTYPE_INT
: lambda type: "int32_t",
278 CTYPE_UINT
: lambda type: "uint32_t",
279 CTYPE_DOUBLE
: lambda type: "double",
280 CTYPE_STRING
: lambda type: "GCRef<avmplus::String>",
281 CTYPE_NAMESPACE
: lambda type: "GCRef<avmplus::Namespace>",
284 TYPEMAP_THUNKRETTYPE
= {
285 CTYPE_OBJECT
: "avmplus::Atom(%s)",
286 CTYPE_ATOM
: "avmplus::Atom(%s)",
287 CTYPE_VOID
: "avmplus::Atom(%s)",
288 CTYPE_BOOLEAN
: "avmplus::Atom(%s)",
289 CTYPE_INT
: "avmplus::Atom(%s)",
290 CTYPE_UINT
: "avmplus::Atom(%s)",
291 CTYPE_DOUBLE
: "double(%s)",
292 CTYPE_STRING
: "avmplus::Atom(%s)",
293 CTYPE_NAMESPACE
: "avmplus::Atom(%s)",
296 TYPEMAP_MEMBERTYPE
= {
297 CTYPE_OBJECT
: "DRCWB(%s*)",
298 CTYPE_ATOM
: "avmplus::AtomWB",
299 CTYPE_VOID
: "#error",
300 CTYPE_BOOLEAN
: "bool32",
301 CTYPE_INT
: "int32_t",
302 CTYPE_UINT
: "uint32_t",
303 CTYPE_DOUBLE
: "double",
304 CTYPE_STRING
: "DRCWB(avmplus::String*)",
305 CTYPE_NAMESPACE
: "DRCWB(avmplus::Namespace*)",
310 CTYPE_ATOM
: "avmplus::Atom",
312 CTYPE_BOOLEAN
: "bool32",
313 CTYPE_INT
: "int32_t",
314 CTYPE_UINT
: "uint32_t",
315 CTYPE_DOUBLE
: "double",
316 CTYPE_STRING
: "avmplus::String*",
317 CTYPE_NAMESPACE
: "avmplus::Namespace*",
320 TYPEMAP_ARGTYPE_SUFFIX
= {
321 CTYPE_OBJECT
: "OBJECT",
324 CTYPE_BOOLEAN
: "BOOLEAN",
327 CTYPE_DOUBLE
: "DOUBLE",
328 CTYPE_STRING
: "STRING",
329 CTYPE_NAMESPACE
: "NAMESPACE",
332 TYPEMAP_ARGTYPE_FOR_UNBOX
= {
334 CTYPE_ATOM
: "avmplus::Atom",
335 CTYPE_VOID
: "#error",
336 CTYPE_BOOLEAN
: "bool32",
337 CTYPE_INT
: "int32_t",
338 CTYPE_UINT
: "uint32_t",
339 CTYPE_DOUBLE
: "double",
340 CTYPE_STRING
: "avmplus::String*",
341 CTYPE_NAMESPACE
: "avmplus::Namespace*",
345 # The explicit cast to ScriptObject is necessary because the type in
346 # question may have only been forward-declared, thus calling methods
347 # on it isn't legal; since we know it's a ScriptObject, we can force the issue.
348 # Note that, for this reason, we can't use staticCast, as the compiler
349 # will complain that they are apparently unrelated types.
350 CTYPE_OBJECT
: lambda val
: "%s.reinterpretCast<avmplus::ScriptObject>()->atom()" % val
,
351 CTYPE_ATOM
: lambda val
: "%s" % val
,
352 CTYPE_VOID
: lambda val
: "undefinedAtom",
353 CTYPE_BOOLEAN
: lambda val
: "((%s) ? trueAtom : falseAtom)" % val
,
354 CTYPE_INT
: lambda val
: "core->intToAtom(%s)" % val
,
355 CTYPE_UINT
: lambda val
: "core->uintToAtom(%s)" % val
,
356 CTYPE_DOUBLE
: lambda val
: "core->doubleToAtom(%s)" % val
,
357 CTYPE_STRING
: lambda val
: "%s->atom()" % val
,
358 CTYPE_NAMESPACE
: lambda val
: "%s->atom()" % val
,
361 TYPEMAP_TO_ATOM_NEEDS_CORE
= {
365 CTYPE_BOOLEAN
: False,
370 CTYPE_NAMESPACE
: False,
373 TYPEMAP_FROM_ATOM
= {
374 # We can't use static_cast<> because the subclass might be only forward-declared at this point;
375 # use good old brute-force cast instead.
376 CTYPE_OBJECT
: lambda val
,type: "(%s*)(AvmCore::atomToScriptObject(%s))" % (type,val
),
377 CTYPE_ATOM
: lambda val
,type: "%s" % val
,
378 CTYPE_VOID
: lambda val
,type: "undefinedAtom",
379 CTYPE_BOOLEAN
: lambda val
,type: "((%s) != falseAtom)" % val
,
380 CTYPE_INT
: lambda val
,type: "AvmCore::integer(%s)" % val
,
381 CTYPE_UINT
: lambda val
,type: "AvmCore::toUInt32(%s)" % val
,
382 CTYPE_DOUBLE
: lambda val
,type: "AvmCore::number(%s)" % val
,
383 CTYPE_STRING
: lambda val
,type: "AvmCore::atomToString(%s)" % val
,
384 CTYPE_NAMESPACE
: lambda val
,type: "AvmCore::atomToNamespace(%s)" % val
,
388 CTYPE_OBJECT
: lambda val
,type: "GCRef<%s>(%s)" % (type,val
),
389 CTYPE_ATOM
: lambda val
,type: val
,
390 CTYPE_VOID
: lambda val
,type: val
,
391 CTYPE_BOOLEAN
: lambda val
,type: val
,
392 CTYPE_INT
: lambda val
,type: val
,
393 CTYPE_UINT
: lambda val
,type: val
,
394 CTYPE_DOUBLE
: lambda val
,type: val
,
395 CTYPE_STRING
: lambda val
,type: "GCRef<%s>(%s)" % (type,val
),
396 CTYPE_NAMESPACE
: lambda val
,type: "GCRef<%s>(%s)" % (type,val
),
400 return int(i
) & 0xffffffff
402 def c_argtype_from_enum(ct
):
403 assert ct
!= CTYPE_OBJECT
404 r
= TYPEMAP_ARGTYPE
[ct
]
409 nm
= nm
.replace("+", "_");
410 nm
= nm
.replace("-", "_");
411 nm
= nm
.replace("?", "_");
412 nm
= nm
.replace("!", "_");
413 nm
= nm
.replace("<", "_");
414 nm
= nm
.replace(">", "_");
415 nm
= nm
.replace("=", "_");
416 nm
= nm
.replace("(", "_");
417 nm
= nm
.replace(")", "_");
418 nm
= nm
.replace("\"", "_");
419 nm
= nm
.replace("'", "_");
420 nm
= nm
.replace("*", "_");
421 nm
= nm
.replace(" ", "_");
422 nm
= nm
.replace(".", "_");
423 nm
= nm
.replace("$", "_");
424 nm
= nm
.replace("::", "_");
425 nm
= nm
.replace(":", "_");
426 nm
= nm
.replace("/", "_");
430 GLUECLASSES_WITHOUT_NS
= frozenset((
436 def ns_prefix(ns
, iscls
):
437 if not ns
.isPublic() and not ns
.isInternal():
438 if ns
.isPrivate() and not iscls
:
442 if ns
.srcname
!= None:
443 return to_cname(str(ns
.srcname
)) + "_"
444 p
= to_cname(ns
.uri
);
449 def stripVersion(uri
):
451 uri16
= uri
.decode('utf8')
453 if cc
>= MIN_API_MARK
and cc
<= MAX_API_MARK
:
454 return cc
-MIN_API_MARK
, uri16
[0:len(uri16
)-1].encode('utf8')
461 def __init__(self
, uri
, kind
):
467 return self
.kind
in [CONSTANT_Namespace
, CONSTANT_PackageNs
] and self
.uri
== ""
468 def isInternal(self
):
469 return self
.kind
in [CONSTANT_PackageInternalNs
]
471 return self
.kind
in [CONSTANT_PrivateNs
]
472 def isProtected(self
):
473 return self
.kind
in [CONSTANT_ProtectedNs
, CONSTANT_StaticProtectedNs
]
474 def stripVersion(self
):
475 api
, strippeduri
= stripVersion(self
.uri
)
476 # it's important to return 'self' (and not an identical clone)
477 # if we are unversioned, otherwise native methods with custom namespaces
478 # may be emitted incorrectly
481 newself
= Namespace(strippeduri
, self
.kind
)
482 newself
.srcname
= self
.srcname
488 def __init__(self
, ns
, name
):
492 if str(self
.ns
) == "":
495 return "*::" + self
.name
496 return str(self
.ns
) + "::" + self
.name
501 def __init__(self
, nsset
, name
):
505 nsStrings
= map(lambda ns
: '"' + ns
.decode("utf8") + '"', self
.nsset
)
506 stringForNSSet
= '[' + ', '.join(nsStrings
) + ']'
507 return stringForNSSet
+ '::' + unicode(self
.name
.decode("utf8"))
512 def __init__(self
, name
, types
):
516 # @todo horrible special-casing, improve someday
518 t
= str(self
.types
[0])
532 def __init__(self
, name
):
542 class MethodInfo(MemberInfo
):
548 optionalValues
= None
556 native_id_name
= None
557 native_method_name
= None
561 unbox_this
= -1 # -1 == undetermined, 0 = no, 1 = yes
564 return (self
.flags
& NATIVE
) != 0
567 return (self
.flags
& NEED_REST
) != 0
569 def hasOptional(self
):
570 return (self
.flags
& HAS_OPTIONAL
) != 0
572 def assign_names(self
, traits
, prefix
):
573 self
.receiver
= traits
575 if not self
.isNative():
578 if self
== traits
.init
:
579 raise Error("ctors cannot be native")
581 assert(isinstance(self
.name
, QName
))
582 self
.native_id_name
= prefix
+ ns_prefix(self
.name
.ns
, False) + self
.name
.name
583 self
.native_method_name
= self
.name
.name
585 if self
.kind
== TRAIT_Getter
:
586 self
.native_id_name
+= "_get"
587 self
.native_method_name
= "get_" + self
.native_method_name
588 elif self
.kind
== TRAIT_Setter
:
589 self
.native_id_name
+= "_set"
590 self
.native_method_name
= "set_" + self
.native_method_name
592 if self
.name
.ns
.srcname
!= None:
593 self
.native_method_name
= str(self
.name
.ns
.srcname
) + "_" + self
.native_method_name
595 # if we are an override, prepend the classname to the C method name.
596 # (native method implementations must not be virtual, and some compilers
597 # will be unhappy if a subclass overrides a method with the same name and signature
598 # without it being virtual.) Note that we really only need to do this if the ancestor
599 # implementation is native, rather than pure AS3, but we currently do it regardless.
601 self
.native_method_name
= traits
.name
.name
+ "_" + self
.native_method_name
603 self
.native_method_name
= to_cname(self
.native_method_name
)
605 class SlotInfo(MemberInfo
):
613 class_gc_exact
= None
614 instancebase_name
= None
615 instance_gc_exact
= None
616 gen_method_map
= False
617 method_map_name
= None
618 has_const_setters
= False
621 def __init__(self
, traits
, itraits
):
623 self
.itraits
= itraits
625 def parse_one_nativeinfo(self
, attrs
, is_vm_builtin
):
627 for k
in attrs
.keys():
630 raise Error("native scripts are no longer supported; please use a native class instead and wrap with AS3 code as necessary.")
634 elif (k
== "instance"):
636 elif (k
== "instancebase"):
637 self
.set_instancebase(v
)
640 self
.set_instanceGC(v
)
641 elif (k
== "classgc"):
643 elif (k
== "instancegc"):
644 self
.set_instanceGC(v
)
645 elif (k
== "methods"):
646 self
.gen_method_map
= True
648 self
.method_map_name
= v
649 elif (k
== "constsetters"):
651 self
.has_const_setters
= True
653 raise Error('native metadata specified illegal value, "%s" for constsetters field. Value must be "true" or "false".' % v
)
654 elif (k
== "construct"):
655 self
.set_construct(v
, is_vm_builtin
)
657 raise Error("unknown attribute native(%s)" % k
)
658 if (self
.traits
.cpp_name_comps
== None) and (self
.itraits
.cpp_name_comps
== None):
659 raise Error("native metadata must specify (cls,instance)")
661 def fullyQualifiedCPPClassName(self
, className
):
662 r
= className
.split('::')
663 if (len(opts
.rootImplNS
) > 0) and not className
.startswith('::') and not className
in GLUECLASSES_WITHOUT_NS
:
664 r
.insert(0, opts
.rootImplNS
)
667 def set_class(self
, name
):
668 if self
.traits
.cpp_name_comps
!= None:
669 raise Error("native(cls) may not be specified multiple times for the same class: %s %s" % (self
.traits
.fqcppname(), name
))
670 self
.traits
.cpp_name_comps
= self
.fullyQualifiedCPPClassName(name
)
672 def set_instance(self
, name
):
673 if self
.itraits
.cpp_name_comps
!= None:
674 raise Error("native(instance) may not be specified multiple times for the same class: %s %s" % (self
.itraits
.fqcppname(), name
))
675 if name
== "ScriptObject" or name
== BASE_INSTANCE_NAME
:
676 raise Error("native(instance='ScriptObject') is no longer supported:")
677 self
.itraits
.cpp_name_comps
= self
.fullyQualifiedCPPClassName(name
)
679 def set_instancebase(self
, name
):
680 if self
.instancebase_name
!= None:
681 raise Error("native(instancebase) may not be specified multiple times for the same class: %s %s" % (self
.instancebase_name
, name
))
682 comps
= self
.fullyQualifiedCPPClassName(name
)
683 self
.instancebase_name
= '::'.join(filter(lambda ns
: len(ns
) > 0, comps
))
685 def set_construct(self
, value
, is_vm_builtin
):
686 if self
.construct
!= None:
687 raise Error("native(construct) may not be specified multiple times for the same class")
688 if value
in ["override", "instance"]:
689 if not is_vm_builtin
:
690 raise Error('construct=%s may only be specified for the VM builtins' % value
)
691 self
.construct
= value
692 elif value
in ["none", "abstract", "abstract-restricted", "restricted", "check", "restricted-check"]:
693 self
.construct
= value
695 raise Error('native metadata specified illegal value, "%s" for construct field.' % value
)
697 def set_classGC(self
, gc
):
698 if self
.class_gc_exact
!= None:
699 raise Error("native(classgc) may not be specified multiple times for the same class: %s %s" % (self
.traits
.fqcppname(), gc
))
701 self
.class_gc_exact
= True
702 elif gc
== "conservative":
705 raise Error("native(classgc) can only be specified as 'exact' or 'conservative': %s %s" % (self
.traits
.fqcppname(), gc
))
707 def set_instanceGC(self
, gc
):
708 if self
.instance_gc_exact
!= None:
709 raise Error("native(instancegc) may not be specified multiple times for the same class: %s %s" % (self
.itraits
.fqcppname(), gc
))
711 self
.instance_gc_exact
= True
712 elif gc
== "conservative":
715 raise Error("native(instancegc) can only be specified as 'exact' or 'conservative': %s %s" % (self
.itraits
.fqcppname(), gc
))
718 def parse_native_info(t
, is_vm_builtin
):
721 ni
= NativeInfo(t
, itraits
)
723 if t
.metadata
!= None:
724 for md
in t
.metadata
:
725 if md
.name
== "native":
726 ni
.parse_one_nativeinfo(md
.attrs
, is_vm_builtin
)
728 if itraits
.cpp_name_comps
!= None and itraits
.is_interface
:
729 raise Error("interfaces may not specify native(instance)")
731 if ni
.gen_method_map
and t
.cpp_name_comps
== None and itraits
.cpp_name_comps
== None:
732 raise Error("cannot specify native(methods) without native(cls)")
734 no_native_instance_specified
= (ni
.construct
== None and itraits
.cpp_name_comps
== None)
736 # if either is specified, make sure both are
737 if t
.cpp_name_comps
!= None or itraits
.cpp_name_comps
!= None:
738 if t
.cpp_name_comps
== None:
739 t
.cpp_name_comps
= BASE_CLASS_NAME
.split('::')
740 if itraits
.cpp_name_comps
== None:
741 itraits
.cpp_name_comps
= BASE_INSTANCE_NAME
.split('::')
742 elif not itraits
.is_interface
:
743 # we are going to create a synthetic class for this
744 t
.cpp_name_comps
= ni
.fullyQualifiedCPPClassName(itraits
.name
.name
+ "Class")
745 t
.is_synthetic
= True
747 # force to True or False (no "None" allowed)
748 if ni
.class_gc_exact
!= True:
749 ni
.class_gc_exact
= False;
750 if ni
.instance_gc_exact
!= True:
751 ni
.instance_gc_exact
= False;
752 t
.is_gc_exact
= ni
.class_gc_exact
753 itraits
.is_gc_exact
= ni
.instance_gc_exact
755 if ni
.construct
!= None:
756 t
.construct
= ni
.construct
757 if t
.construct
in ["override", "instance"]:
758 t
.has_construct_method_override
= True
759 if t
.construct
in ["abstract-restricted", "restricted", "restricted-check"]:
760 t
.is_restricted_inheritance
= True
761 if t
.construct
in ["abstract", "abstract-restricted"]:
762 t
.is_abstract_base
= True
763 if t
.construct
in ["check", "restricted-check"]:
764 t
.has_pre_create_check
= True
765 if ni
.construct
== "instance":
766 itraits
.construct
= "override"
767 itraits
.has_construct_method_override
= True
769 if str(t
.name
) == "Object$" or no_native_instance_specified
:
770 # "Object" is special-cased.
771 t
.createInstanceProcName
= "ClassClosure::createScriptObjectProc"
773 elif t
.construct
in ["none", "abstract", "abstract-restricted"]:
774 t
.createInstanceProcName
= "ClassClosure::cantInstantiateCreateInstanceProc"
776 elif t
.construct
in ["override", "instance"] or itraits
.ctype
!= CTYPE_OBJECT
:
777 t
.createInstanceProcName
= "ClassClosure::impossibleCreateInstanceProc"
779 elif t
.cpp_name_comps
!= None:
780 t
.createInstanceProcName
= "%s::createInstanceProc" % t
.fqcppname()
781 t
.has_custom_createInstanceProc
= True
783 t
.has_const_setters
= ni
.has_const_setters
784 t
.gen_method_map
= ni
.gen_method_map
785 # t.fqinstancebase_name = ni.instancebase_name # not supported for classes
787 t
.method_map_name
= t
.fqcppname() # custom method_map_name never applies to class
788 t
.slotsStructName
= to_cname(t
.fqcppname()) + 'Slots'
789 t
.slotsInstanceName
= 'm_slots_' + t
.cppname()
791 assert itraits
!= None
792 itraits
.has_const_setters
= ni
.has_const_setters
793 itraits
.gen_method_map
= ni
.gen_method_map
794 itraits
.fqinstancebase_name
= ni
.instancebase_name
795 if itraits
.has_cpp_name():
796 if ni
.method_map_name
!= None:
797 itraits
.method_map_name
= ni
.method_map_name
799 itraits
.method_map_name
= itraits
.fqcppname()
800 itraits
.slotsStructName
= to_cname(itraits
.fqcppname()) + 'Slots'
801 itraits
.slotsInstanceName
= 'm_slots_' + itraits
.cppname()
805 "Object": CTYPE_ATOM
, # yes, items of exactly class "Object" are stored as Atom; subclasses are stored as pointer-to-Object
811 "Number": CTYPE_DOUBLE
,
812 "Boolean": CTYPE_BOOLEAN
,
813 "String": CTYPE_STRING
,
814 "Namespace": CTYPE_NAMESPACE
837 cpp_name_comps
= None
838 slotsStructName
= None
839 slotsInstanceName
= None
843 createInstanceProcName
= None
844 # some values for "construct" imply an override to the ScriptObject::construct method,
845 # some don't. this simplifies things.
846 has_construct_method_override
= False
847 has_custom_createInstanceProc
= False
848 is_restricted_inheritance
= False
849 is_abstract_base
= False
850 has_pre_create_check
= False
851 has_const_setters
= False
852 gen_method_map
= False
854 # FIXME, this is a hack for MI classes in AIR
855 fqinstancebase_name
= None
856 # FIXME, this is a hack for MI classes in AIR
857 method_map_name
= None
859 def __init__(self
, name
):
864 if BMAP
.has_key(str(name
)):
865 self
.ctype
= BMAP
[str(name
)]
868 return str(self
.name
)
870 def cpp_offsetof_slots(self
):
871 if (len(self
.slots
) > 0):
872 return "offsetof(%s, %s)" % (self
.fqcppname(), self
.slotsInstanceName
)
876 # What's the C++ type to use when declaring this type as a member of a GCObject?
877 def cpp_gcmember_name(self
):
878 r
= TYPEMAP_MEMBERTYPE
[self
.ctype
]
879 if self
.ctype
== CTYPE_OBJECT
:
880 if self
.has_cpp_name():
881 fqcppname
= self
.fqcppname()
883 fqcppname
= BASE_INSTANCE_NAME
887 # What's the C++ type to use when declaring this type as an input argument to a C++ method?
888 def cpp_argument_name(self
):
889 r
= TYPEMAP_ARGTYPE
[self
.ctype
]
890 if self
.ctype
== CTYPE_OBJECT
:
891 if self
.has_cpp_name():
892 fqcppname
= self
.fqcppname()
894 fqcppname
= BASE_INSTANCE_NAME
898 # What's the C++ type to use when unboxing this type as an input argument to a C++ method?
899 def cpp_unboxing_argument_name(self
):
900 r
= TYPEMAP_ARGTYPE_FOR_UNBOX
[self
.ctype
]
901 if self
.ctype
== CTYPE_OBJECT
:
902 if self
.has_cpp_name():
903 fqcppname
= self
.fqcppname()
905 fqcppname
= BASE_INSTANCE_NAME
909 # What's the C++ type to use when returning this as a function result?
910 def cpp_return_name(self
):
911 r
= TYPEMAP_RETTYPE
[self
.ctype
]
912 if self
.ctype
== CTYPE_OBJECT
:
913 if self
.has_cpp_name():
914 fqcppname
= self
.fqcppname()
916 fqcppname
= BASE_INSTANCE_NAME
920 def has_cpp_name(self
):
921 return self
.cpp_name_comps
!= None
923 # return the fully qualified cpp name, eg "foo::bar::FooObject"
925 return '::'.join(filter(lambda ns
: len(ns
) > 0, self
.cpp_name_comps
))
927 # return the cpp name minus namespaces, eg "FooObject"
929 return self
.cpp_name_comps
[-1]
931 # return the cpp namespace(s), eg "foo::bar"
933 return '::'.join(filter(lambda ns
: len(ns
) > 0, self
.cpp_name_comps
[:-1]))
937 UNDEFINED
= Traits("void")
942 def __init__(self
, data
):
947 r
= unpack_from("B", self
.data
, self
.pos
)[0]
949 assert(r
>= 0 and r
<= 255)
953 r
= unpack_from("<h", self
.data
, self
.pos
)[0]
955 assert(r
>= 0 and r
<= 65535)
958 def readDouble(self
):
959 r
= unpack_from("<d", self
.data
, self
.pos
)[0]
963 def readBytes(self
, lenbytes
):
964 r
= self
.data
[self
.pos
:self
.pos
+lenbytes
]
969 lenbytes
= self
.readU30()
970 return self
.readBytes(lenbytes
)
973 result
= self
.readU8()
974 if not result
& 0x00000080:
976 result
= (result
& 0x0000007f) |
(self
.readU8() << 7)
977 if not result
& 0x00004000:
979 result
= (result
& 0x00003fff) |
(self
.readU8() << 14)
980 if not result
& 0x00200000:
982 result
= (result
& 0x001fffff) |
(self
.readU8() << 21)
983 if not result
& 0x10000000:
985 result
= (result
& 0x0fffffff) |
(self
.readU8() << 28)
1006 publicNs
= Namespace("", CONSTANT_Namespace
)
1007 anyNs
= Namespace("*", CONSTANT_Namespace
)
1009 is_vm_builtin
= False
1016 def __init__(self
, data
, scriptName
):
1017 self
.scriptName
= scriptName
1018 self
.data
= ByteArray(data
)
1020 if self
.data
.readU16() != 16 or self
.data
.readU16() != 46:
1021 raise Error("Bad Abc Version")
1025 self
.defaults
= [ (None, 0) ] * 32
1026 self
.defaults
[CONSTANT_Utf8
] = (self
.strings
, CTYPE_STRING
)
1027 self
.defaults
[CONSTANT_Int
] = (self
.ints
, CTYPE_INT
)
1028 self
.defaults
[CONSTANT_UInt
] = (self
.uints
, CTYPE_UINT
)
1029 self
.defaults
[CONSTANT_Double
] = (self
.doubles
, CTYPE_DOUBLE
)
1030 self
.defaults
[CONSTANT_False
] = ({ CONSTANT_False
: False }, CTYPE_BOOLEAN
)
1031 self
.defaults
[CONSTANT_True
] = ({ CONSTANT_True
: True }, CTYPE_BOOLEAN
)
1032 self
.defaults
[CONSTANT_Namespace
] = (self
.namespaces
, CTYPE_NAMESPACE
)
1033 self
.defaults
[CONSTANT_PrivateNs
] = (self
.namespaces
, CTYPE_NAMESPACE
)
1034 self
.defaults
[CONSTANT_PackageNs
] = (self
.namespaces
, CTYPE_NAMESPACE
)
1035 self
.defaults
[CONSTANT_PackageInternalNs
] = (self
.namespaces
, CTYPE_NAMESPACE
)
1036 self
.defaults
[CONSTANT_ProtectedNs
] = (self
.namespaces
, CTYPE_NAMESPACE
)
1037 self
.defaults
[CONSTANT_StaticProtectedNs
] = (self
.namespaces
, CTYPE_NAMESPACE
)
1038 self
.defaults
[CONSTANT_ExplicitNamespace
] = (self
.namespaces
, CTYPE_NAMESPACE
)
1039 self
.defaults
[CONSTANT_Null
] = ({ CONSTANT_Null
: None }, CTYPE_ATOM
)
1041 self
.parseMethodInfos()
1042 self
.parseMetadataInfos()
1043 self
.parseInstanceInfos()
1044 self
.parseClassInfos()
1045 self
.parseScriptInfos()
1046 self
.parseMethodBodies()
1048 for i
in range(0, len(self
.classes
)):
1050 assert(isinstance(c
.name
, QName
))
1051 prefix
= ns_prefix(c
.name
.ns
, True) + to_cname(c
.name
.name
)
1053 NativeInfo
.parse_native_info(c
, self
.is_vm_builtin
)
1054 self
.assign_names(c
, prefix
)
1056 self
.assign_names(c
.itraits
, prefix
)
1058 for i
in range(0, len(self
.scripts
)):
1059 script
= self
.scripts
[i
]
1061 for j
in range(0, len(script
.tmethods
)):
1062 m
= script
.tmethods
[j
]
1063 if m
.metadata
!= None:
1064 for md
in m
.metadata
:
1065 if md
.name
== "native":
1066 if md
.attrs
.has_key("script"):
1067 raise Error("native(script) is no longer supported; please use a native(\"function-name\") instead: " + str(m
.name
))
1068 if len(md
.attrs
) != 1 or not md
.attrs
.has_key(""):
1069 raise Error("native(\"function-name\") is the only form supported here" + str(m
.name
))
1070 if not m
.isNative():
1071 raise Error("native(\"function-name\") can only be used on native functions" + str(m
.name
))
1073 m
.native_method_name
= md
.attrs
[""] # override
1074 m
.native_id_name
= "native_script_function_" + ns_prefix(m
.name
.ns
, False) + m
.name
.name
1075 m
.gen_method_map
= True
1078 def assign_names(self
, traits
, prefix
):
1079 if traits
.init
!= None:
1080 traits
.init
.assign_names(traits
, prefix
)
1081 for j
in range(0, len(traits
.tmethods
)):
1082 traits
.tmethods
[j
].assign_names(traits
, prefix
)
1084 def default_ctype_and_value(self
,d
):
1086 deftable
= self
.defaults
[kind
]
1087 if deftable
[0] != None:
1088 val
= str(deftable
[0][index
])
1091 assert(kind
== 0 and index
== 0)
1092 val
= "undefinedAtom"
1093 ct
= CTYPE_ATOM
# yes, not void
1095 if ct
== CTYPE_DOUBLE
:
1096 # Python apparently doesn't have isNaN, isInf
1098 val
= "MathUtils::kNaN"
1099 elif is_neg_inf(val
):
1100 val
= "MathUtils::kNegInfinity"
1101 elif is_pos_inf(val
):
1102 val
= "MathUtils::kInfinity"
1103 elif float(val
) >= -2147483648.0 and float(val
) <= 2147483647.0 and float(val
) == floor(float(val
)):
1105 val
= "%.0f" % float(val
)
1106 elif float(val
) >= 0.0 and float(val
) <= 4294967295.0 and float(val
) == floor(float(val
)):
1108 val
= "%.0fU" % float(val
)
1109 elif ct
== CTYPE_STRING
:
1110 for i
in range(0, len(self
.strings
)):
1111 if (self
.strings
[i
] == str(val
)):
1112 val
= "AvmThunkGetConstantString(%d)/* \"%s\" */" % (i
, self
.strings
[i
])
1114 elif ct
== CTYPE_BOOLEAN
:
1115 assert(str(val
) == "False" or str(val
) == "True")
1116 if str(val
) == "False":
1120 if str(val
) == "None":
1121 val
= "nullObjectAtom"
1122 return ct
,val
,rawval
1124 def parseCpool(self
):
1126 n
= self
.data
.readU30()
1127 self
.ints
= [0] * max(1,n
)
1128 for i
in range(1, n
):
1129 ii
= self
.data
.readU30()
1130 if float(ii
) > 2147483647.0:
1131 ii
= int(ii
- 4294967296.0)
1132 assert(int(ii
) >= -2147483648 and int(ii
) <= 2147483647)
1133 self
.ints
[i
] = int(ii
)
1135 n
= self
.data
.readU30()
1136 self
.uints
= [0] * max(1,n
)
1137 for i
in range(1, n
):
1138 self
.uints
[i
] = uint(self
.data
.readU30())
1140 n
= self
.data
.readU30()
1141 self
.doubles
= [ kNaN
] * max(1,n
)
1142 for i
in range(1, n
):
1143 self
.doubles
[i
] = self
.data
.readDouble()
1145 n
= self
.data
.readU30()
1146 self
.strings
= [""] * max(1,n
)
1147 for i
in range(1, n
):
1148 self
.strings
[i
] = self
.data
.readUTF8()
1150 n
= self
.data
.readU30()
1151 self
.namespaces
= [self
.anyNs
] * max(1,n
)
1152 for i
in range(1, n
):
1153 nskind
= self
.data
.readU8()
1154 if nskind
in [CONSTANT_Namespace
,
1156 CONSTANT_PackageInternalNs
,
1157 CONSTANT_ProtectedNs
,
1158 CONSTANT_ExplicitNamespace
,
1159 CONSTANT_StaticProtectedNs
]:
1160 uri
= self
.strings
[self
.data
.readU30()]
1161 self
.namespaces
[i
] = Namespace(uri
, nskind
)
1162 # if it's public, and the final char has the magic "version mark",
1163 # it's a versioned namespace uri
1164 if nskind
in [CONSTANT_Namespace
, CONSTANT_PackageNs
]:
1165 api
, strippeduri
= stripVersion(uri
)
1167 if not strippeduri
in self
.versioned_uris
:
1168 self
.versioned_uris
[strippeduri
] = []
1169 if not api
in self
.versioned_uris
[strippeduri
]:
1170 self
.versioned_uris
[strippeduri
].append(api
)
1172 elif nskind
in [CONSTANT_PrivateNs
]:
1173 self
.data
.readU30() # skip
1174 self
.namespaces
[i
] = Namespace("private", CONSTANT_PrivateNs
)
1176 n
= self
.data
.readU30()
1177 self
.nssets
= [ None ] * max(1,n
)
1178 for i
in range(1, n
):
1179 count
= self
.data
.readU30()
1181 for j
in range(0, count
):
1182 self
.nssets
[i
].append(self
.namespaces
[self
.data
.readU30()])
1184 n
= self
.data
.readU30()
1185 self
.names
= [ None ] * max(1,n
)
1186 for i
in range(1, n
):
1187 namekind
= self
.data
.readU8()
1188 if namekind
in [CONSTANT_Qname
, CONSTANT_QnameA
]:
1189 self
.names
[i
] = QName(self
.namespaces
[self
.data
.readU30()], self
.strings
[self
.data
.readU30()])
1191 elif namekind
in [CONSTANT_RTQname
, CONSTANT_RTQnameA
]:
1192 self
.names
[i
] = QName(self
.anyNs
, self
.strings
[self
.data
.readU30()])
1194 elif namekind
in [CONSTANT_RTQnameL
, CONSTANT_RTQnameLA
]:
1195 self
.names
[i
] = None
1197 elif namekind
in [CONSTANT_NameL
, CONSTANT_NameLA
]:
1198 self
.names
[i
] = QName(Namespace(""), None)
1200 elif namekind
in [CONSTANT_Multiname
, CONSTANT_MultinameA
]:
1201 name
= self
.strings
[self
.data
.readU30()]
1202 nsset
= self
.nssets
[self
.data
.readU30()]
1203 self
.names
[i
] = Multiname(nsset
, name
)
1205 elif namekind
in [CONSTANT_MultinameL
, CONSTANT_MultinameLA
]:
1206 nsset
= self
.nssets
[self
.data
.readU30()]
1207 self
.names
[i
] = Multiname(nsset
, None)
1209 elif namekind
in [CONSTANT_TypeName
]:
1210 name
= self
.names
[self
.data
.readU30()];
1211 count
= self
.data
.readU30();
1213 for j
in range(0, count
):
1214 types
.append(self
.names
[self
.data
.readU30()]);
1215 self
.names
[i
] = TypeName(name
, types
);
1217 raise Error("Bad Kind")
1219 def parseMethodInfos(self
):
1220 self
.names
[0] = QName(self
.publicNs
,"*")
1221 method_count
= self
.data
.readU30()
1222 self
.methods
= [ None ] * method_count
1223 for i
in range(0, method_count
):
1226 param_count
= self
.data
.readU30()
1227 m
.returnType
= self
.names
[self
.data
.readU30()]
1228 m
.paramTypes
= [ None ] * param_count
1229 m
.paramNames
= [ "" ] * param_count
1230 m
.optional_count
= 0
1231 for j
in range(0, param_count
):
1232 m
.paramTypes
[j
] = self
.names
[self
.data
.readU30()]
1233 m
.debugName
= self
.strings
[self
.data
.readU30()]
1234 m
.flags
= self
.data
.readU8()
1236 m
.optional_count
= self
.data
.readU30();
1237 m
.optionalValues
= [ (-1, -1) ] * param_count
1238 for k
in range(param_count
-m
.optional_count
, param_count
):
1239 index
= self
.data
.readU30()
1240 kind
= self
.data
.readU8()
1241 m
.optionalValues
[k
] = (kind
, index
)
1242 if (m
.flags
& HAS_ParamNames
) != 0:
1243 for j
in range(0, param_count
):
1244 m
.paramNames
[j
] = self
.strings
[self
.data
.readU30()]
1246 def parseMetadataInfos(self
):
1247 count
= self
.data
.readU30()
1248 self
.metadata
= [ None ] * count
1249 for i
in range (0, count
):
1250 mname
= self
.strings
[self
.data
.readU30()]
1252 self
.metadata
[i
] = m
1253 values_count
= self
.data
.readU30()
1254 names
= [ None ] * values_count
1255 for q
in range(0, values_count
):
1256 names
[q
] = self
.strings
[self
.data
.readU30()]
1257 for q
in range(0, values_count
):
1258 m
.attrs
[names
[q
]] = self
.strings
[self
.data
.readU30()]
1260 def parseInstanceInfos(self
):
1261 count
= self
.data
.readU30()
1262 self
.instances
= [ None ] * count
1264 for i
in range (0, count
):
1265 tname
= self
.names
[self
.data
.readU30()]
1267 self
.instances
[i
] = t
1268 instancesDict
[id(tname
)] = t
1269 t
.base
= self
.names
[self
.data
.readU30()]
1270 t
.flags
= self
.data
.readU8()
1271 if (t
.flags
& 1) != 0:
1273 if (t
.flags
& 2) != 0:
1275 if (t
.flags
& 4) != 0:
1276 t
.is_interface
= True
1277 if (t
.flags
& 8) != 0:
1278 t
.protectedNs
= self
.namespaces
[self
.data
.readU30()]
1279 interface_count
= self
.data
.readU30()
1280 t
.interfaces
= [None] * interface_count
1281 for j
in range(0, interface_count
):
1282 t
.interfaces
[j
] = self
.names
[self
.data
.readU30()]
1283 methid
= self
.data
.readU30()
1284 t
.init
= self
.methods
[methid
]
1285 t
.init
.name
= t
.name
1286 t
.init
.kind
= TRAIT_Method
1288 self
.parseTraits(t
, instancesDict
.get(id(t
.base
), None))
1292 if isinstance(name
, QName
):
1294 if len(name
.nsset
) == 0:
1295 return QName(Namespace("", CONSTANT_Namespace
), name
.name
)
1296 return QName(name
.nsset
[0].stripVersion(), name
.name
)
1298 def qname(self
, name
):
1299 if (not self
.nameToQName
.has_key(id(name
))):
1301 result
= self
.__qname
(name
)
1305 self
.qnameToName
[id(result
)] = name
1306 self
.nameToQName
[id(name
)] = result
1308 return self
.nameToQName
[id(name
)]
1310 def parseTraits(self
, t
, baseTraits
=None):
1311 lastBaseTraitsSlotId
= 0 if baseTraits
is None else baseTraits
.nextSlotId
1312 namecount
= self
.data
.readU30()
1313 t
.members
= [ None ] * namecount
1314 for i
in range(0, namecount
):
1315 name_index
= self
.data
.readU30()
1316 name
= self
.names
[name_index
]
1317 name
= self
.qname(name
)
1318 bindingOffset
= self
.data
.pos
1319 tag
= self
.data
.readU8()
1322 if kind
in [TRAIT_Slot
, TRAIT_Const
, TRAIT_Class
]:
1324 member
.fileOffset
= bindingOffset
1325 memberId
= self
.data
.readU30()
1326 member
.id = (memberId
- 1) if memberId
!= 0 else (len(t
.slots
) + lastBaseTraitsSlotId
)
1327 memberIndex
= member
.id - lastBaseTraitsSlotId
1328 while len(t
.slots
) <= memberIndex
:
1329 t
.slots
.append(None)
1330 t
.slots
[member
.id - lastBaseTraitsSlotId
] = member
1331 t
.nextSlotId
= max(t
.nextSlotId
, member
.id + 1)
1332 if kind
in [TRAIT_Slot
, TRAIT_Const
]:
1333 member
.type = self
.names
[self
.data
.readU30()]
1334 index
= self
.data
.readU30()
1336 deftable
= self
.defaults
[self
.data
.readU8()]
1337 member
.value
= deftable
[0][index
]
1338 if deftable
[1] == CTYPE_NAMESPACE
:
1339 assert(isinstance(member
.value
, Namespace
))
1340 member
.value
.srcname
= name
.name
1342 member
.value
= self
.classes
[self
.data
.readU30()]
1343 member
.value
.qname
= name
1344 elif kind
in [TRAIT_Method
, TRAIT_Getter
, TRAIT_Setter
]:
1345 self
.data
.readU30() # disp_id, ignored
1346 methid
= self
.data
.readU30()
1347 member
= self
.methods
[methid
]
1348 t
.tmethods
.append(member
)
1350 member
.final
= (tag
& ATTR_final
) != 0
1351 member
.override
= (tag
& ATTR_override
) != 0
1354 t
.members
[i
] = member
1355 t
.names
[str(name
)] = member
1357 if (tag
& ATTR_metadata
) != 0:
1358 mdCount
= self
.data
.readU30()
1359 member
.metadata
= [ None ] * mdCount
1360 for j
in range(0, mdCount
):
1361 member
.metadata
[j
] = self
.metadata
[self
.data
.readU30()]
1362 # stash class metadata in the ctraits and itraits too, makes it much easier later
1363 if kind
== TRAIT_Class
:
1364 member
.value
.metadata
= member
.metadata
1365 member
.value
.itraits
.metadata
= member
.metadata
1367 def parseClassInfos(self
):
1368 count
= len(self
.instances
)
1369 self
.classes
= [ None ] * count
1370 for i
in range(0, count
):
1371 itraits
= self
.instances
[i
]
1372 tname
= QName(itraits
.name
.ns
, (str(itraits
.name
.name
) + "$"))
1373 if str(tname
) == "Object$":
1374 self
.is_vm_builtin
= True
1377 t
.init
= self
.methods
[self
.data
.readU30()]
1381 t
.init
.name
= str(t
.itraits
.name
) + "$cinit"
1382 t
.init
.kind
= TRAIT_Method
1385 def parseScriptInfos(self
):
1386 count
= self
.data
.readU30()
1387 self
.scripts
= [ None ] * count
1388 for i
in range(0, count
):
1389 tname
= self
.scriptName
+ "_script_" + str(i
)
1392 t
.init
= self
.methods
[self
.data
.readU30()]
1393 t
.base
= self
.names
[0]
1395 t
.init
.name
= t
.name
+ "$init"
1396 t
.init
.kind
= TRAIT_Method
1399 def parseMethodBodies(self
):
1400 count
= self
.data
.readU30()
1401 for i
in range(0, count
):
1402 m
= self
.methods
[self
.data
.readU30()]
1403 m
.max_stack
= self
.data
.readU30()
1404 m
.local_count
= self
.data
.readU30()
1405 initScopeDepth
= self
.data
.readU30()
1406 maxScopeDepth
= self
.data
.readU30()
1407 m
.max_scope
= maxScopeDepth
- initScopeDepth
1408 code_length
= self
.data
.readU30()
1409 m
.code
= self
.data
.readBytes(code_length
)
1410 ex_count
= self
.data
.readU30()
1411 for j
in range(0, ex_count
):
1412 frm
= self
.data
.readU30()
1413 to
= self
.data
.readU30()
1414 target
= self
.data
.readU30()
1415 type = self
.names
[self
.data
.readU30()]
1416 name
= self
.names
[self
.data
.readU30()];
1417 m
.activation
= Traits(None)
1418 self
.parseTraits(m
.activation
)
1421 class IndentingPrintWriter
:
1427 def __init__(self
, file):
1432 for i
in range(0, self
.indent
):
1434 self
.do_indent
= False
1440 def println(self
, s
):
1441 assert self
.indent
>= 0
1445 if self
.backslash
> 0:
1448 self
.do_indent
= True
1451 NON_POINTER_4_BYTE_SLOT_BUCKET
= 0
1452 POINTER_SLOT_BUCKET
= 1
1453 NON_POINTER_8_BYTE_SLOT_BUCKET
= 2
1455 CTYPE_TO_SLOT_SORT_BUCKET
= {
1456 # following types are 4 bytes
1457 CTYPE_INT
: NON_POINTER_4_BYTE_SLOT_BUCKET
,
1458 CTYPE_UINT
: NON_POINTER_4_BYTE_SLOT_BUCKET
,
1459 CTYPE_BOOLEAN
: NON_POINTER_4_BYTE_SLOT_BUCKET
,
1460 # following types are pointer size ( either 4 or 8 bytes )
1461 CTYPE_OBJECT
: POINTER_SLOT_BUCKET
,
1462 CTYPE_ATOM
: POINTER_SLOT_BUCKET
,
1463 CTYPE_STRING
: POINTER_SLOT_BUCKET
,
1464 CTYPE_NAMESPACE
: POINTER_SLOT_BUCKET
,
1465 # doubles are 8 bytes
1466 CTYPE_DOUBLE
: NON_POINTER_8_BYTE_SLOT_BUCKET
,
1467 # slots should never be of type void
1471 CTYPE_TO_NEED_FORWARD_DECL
= {
1474 CTYPE_BOOLEAN
: False,
1475 CTYPE_OBJECT
: True,
1477 CTYPE_STRING
: True,
1478 CTYPE_NAMESPACE
: True,
1479 CTYPE_DOUBLE
: False,
1483 GLUECLASSES_WITHOUT_SLOTS
= frozenset((
1487 'avmplus::Namespace',
1491 GLUECLASSES_WITHOUT_CONSTRUCT_WRAPPERS
= frozenset((
1501 lookup_traits
= None
1504 def addAbc(self
, a
):
1506 self
.lookup_traits
= None
1508 def class_native_name(self
, c
):
1509 return ns_prefix(c
.qname
.ns
, True) + to_cname(c
.qname
.name
)
1511 def class_id_name(self
, c
):
1512 return "abcclass_" + self
.class_native_name(c
)
1514 def emitAOT(self
, out
, name
, ctypeObject
):
1515 out
.println('#ifdef VMCFG_AOT')
1517 traits
= filter(lambda t
: (t
.has_cpp_name()) and (not t
.is_synthetic
) and (t
.fqcppname() != "double") and ((t
.ctype
== ctypeObject
) or (t
.fqcppname() == BASE_INSTANCE_NAME
) or (t
.fqcppname() == BASE_CLASS_NAME
)), self
.abc
.classes
+ self
.abc
.instances
)
1518 glueClasses
= sorted(set(map(lambda t
: t
.fqcppname(), traits
)))
1520 out
.println('extern "C" const struct {')
1524 for i
in range(0, len(glueClasses
)):
1525 out
.println('const char* const n_%(count)u; %(glueClass)s* const m_%(count)u;' % { 'count' : i
, 'glueClass': glueClasses
[i
]})
1528 out
.println('} aotABCTypes_%s = {' % name
)
1532 for i
in range(0, len(glueClasses
)):
1533 out
.println('"%(glueClass)s", 0,' % { 'count' : i
, 'glueClass': glueClasses
[i
]})
1538 out
.println('#endif')
1540 def emit_h(self
, out
, name
):
1542 out
.println(MPL_HEADER
);
1544 out
.println("/* machine generated file -- do not edit */");
1547 out
.println("#ifndef _H_nativegen_header_%s" % name
);
1548 out
.println("#define _H_nativegen_header_%s" % name
);
1551 self
.forwardDeclareGlueClasses(out
)
1553 nativeIDNamespaces
= opts
.nativeIDNS
.split('::')
1554 out
.println(' '.join(map(lambda ns
: 'namespace %s {' % ns
, nativeIDNamespaces
)))
1557 out
.println('extern const uint32_t '+name
+"_abc_class_count;")
1558 out
.println('extern const uint32_t '+name
+"_abc_script_count;")
1559 out
.println('extern const uint32_t '+name
+"_abc_method_count;")
1560 out
.println('extern const uint32_t '+name
+"_abc_length;")
1561 out
.println('extern const uint8_t '+name
+"_abc_data[];");
1562 out
.println('extern const char* const '+name
+"_versioned_uris[];");
1564 out
.println("AVMTHUNK_DECLARE_NATIVE_INITIALIZER(%s)" % (name
));
1567 out
.println("/* classes */");
1568 for i
in range(0, len(self
.abc
.classes
)):
1569 c
= self
.abc
.classes
[i
]
1570 out
.println("const uint32_t " + self
.class_id_name(c
) + " = " + str(c
.class_id
) + ";");
1573 out
.println("/* methods */");
1574 for i
in range(0, len(self
.abc
.methods
)):
1575 m
= self
.abc
.methods
[i
]
1576 if m
.native_id_name
!= None:
1579 out
.println("const uint32_t "+m
.native_id_name
+" = "+str(m
.id)+";");
1581 # not sure if we want to expose method id's for non-native methods; emit as comments for now
1582 out
.println("/* const uint32_t "+m
.native_id_name
+" = "+str(m
.id)+"; */");
1585 for receiver
,m
in self
.all_thunks
:
1586 self
.emitThunkProto(out
, receiver
, m
);
1588 out
.println('class SlotOffsetsAndAsserts;')
1589 self
.emitStructDeclarations(out
)
1591 out
.println(' '.join(('}',) * len(nativeIDNamespaces
)))
1593 out
.println('namespace %s {' % opts
.rootImplNS
)
1594 self
.emitGlueClassManifest(out
)
1597 out
.println("#endif // _H_nativegen_header_%s" % name
);
1600 def emit_cls(self
, out
, name
):
1602 out
.println(MPL_HEADER
);
1604 out
.println("/* machine generated file -- do not edit */");
1606 out
.println("#ifndef _H_nativegen_classes_%s" % name
);
1607 out
.println("#define _H_nativegen_classes_%s" % name
);
1610 rootNS
= opts
.rootImplNS
.split('::')
1611 out
.println(' '.join(map(lambda ns
: 'namespace %s {' % ns
, rootNS
)))
1614 self
.emitSyntheticClasses(out
)
1616 out
.println(' '.join(('}',) * len(rootNS
)))
1619 out
.println("#endif // _H_nativegen_classes_%s" % name
);
1621 def emit_cpp(self
, out
, name
):
1623 out
.println(MPL_HEADER
);
1625 out
.println("/* machine generated file -- do not edit */");
1628 nativeIDNamespaces
= opts
.nativeIDNS
.split('::')
1629 out
.println(' '.join(map(lambda ns
: 'namespace %s {' % ns
, nativeIDNamespaces
)))
1632 out
.println("const uint32_t "+name
+"_abc_class_count = "+str(len(self
.abc
.classes
))+";");
1633 out
.println("const uint32_t "+name
+"_abc_script_count = "+str(len(self
.abc
.scripts
))+";");
1634 out
.println("const uint32_t "+name
+"_abc_method_count = "+str(len(self
.abc
.methods
))+";");
1635 out
.println("const uint32_t "+name
+"_abc_length = "+str(len(self
.abc
.data
.data
))+";");
1638 out
.println("/* thunks (%d total) */" % len(self
.all_thunks
));
1640 out
.println("#define DOPROF")
1641 out
.println('#include "../vprof/vprof.h"')
1643 for receiver
,m
in self
.all_thunks
:
1644 self
.emitThunkBody(out
, receiver
, m
);
1647 self
.printStructAsserts(out
, self
.abc
)
1651 out
.println("AVMTHUNK_BEGIN_NATIVE_TABLES(%s)" % self
.abc
.scriptName
)
1655 out
.println("AVMTHUNK_BEGIN_NATIVE_METHODS(%s)" % self
.abc
.scriptName
)
1657 for i
in range(0, len(self
.abc
.methods
)):
1658 m
= self
.abc
.methods
[i
]
1659 if m
.isNative() and (m
.receiver
== None or m
.receiver
.gen_method_map
):
1660 assert(m
.native_method_name
!= None)
1661 assert(m
.native_id_name
!= None)
1662 if m
.receiver
== None:
1663 out
.println("AVMTHUNK_NATIVE_FUNCTION(%s, %s)" % (m
.native_id_name
, m
.native_method_name
))
1665 # special-case the two oddballs of the group: String and Namespace
1666 # don't descend from ScriptObject and so need a little extra love.
1667 if str(m
.receiver
.name
) == "String":
1668 nmout
= "AVMTHUNK_NATIVE_METHOD_STRING"
1669 elif str(m
.receiver
.name
) == "Namespace":
1670 nmout
= "AVMTHUNK_NATIVE_METHOD_NAMESPACE"
1672 nmout
= "AVMTHUNK_NATIVE_METHOD"
1673 out
.println("%s(%s, %s::%s)" % (nmout
, m
.native_id_name
, m
.receiver
.method_map_name
, m
.native_method_name
))
1675 out
.println("AVMTHUNK_END_NATIVE_METHODS()")
1678 out
.println("AVMTHUNK_BEGIN_NATIVE_CLASSES(%s)" % self
.abc
.scriptName
)
1680 for i
in range(0, len(self
.abc
.classes
)):
1681 c
= self
.abc
.classes
[i
]
1682 if (c
.has_cpp_name() or c
.itraits
.has_cpp_name()) and not c
.is_synthetic
:
1683 if c
.gen_method_map
:
1684 offsetOfSlotsClass
= "SlotOffsetsAndAsserts::kSlotsOffset%s" % c
.cppname()
1685 offsetOfSlotsInstance
= "SlotOffsetsAndAsserts::kSlotsOffset%s" % c
.itraits
.cppname()
1686 out
.println("AVMTHUNK_NATIVE_CLASS(%s, %s, %s, %s, %s, %s, %s, %s, %s)" %\
1687 (self
.class_id_name(c
),\
1690 offsetOfSlotsClass
,\
1691 c
.itraits
.fqcppname(),\
1692 offsetOfSlotsInstance
,\
1693 str(c
.has_construct_method_override
).lower(),
1694 str(c
.is_restricted_inheritance
).lower(),
1695 str(c
.is_abstract_base
).lower()))
1697 out
.println("NATIVE_CLASS(%s, %s, %s)" % (self
.class_id_name(c
), c
.fqcppname(), c
.itraits
.fqcppname()))
1699 out
.println("AVMTHUNK_END_NATIVE_CLASSES()")
1703 out
.println("AVMTHUNK_END_NATIVE_TABLES()")
1706 out
.println("AVMTHUNK_DEFINE_NATIVE_INITIALIZER(%s)" % (name
));
1708 if opts
.externmethodandclassetables
:
1710 out
.println('extern const NativeClassInfo* '+name
+"_classEntriesExtern = "+name
+"_classEntries;");
1711 out
.println('extern const NativeMethodInfo* '+name
+"_methodEntriesExtern = "+name
+"_methodEntries;");
1714 out
.println("/* abc */");
1715 n
= len(self
.abc
.data
.data
)
1716 out
.println("const uint8_t "+name
+"_abc_data["+str(n
)+"] = {");
1717 for i
in range(0, n
):
1718 x
= ord(self
.abc
.data
.data
[i
]) & 255;
1728 out
.println("/* versioned_uris */");
1729 out
.println("const char* const "+name
+"_versioned_uris[] = {");
1731 # don't really need to sort 'em, but helps keep output stable
1732 sorted_keys
= sorted(self
.abc
.versioned_uris
.keys())
1733 for i
in sorted_keys
:
1734 # The empty URI (aka "public") is always versioned
1735 # (and special-cased by the versioning code in AvmCore)
1736 # so don't bother emitting it.
1738 out
.println('"%s", // %s' % (i
, str(sorted(self
.abc
.versioned_uris
[i
]))))
1744 self
.emitAOT(out
, name
, CTYPE_OBJECT
)
1746 out
.println(' '.join(('}',) * len(nativeIDNamespaces
)))
1748 # note, these are emitted *after* closing the namespaces
1749 self
.emitStructStubs(out
)
1751 def emit(self
, abc
, name
, out_h
, out_cls
, out_c
):
1753 self
.all_thunks
= []
1754 self
.lookup_traits
= None
1756 for i
in range(1, len(abc
.names
)):
1757 if (not isinstance(abc
.names
[i
], TypeName
)):
1758 self
.namesDict
[id(abc
.qname(abc
.names
[i
]))] = i
1760 for i
in range(0, len(abc
.scripts
)):
1761 script
= abc
.scripts
[i
]
1763 self
.processTraits(script
)
1765 self
.emit_h(out_h
, name
)
1766 self
.emit_cls(out_cls
, name
)
1767 self
.emit_cpp(out_c
, name
)
1769 def forwardDeclareGlueClasses(self
, out_h
):
1770 # find all the native glue classes and write forward declarations for them
1771 cppNamespaceToGlueClasses
= {}
1773 for i
in range(0, len(self
.abc
.classes
)):
1774 c
= self
.abc
.classes
[i
]
1775 if c
.has_cpp_name():
1777 if (c
.itraits
.has_cpp_name()):
1778 traitsSet
.add(c
.itraits
)
1780 for t
in frozenset(traitsSet
):
1781 filteredSlots
= filter(lambda s
: s
is not None, t
.slots
)
1782 for s
in filteredSlots
:
1783 slotTraits
= self
.lookupTraits(s
.type)
1784 traitsSet
.add(slotTraits
)
1786 glueClassToTraits
= {}
1787 for t
in sorted(traitsSet
):
1788 if ((t
.has_cpp_name()) and (CTYPE_TO_NEED_FORWARD_DECL
[t
.ctype
])):
1790 glueClassName
= t
.cppname()
1791 # special hack because the metadata for the class Math says its instance data is of type double
1792 if glueClassName
!= "double":
1793 cppNamespaceToGlueClasses
.setdefault(classNS
, set()).add(glueClassName
)
1794 key
= classNS
+ '::' + glueClassName
1795 if not key
in glueClassToTraits
:
1796 glueClassToTraits
[key
] = []
1797 glueClassToTraits
[key
].append(t
)
1798 for (nsStr
, glueClasses
) in sorted(cppNamespaceToGlueClasses
.iteritems()):
1799 # turn list of namespaces [foo, bar, baz] into "namespace foo { namespace bar { namespace baz {"
1800 nsList
= nsStr
.split('::')
1801 out_h
.println(' '.join(map(lambda ns
: 'namespace %s {' % ns
, nsList
)))
1804 # this can emit the same class multiple times; that's by design,
1805 # for clarity & stability of output
1806 for glueClass
in sorted(glueClasses
):
1807 traitsList
= glueClassToTraits
[nsStr
+ '::' + glueClass
]
1808 for traits
in sorted(traitsList
):
1809 out_h
.println('class %s; // %s' % (glueClass
, traits
))
1811 out_h
.println(' '.join(('}',) * len(nsList
)))
1814 def emitGlueClassManifest(self
, out
):
1816 for i
in range(0, len(self
.abc
.classes
)):
1817 c
= self
.abc
.classes
[i
]
1818 as3name
= to_cname(c
.itraits
.name
.name
) + "Class"
1819 if c
.has_cpp_name() or c
.itraits
.has_cpp_name():
1820 cppname
= c
.fqcppname()
1822 cppname
= BASE_CLASS_NAME
1823 clsid
= "%s::%s" % (opts
.nativeIDNS
, self
.class_id_name(c
))
1824 names
.append((as3name
,cppname
,clsid
))
1825 names
= sorted(names
)
1826 man_name
= "%sClassManifest" % self
.abc
.scriptName
1828 out
.println("class %s : public avmplus::ClassManifestBase" % man_name
)
1831 out
.println("friend class avmplus::AvmCore;")
1832 out
.println("friend class avmplus::IntVectorClass;")
1833 out
.println("friend class avmplus::UIntVectorClass;")
1834 out
.println("friend class avmplus::DoubleVectorClass;")
1835 out
.println("friend class avmplus::ObjectVectorClass;")
1837 out
.println("private:")
1839 out
.println("REALLY_INLINE %s(avmplus::ScriptEnv* e) : ClassManifestBase(%d, e) { }" % (man_name
, len(names
)))
1840 out
.println("REALLY_INLINE static %s* create(avmplus::ScriptEnv* e) { return new (MMgc::GC::GetGC(e), MMgc::kExact, sizeof(ClassClosure*)*%d) %s(e); }" % (man_name
, len(names
)-1, man_name
))
1842 out
.println("public:")
1844 for as3name
,cppname
,clsid
in names
:
1845 # We can't use static_cast<> because the subclass is only forward-declared at this point
1846 out
.println("REALLY_INLINE GCRef<%s> get_%s() { return (%s*)(lazyInitClass(%s)); }" % (cppname
, as3name
, cppname
, clsid
))
1851 def cmpSlots(slotA
, slotB
, slotsTypeInfo
):
1852 if (slotA
is slotB
):
1855 # slotA or slotB could be None, which means they are an anonymous slot.
1856 # Anonymous slots should be at the end of the pointer slots.
1857 ctype_b
= slotsTypeInfo
[id(slotB
)][0]
1858 slotBBucket
= CTYPE_TO_SLOT_SORT_BUCKET
[ctype_b
] if (slotB
is not None) else POINTER_SLOT_BUCKET
1860 if (slotBBucket
<= POINTER_SLOT_BUCKET
):
1865 assert slotA
is not None
1866 ctype_a
= slotsTypeInfo
[id(slotA
)][0]
1867 slotABucket
= CTYPE_TO_SLOT_SORT_BUCKET
[ctype_a
]
1869 if (slotBBucket
<= POINTER_SLOT_BUCKET
):
1874 assert slotB
is not None
1875 slotBucketCmp
= cmp(slotABucket
, slotBBucket
)
1876 if (slotBucketCmp
!= 0):
1877 return slotBucketCmp
1878 return cmp(slotA
.fileOffset
, slotB
.fileOffset
)
1881 def needsInstanceSlotsStruct(c
):
1882 return (c
.itraits
.has_cpp_name()) and (c
.itraits
.fqcppname() != BASE_INSTANCE_NAME
)
1884 def emitStructDeclarations(self
, out
):
1885 visitedGlueClasses
= set()
1886 for i
in range(0, len(self
.abc
.classes
)):
1887 c
= self
.abc
.classes
[i
]
1888 if (c
.has_cpp_name()):
1889 self
.emitStructDeclarationsForTraits(out
, c
, visitedGlueClasses
, True)
1890 if (self
.needsInstanceSlotsStruct(c
)):
1891 self
.emitStructDeclarationsForTraits(out
, c
.itraits
, visitedGlueClasses
, False)
1893 assert not self
.needsInstanceSlotsStruct(c
)
1895 def emitStructInlines(self
, out
):
1896 for i
in range(0, len(self
.abc
.classes
)):
1897 c
= self
.abc
.classes
[i
]
1898 if (c
.has_cpp_name()):
1899 self
.emitMethodWrapperBodies(out
, c
)
1900 self
.emitMethodWrapperBodies(out
, c
.itraits
)
1902 def emitStructStubs(self
, out
):
1903 visitedGlueClasses
= set()
1904 for i
in range(0, len(self
.abc
.classes
)):
1905 c
= self
.abc
.classes
[i
]
1906 if (c
.has_cpp_name()):
1907 self
.emitStructStubsForTraits(out
, c
, visitedGlueClasses
, True)
1908 if (self
.needsInstanceSlotsStruct(c
)):
1909 self
.emitStructStubsForTraits(out
, c
.itraits
, visitedGlueClasses
, False)
1911 assert not self
.needsInstanceSlotsStruct(c
)
1913 def sortSlots(self
, t
):
1914 filteredSlots
= filter(lambda s
: s
is not None, t
.slots
)
1917 for slot
in filteredSlots
:
1918 slotTraits
= self
.lookupTraits(slot
.type)
1919 slotCType
= slotTraits
.ctype
1920 if slotCType
== CTYPE_VOID
:
1921 raise Error("A slot should never be CTYPE_VOID")
1922 slotArgType
= slotTraits
.cpp_argument_name()
1923 slotRetType
= slotTraits
.cpp_return_name()
1924 slotMemberType
= slotTraits
.cpp_gcmember_name()
1925 slotsTypeInfo
[id(slot
)] = (slotCType
, slotArgType
, slotRetType
, slotMemberType
)
1927 sortedSlots
= sorted(t
.slots
, lambda x
,y
: self
.cmpSlots(x
, y
, slotsTypeInfo
))
1928 return sortedSlots
, slotsTypeInfo
1930 def emitDeclareSlotClass(self
, out
, t
, sortedSlots
, slotsTypeInfo
, isClassTraits
):
1932 out
.println('//-----------------------------------------------------------')
1933 out
.println('// %s' % str(t
.name
))
1934 out
.println('//-----------------------------------------------------------')
1935 out
.println('class %s' % t
.slotsStructName
)
1938 out
.println('friend class SlotOffsetsAndAsserts;')
1940 out
.println('public:')
1943 for slot
in sortedSlots
:
1944 if (slot
is not None):
1945 assert slot
.kind
in (TRAIT_Slot
, TRAIT_Const
)
1946 (slotCType
, slotArgType
, slotRetType
, slotMemberType
) = slotsTypeInfo
[id(slot
)]
1947 name
= to_cname(slot
.name
)
1948 if slotCType
== CTYPE_BOOLEAN
:
1949 out
.println('REALLY_INLINE %s get_%s() const { return m_%s != 0; }' % (slotRetType
, name
, name
))
1951 out
.println('REALLY_INLINE %s get_%s() const { return m_%s; }' % (slotRetType
, name
, name
))
1952 if ((slot
.kind
== TRAIT_Slot
) or (t
.has_const_setters
)):
1953 out
.println('REALLY_INLINE void set_%s(%s newVal) { m_%s = newVal; }' % (name
, slotArgType
, name
))
1955 out
.println('private:')
1959 for slot
in sortedSlots
:
1960 if (slot
is not None):
1961 assert slot
.kind
in (TRAIT_Slot
, TRAIT_Const
)
1962 (slotCType
, slotArgType
, slotRetType
, slotMemberType
) = slotsTypeInfo
[id(slot
)]
1963 out
.println('%s m_%s;' % (slotMemberType
, to_cname(slot
.name
)))
1965 out
.println('Atom __anonymous_slot_%u;' % (anonCount
))
1966 anonCount
= anonCount
+ 1
1970 for slot
in sortedSlots
:
1971 if (slot
is not None):
1972 slotTraits
= self
.lookupTraits(slot
.type)
1973 if slotTraits
.ctype
== CTYPE_ATOM
:
1975 elif (slotTraits
.ctype
== CTYPE_STRING
) or (slotTraits
.ctype
== CTYPE_NAMESPACE
) or (slotTraits
.ctype
== CTYPE_OBJECT
):
1979 if numTracedSlots
> 0:
1981 out
.println('public:');
1983 out
.println('REALLY_INLINE void gcTracePrivateProperties(MMgc::GC* gc)')
1987 for slot
in sortedSlots
:
1988 if (slot
is not None):
1989 slotTraits
= self
.lookupTraits(slot
.type)
1990 if slotTraits
.ctype
== CTYPE_ATOM
:
1991 out
.println('gc->TraceAtom(&m_%s);' % to_cname(slot
.name
))
1992 elif (slotTraits
.ctype
== CTYPE_STRING
) or (slotTraits
.ctype
== CTYPE_NAMESPACE
) or (slotTraits
.ctype
== CTYPE_OBJECT
):
1993 out
.println('gc->TraceLocation(&m_%s);' % to_cname(slot
.name
))
1995 out
.println('gc->TraceAtom(&__anonymous_slot_%u);' % (anonCount
,))
1996 anonCount
= anonCount
+ 1
2001 out
.println('#define GC_TRIVIAL_TRACER_' + t
.cppname())
2007 def emitConstructDeclarations(self
, out
, t
, sortedSlots
, slotsTypeInfo
, isClassTraits
):
2013 # FIXME: make these non-public, friend access only
2014 out
.println("public:")
2016 out
.println("static %s* FASTCALL createClassClosure(avmplus::VTable* cvtable);" % BASE_CLASS_NAME
)
2019 if t
.has_custom_createInstanceProc
:
2020 out
.println("public:")
2022 if t
.has_pre_create_check
:
2023 out
.println("static void FASTCALL preCreateInstanceCheck(%s*);" % BASE_CLASS_NAME
);
2024 out
.println("static avmplus::ScriptObject* FASTCALL createInstanceProc(%s*);" % BASE_CLASS_NAME
)
2027 if t
.has_construct_method_override
:
2028 # emit the construct declaration to ensure that construct is defined for this class
2029 out
.println("public:")
2031 out
.println("virtual avmplus::Atom construct(int argc, avmplus::Atom* argv);")
2034 # TEMPORARY: emit a (debug-only) stub to ensure that construct is NOT defined for this class
2035 out
.println("public:")
2037 out
.println("AvmThunk_DEBUG_ONLY( virtual avmplus::Atom construct(int argc, avmplus::Atom* argv); )")
2040 # createInstance() is no longer supported; emit a (debug-only) stub to generate compile errors for any dangling usages
2041 out
.println("private:")
2043 out
.println("AvmThunk_DEBUG_ONLY( virtual void createInstance() { AvmAssert(0); } )")
2046 def emitConstructStubs(self
, out
, t
, sortedSlots
, slotsTypeInfo
, isClassTraits
):
2052 out
.println("/*static*/ %s* FASTCALL %s::createClassClosure(avmplus::VTable* cvtable)" % (BASE_CLASS_NAME
,t
.fqcppname()))
2056 out
.println("cvtable->ivtable->createInstanceProc = %s;" % (t
.createInstanceProcName
));
2057 out
.println("ClassClosure* const cc = new (cvtable->gc(), MMgc::kExact, cvtable->getExtraSize()) %s(cvtable);" % t
.fqcppname())
2059 out
.println("cvtable->ivtable->createInstanceProc = %s;" % (t
.createInstanceProcName
));
2060 out
.println("ClassClosure* const cc = new (cvtable->gc(), cvtable->getExtraSize()) %s(cvtable);" % t
.fqcppname())
2061 out
.println("AvmThunk_DEBUG_ONLY( %s::SlotOffsetsAndAsserts::do%sAsserts(cc->traits(), cc->traits()->itraits); )" % (opts
.nativeIDNS
, t
.cppname()))
2062 out
.println("return cc;")
2066 if t
.has_custom_createInstanceProc
:
2067 out
.println("/*static*/ avmplus::ScriptObject* FASTCALL %s::createInstanceProc(%s* cls)" % (t
.fqcppname(), BASE_CLASS_NAME
));
2070 if t
.has_pre_create_check
:
2071 out
.println("%s::preCreateInstanceCheck(cls);" % (t
.fqcppname()));
2072 if t
.itraits
.is_gc_exact
:
2073 out
.println("return new (cls->gc(), MMgc::kExact, cls->getExtraSize()) %s(cls->ivtable(), cls->prototypePtr());" % (t
.itraits
.fqcppname()))
2075 out
.println("return new (cls->gc(), cls->getExtraSize()) %s(cls->ivtable(), cls->prototypePtr());" % (t
.itraits
.fqcppname()))
2079 if not t
.has_construct_method_override
:
2080 if t
.fqinstancebase_name
!= None:
2081 baseclassname
= t
.fqinstancebase_name
2083 baseclassname
= self
.lookupTraits(t
.base
).fqcppname()
2084 out
.println("AvmThunk_DEBUG_ONLY( avmplus::Atom %s::construct(int argc, avmplus::Atom* argv) { return %s::construct(argc, argv); } )" % (t
.fqcppname(), baseclassname
))
2086 def get_args_info(self
, t
, m
):
2087 argtraits
= self
.argTraits(t
, m
)
2090 for i
in range(0, len(argtraits
)):
2095 argname
= "arg%d" % i
2096 if argt
.is_interface
:
2097 # FIXME: interface arguments just pass in as ScriptObject, for now
2098 arg_typedef
= BASE_INSTANCE_NAME
2099 elif argt
.ctype
== CTYPE_OBJECT
:
2100 arg_typedef
= self
.findNativeBase(argt
)
2102 arg_typedef
= None # unused
2103 arg_typedef
= TYPEMAP_RETTYPE_GCREF
[argt
.ctype
](arg_typedef
)
2104 args
.append((argt
, arg_typedef
, argname
))
2105 if TYPEMAP_TO_ATOM_NEEDS_CORE
[argt
.ctype
]:
2107 return args
,needcore
2109 def shouldEmitConstructObject(self
, t
):
2110 return t
.itraits
!= None and \
2111 t
.construct
!= "none" and \
2112 not t
.is_abstract_base
and \
2113 (not t
.itraits
.has_cpp_name() or not t
.itraits
.fqcppname() in GLUECLASSES_WITHOUT_CONSTRUCT_WRAPPERS
) and \
2114 not t
.itraits
.init
.needRest()
2116 def emitConstructObjectDeclaration(self
, out
, t
, args
):
2117 ret_typedef
= TYPEMAP_RETTYPE_GCREF
[t
.itraits
.ctype
](t
.itraits
.fqcppname())
2118 arglist
= ', '.join(map(lambda (argt
, arg_typedef
, argname
): "%s %s" % (arg_typedef
, argname
), args
[1:]))
2119 out
.println("%s constructObject(%s);" % (ret_typedef
, arglist
))
2121 def emitMethodWrappers(self
, out
, t
):
2122 # For now, only emit a constructObject() wrapper;
2123 # someday, probably emit other C++ -> AS3 call wrappers.
2124 if self
.shouldEmitConstructObject(t
):
2125 out
.println("public:")
2127 args
,needcore
= self
.get_args_info(t
,t
.itraits
.init
)
2128 ctype
= t
.itraits
.ctype
2129 # t.itraits is a pure-AS3 class, so it has no C++ class;
2130 # the most closest native ancestor and use that.
2131 fqcppname
= self
.findNativeBase(t
.itraits
)
2132 ret_typedef
= TYPEMAP_RETTYPE_GCREF
[ctype
](fqcppname
)
2133 arglist
= ', '.join(map(lambda (argt
, arg_typedef
, argname
): "%s %s" % (arg_typedef
, argname
), args
[1:]))
2134 out
.println("REALLY_INLINE %s constructObject(%s)" % (ret_typedef
, arglist
))
2138 # explicitly cast to AvmCore* because it might be an only-forward-declared subclass
2139 out
.println("avmplus::AvmCore* const core = ((AvmCore*)(this->core()));")
2140 arglist
= ', '.join(map(lambda (argt
, arg_typedef
, argname
): TYPEMAP_TO_ATOM
[argt
.ctype
](argname
), args
))
2141 out
.println("avmplus::Atom args[%d] = { %s };" % (len(args
), arglist
))
2142 out
.println("avmplus::Atom const result = this->construct(%d, args);" % (len(args
)-1))
2143 raw_result
= TYPEMAP_FROM_ATOM
[ctype
]("result", fqcppname
)
2144 out
.println("return %s;" % TYPEMAP_TO_GCREF
[ctype
](raw_result
,fqcppname
))
2149 def emitSlotDeclarations(self
, out
, t
, sortedSlots
, slotsTypeInfo
, closingSemi
):
2150 out
.println("private:")
2152 out
.println("friend class %s::SlotOffsetsAndAsserts;" % opts
.nativeIDNS
)
2154 if (len(t
.slots
) > 0):
2155 out
.println("protected:")
2157 for slot
in sortedSlots
:
2158 assert slot
.kind
in (TRAIT_Slot
, TRAIT_Const
)
2159 (slotCType
, slotArgType
, slotRetType
, slotMemberType
) = slotsTypeInfo
[id(slot
)]
2160 name
= to_cname(slot
.name
)
2161 out
.println("REALLY_INLINE %s get_%s() const { return %s.get_%s(); }" % (slotRetType
, name
, t
.slotsInstanceName
, name
));
2162 if ((slot
.kind
== TRAIT_Slot
) or (t
.has_const_setters
)):
2163 out
.println("REALLY_INLINE void set_%s(%s newVal) { %s.set_%s(newVal); }" % (name
, slotArgType
, t
.slotsInstanceName
, name
))
2165 out
.println("private:")
2167 out
.println("%s::%s %s%s" % (opts
.nativeIDNS
, t
.slotsStructName
, t
.slotsInstanceName
,closingSemi
) )
2170 def emitStructDeclarationsForTraits(self
, out
, t
, visitedGlueClasses
, isClassTraits
):
2172 if (t
.fqcppname() in visitedGlueClasses
):
2173 if (len(t
.slots
) == 0):
2175 raise Error('C++ glue classes for AS3 classes that have slots may only be referenced by metadata for one AS3 class: %s(%s)' % (t
.name
, t
.fqcppname()))
2177 visitedGlueClasses
.add(t
.fqcppname())
2178 if (t
.fqcppname() in GLUECLASSES_WITHOUT_SLOTS
):
2181 sortedSlots
,slotsTypeInfo
= self
.sortSlots(t
)
2182 self
.emitDeclareSlotClass(out
, t
, sortedSlots
, slotsTypeInfo
, isClassTraits
)
2184 if not t
.is_synthetic
:
2186 out
.println('#define DECLARE_SLOTS_%s' % t
.cppname())
2188 self
.emitConstructDeclarations(out
, t
, sortedSlots
, slotsTypeInfo
, isClassTraits
)
2189 self
.emitMethodWrappers(out
, t
)
2190 self
.emitSlotDeclarations(out
, t
, sortedSlots
, slotsTypeInfo
, "")
2195 out
.println('//-----------------------------------------------------------')
2198 def emitSyntheticClasses(self
, out
):
2199 out
.println('// NOTE: The following classes are never actually instantiated as such;')
2200 out
.println('// they are provided as a C++ front end onto pure AS3 classes.')
2201 for i
in range(0, len(self
.abc
.classes
)):
2202 t
= self
.abc
.classes
[i
]
2204 isClassTraits
= True
2205 sortedSlots
,slotsTypeInfo
= self
.sortSlots(t
)
2206 out
.println('//-----------------------------------------------------------')
2207 out
.println('// %s' % str(t
.name
))
2208 out
.println('//-----------------------------------------------------------')
2209 out
.println("class %s : public %s" % (t
.cppname(), BASE_CLASS_NAME
))
2211 self
.emitConstructDeclarations(out
, t
, sortedSlots
, slotsTypeInfo
, isClassTraits
)
2212 self
.emitMethodWrappers(out
, t
)
2213 self
.emitSlotDeclarations(out
, t
, sortedSlots
, slotsTypeInfo
, ";")
2214 out
.println("private:")
2216 out
.println("explicit %s(); // unimplemented" % t
.cppname())
2217 out
.println("explicit %s(const %s&); // unimplemented" % (t
.cppname(), t
.cppname()))
2218 out
.println("void operator=(const %s&); // unimplemented" % t
.cppname())
2224 def emitStructStubsForTraits(self
, out
, t
, visitedGlueClasses
, isClassTraits
):
2226 if (t
.fqcppname() in visitedGlueClasses
):
2227 if (len(t
.slots
) == 0):
2229 raise Error('C++ glue classes for AS3 classes that have slots may only be referenced by metadata for one AS3 class: %s(%s)' % (t
.name
, t
.fqcppname()))
2231 visitedGlueClasses
.add(t
.fqcppname())
2232 if (t
.fqcppname() in GLUECLASSES_WITHOUT_SLOTS
):
2235 sortedSlots
,slotsTypeInfo
= self
.sortSlots(t
)
2236 self
.emitConstructStubs(out
, t
, sortedSlots
, slotsTypeInfo
, isClassTraits
)
2238 def printStructAsserts(self
, out
, abc
):
2239 out
.println('class SlotOffsetsAndAsserts')
2241 out
.println('public:')
2243 out
.println('static uint32_t getSlotOffset(Traits* t, int nameId);')
2244 out
.println('enum {')
2246 visitedNativeClasses
= set()
2247 for i
in range(0, len(abc
.classes
)):
2249 if (c
.gen_method_map
):
2250 if (c
.fqcppname() not in visitedNativeClasses
):
2251 visitedNativeClasses
.add(c
.fqcppname())
2252 out
.println('kSlotsOffset%s = %s,' % (c
.cppname(), c
.cpp_offsetof_slots()))
2253 if (c
.itraits
.fqcppname() not in visitedNativeClasses
):
2254 visitedNativeClasses
.add(c
.itraits
.fqcppname())
2255 out
.println('kSlotsOffset%s = %s,' % (c
.itraits
.cppname(), c
.itraits
.cpp_offsetof_slots()))
2256 out
.println('kSlotsOffset_fnord')
2260 out
.println('#ifdef DEBUG')
2261 for i
in range(0, len(abc
.classes
)):
2263 if (c
.gen_method_map
):
2264 out
.println('static void do%sAsserts(Traits* ctraits, Traits* itraits);' % c
.cppname())
2265 out
.println('#endif');
2269 out
.println('#ifdef DEBUG');
2270 for i
in range(0, len(abc
.classes
)):
2272 if (c
.has_cpp_name() and not c
.is_synthetic
):
2273 out
.println('REALLY_INLINE void SlotOffsetsAndAsserts::do%sAsserts(Traits* ctraits, Traits* itraits)' % c
.cppname())
2276 assert (c
.has_cpp_name
)
2277 out
.println('(void)ctraits; (void)itraits;')
2278 self
.printStructAssertsForTraits(out
, c
, True, 'ctraits')
2279 if self
.needsInstanceSlotsStruct(c
):
2280 self
.printStructAssertsForTraits(out
, c
.itraits
, False, 'itraits')
2283 out
.println('#endif // DEBUG')
2285 def printStructAssertsForTraits(self
, out
, t
, isClassTraits
, traitsVarName
):
2286 if (len(t
.slots
) > 0):
2287 out
.println('MMGC_STATIC_ASSERT(offsetof(%s, %s) == kSlotsOffset%s);' % (t
.fqcppname(), t
.slotsInstanceName
, t
.cppname()))
2288 out
.println('MMGC_STATIC_ASSERT(offsetof(%s, %s) <= 0xFFFF);' % (t
.fqcppname(), t
.slotsInstanceName
))
2289 out
.println('MMGC_STATIC_ASSERT(sizeof(%s) <= 0xFFFF);' % (t
.fqcppname()))
2290 for slot
in t
.slots
:
2292 out
.println('AvmAssert(getSlotOffset(%s, %u) == (offsetof(%s, %s) + offsetof(%s, m_%s)));'
2293 % (traitsVarName
, self
.namesDict
[id(slot
.name
)], t
.fqcppname(), t
.slotsInstanceName
, t
.slotsStructName
, to_cname(slot
.name
)))
2295 def argTraits(self
, receiver
, m
):
2296 argtraits
= [ receiver
]
2297 for i
in range(0, len(m
.paramTypes
)):
2298 argtraits
.append(self
.lookupTraits(m
.paramTypes
[i
]))
2301 def findNativeBase(self
, t
):
2302 if t
.has_cpp_name():
2303 return t
.fqcppname()
2305 return self
.findNativeBase(self
.lookupTraits(t
.base
))
2308 def thunkInfo(self
, m
):
2309 ret_traits
= self
.lookupTraits(m
.returnType
)
2310 ret_ctype
= ret_traits
.ctype
2311 if m
.kind
== TRAIT_Setter
:
2312 ret_ctype
= CTYPE_VOID
2313 # for return types of thunks, everything but double maps to Atom
2314 if ret_ctype
!= CTYPE_DOUBLE
:
2315 thunk_ret_ctype
= CTYPE_ATOM
2317 thunk_ret_ctype
= CTYPE_DOUBLE
2318 decl
= "%s %s_thunk(MethodEnv* env, uint32_t argc, Atom* argv)" % (TYPEMAP_RETTYPE
[thunk_ret_ctype
], m
.native_id_name
)
2319 return ret_traits
,ret_ctype
,thunk_ret_ctype
,decl
2321 def emitThunkProto(self
, out
, receiver
, m
):
2322 ret_traits
,ret_ctype
,thunk_ret_ctype
,decl
= self
.thunkInfo(m
)
2323 out
.println('extern ' + decl
+ ";");
2325 def emitThunkBody(self
, out
, receiver
, m
):
2326 ret_traits
,ret_ctype
,thunk_ret_ctype
,decl
= self
.thunkInfo(m
)
2328 unbox_receiver
= self
.calc_unbox_this(m
)
2335 out
.println('_nvprof("%s", 1);' % name
)
2337 param_count
= len(m
.paramTypes
);
2338 optional_count
= m
.optional_count
;
2340 argtraits
= self
.argTraits(receiver
, m
)
2343 out
.println("enum {");
2345 for i
in range(0, len(argtraits
)):
2347 out
.println("argoff0 = 0");
2349 out
.println(", argoff%d = argoff%d + %s" % (i
, i
-1, argszprev
));
2350 argszprev
= "AvmThunkArgSize_%s" % TYPEMAP_ARGTYPE_SUFFIX
[argtraits
[i
].ctype
];
2355 out
.println("const uint32_t argoffV = argoff"+str(len(argtraits
)-1)+" + "+argszprev
+";");
2359 arg0_typedef
= argtraits
[0].cpp_argument_name()
2360 assert(argtraits
[0].ctype
in [CTYPE_OBJECT
,CTYPE_STRING
,CTYPE_NAMESPACE
])
2362 val
= "AvmThunkUnbox_AvmAtomReceiver("+arg0_typedef
+", argv[argoff0])";
2364 val
= "AvmThunkUnbox_AvmReceiver("+arg0_typedef
+", argv[argoff0])";
2365 args
.append((val
, arg0_typedef
))
2367 for i
in range(1, len(argtraits
)):
2368 arg_ctype
= argtraits
[i
].ctype
2369 arg_typedef
= argtraits
[i
].cpp_unboxing_argument_name()
2370 val
= "AvmThunkUnbox_%s(%s, argv[argoff%d])" % (TYPEMAP_ARGTYPE_SUFFIX
[arg_ctype
], arg_typedef
, i
)
2371 if arg_ctype
== CTYPE_OBJECT
:
2372 unboxname
= self
.findNativeBase(argtraits
[i
])
2373 if unboxname
!= None:
2374 val
= "(%s*)%s" % (unboxname
, val
)
2375 # argtraits includes receiver at 0, optionalValues does not
2376 if i
> param_count
- optional_count
:
2377 dct
,defval
,defvalraw
= self
.abc
.default_ctype_and_value(m
.optionalValues
[i
-1]);
2378 if dct
!= arg_ctype
:
2379 defval
= "AvmThunkCoerce_%s_%s(%s)" % (TYPEMAP_ARGTYPE_SUFFIX
[dct
], TYPEMAP_ARGTYPE_SUFFIX
[arg_ctype
], defval
)
2380 val
= "(argc < "+str(i
)+" ? "+defval
+" : "+val
+")";
2381 if arg_ctype
== CTYPE_OBJECT
:
2382 coercename
= self
.findNativeBase(argtraits
[i
])
2383 if coercename
!= None:
2384 val
= "(%s*)%s" % (coercename
, val
)
2385 args
.append((val
, arg_typedef
))
2388 args
.append(("(argc <= "+str(param_count
)+" ? NULL : argv + argoffV)", "Atom*"))
2389 args
.append(("(argc <= "+str(param_count
)+" ? 0 : argc - "+str(param_count
)+")", "uint32_t"))
2391 if not m
.hasOptional() and not m
.needRest():
2392 out
.println("(void)argc;");
2394 out
.println("(void)env;") # avoid "unreferenced formal parameter" in non-debugger builds
2395 if m
.receiver
== None or not m
.receiver
.has_cpp_name():
2396 rec_type
= BASE_INSTANCE_NAME
+"*"
2398 rec_type
= m
.receiver
.cpp_argument_name()
2399 out
.println("%s const obj = %s;" % (rec_type
, args
[0][0]))
2401 if ret_ctype
!= CTYPE_VOID
:
2402 out
.prnt("%s const ret = " % ret_traits
.cpp_return_name())
2404 if m
.receiver
== None:
2405 out
.prnt("%s(obj" % m
.native_method_name
)
2408 if m
.receiver
.method_map_name
!= m
.receiver
.fqcppname():
2409 native_method_name
= m
.receiver
.method_map_name
+ "::" + m
.native_method_name
2411 native_method_name
= m
.native_method_name
2412 out
.prnt("obj->%s(" % native_method_name
)
2418 for i
in range(1, len(args
)):
2421 out
.println("%s" % args
[i
][0]);
2426 if ret_ctype
!= CTYPE_VOID
:
2427 ret_result
= TYPEMAP_THUNKRETTYPE
[ret_ctype
] % "ret";
2429 ret_result
= "undefinedAtom";
2430 out
.println("return %s;" % ret_result
)
2434 # inefficient, but doesn't really matter
2435 def find_override_base(self
, mi
):
2436 if mi
.override
and mi
.receiver
.base
!= None:
2437 bt
= self
.lookupTraits(mi
.receiver
.base
)
2438 for j
in range(0, len(bt
.tmethods
)):
2439 bmi
= bt
.tmethods
[j
]
2440 if bmi
.name
.name
== mi
.name
.name
and bmi
.name
.ns
== mi
.name
.ns
and bmi
!= mi
:
2441 #print "OVER", str(mi.name), str(mi.receiver)
2442 #print "BASE", str(bmi.name), str(bmi.receiver)
2446 def calc_unbox_this(self
, mi
):
2447 if mi
.unbox_this
< 0:
2448 bt
,bmi
= self
.find_override_base(mi
)
2450 mi
.unbox_this
= 0 # no need to unbox
2451 elif bmi
.unbox_this
> 0:
2452 mi
.unbox_this
= 1 # unbox_this is sticky, down the inheritance tree
2453 elif len(bmi
.paramTypes
) > 0:
2454 param0
= self
.lookupTraits(bmi
.paramTypes
[0])
2455 if mi
.receiver
.ctype
in [CTYPE_OBJECT
,CTYPE_STRING
,CTYPE_NAMESPACE
] and param0
.ctype
== CTYPE_ATOM
:
2456 mi
.unbox_this
= 1 # unbox_this is sticky, down the inheritance tree
2457 return mi
.unbox_this
> 0
2459 def lookupTraits(self
, name
):
2461 if self
.lookup_traits
== None:
2462 self
.lookup_traits
= {}
2463 self
.lookup_traits
["*"] = NULL
2464 self
.lookup_traits
["void"] = UNDEFINED
2467 if self
.lookup_traits
.has_key(str(t
)):
2468 raise Error("duplicate name found: " + str(t
))
2469 self
.lookup_traits
[str(t
)] = t
2471 if self
.lookup_traits
.has_key(str(t
)):
2472 raise Error("duplicate name found: " + str(t
))
2473 self
.lookup_traits
[str(t
)] = t
2474 for t
in a
.instances
:
2475 if self
.lookup_traits
.has_key(str(t
)):
2476 raise Error("duplicate name found: " + str(t
))
2477 self
.lookup_traits
[str(t
)] = t
2478 if not self
.lookup_traits
.has_key(name
):
2479 raise Error("name not found: " + name
)
2480 return self
.lookup_traits
[name
]
2482 def gatherThunk(self
, receiver
, m
):
2483 if m
.native_id_name
== None:
2484 raise Error("name not specified for native method " + str(m
.name
))
2485 self
.all_thunks
.append((receiver
, m
))
2487 def processClass(self
, b
):
2489 self
.processTraits(c
)
2490 self
.processTraits(c
.itraits
)
2492 def processMethod(self
, receiver
, m
):
2494 self
.gatherThunk(receiver
, m
)
2496 def processTraits(self
, s
):
2498 if s
.init
.isNative():
2499 raise Error("native constructors are not allowed: " + str(s
))
2500 self
.processMethod(s
, s
.init
)
2501 for i
in range(0, len(s
.members
)):
2502 if s
.members
[i
].kind
in [TRAIT_Method
,TRAIT_Getter
,TRAIT_Setter
]:
2503 self
.processMethod(s
, s
.members
[i
])
2504 elif s
.members
[i
].kind
in [TRAIT_Class
]:
2505 self
.processClass(s
.members
[i
]);
2507 ngen
= AbcThunkGen();
2517 abcScriptName
= os
.path
.splitext(os
.path
.split(file)[1])[0]
2518 #print "read %s" % abcScriptName
2519 abcGenFor
= Abc(data
, abcScriptName
)
2520 ngen
.addAbc(abcGenFor
)
2521 abcGenName
= os
.path
.splitext(file)[0]
2527 hfile
= open(abcGenName
+".h","w")
2528 clsfile
= open(abcGenName
+"-classes.hh","w")
2529 cppfile
= open(abcGenName
+".cpp","w")
2530 h
= IndentingPrintWriter(hfile
)
2531 cls
= IndentingPrintWriter(clsfile
)
2532 c
= IndentingPrintWriter(cppfile
)
2533 ngen
.emit(abcGenFor
, abcScriptName
, h
, cls
, c
);
2534 except Exception, e
:
2535 sys
.stderr
.write("ERROR: "+str(e
)+"\n")