1 ##########################################################################
3 # Copyright 2008-2010 VMware, Inc.
6 # Permission is hereby granted, free of charge, to any person obtaining a copy
7 # of this software and associated documentation files (the "Software"), to deal
8 # in the Software without restriction, including without limitation the rights
9 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 # copies of the Software, and to permit persons to whom the Software is
11 # furnished to do so, subject to the following conditions:
13 # The above copyright notice and this permission notice shall be included in
14 # all copies or substantial portions of the Software.
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 ##########################################################################/
26 """Common trace code generation."""
32 sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
35 import specs.stdapi as stdapi
38 def getWrapperInterfaceName(interface):
39 return "Wrap" + interface.expr
42 class ComplexValueSerializer(stdapi.OnceVisitor):
43 '''Type visitors which generates serialization functions for
46 Simple types are serialized inline.
49 def __init__(self, serializer):
50 stdapi.OnceVisitor.__init__(self)
51 self.serializer = serializer
53 def visitVoid(self, literal):
56 def visitLiteral(self, literal):
59 def visitString(self, string):
62 def visitConst(self, const):
63 self.visit(const.type)
65 def visitStruct(self, struct):
66 print 'static const char * _struct%s_members[%u] = {' % (struct.tag, len(struct.members))
67 for type, name, in struct.members:
68 print ' "%s",' % (name,)
70 print 'static const trace::StructSig _struct%s_sig = {' % (struct.tag,)
71 print ' %u, "%s", %u, _struct%s_members' % (struct.id, struct.name, len(struct.members), struct.tag)
75 def visitArray(self, array):
76 self.visit(array.type)
78 def visitBlob(self, array):
81 def visitEnum(self, enum):
82 print 'static const trace::EnumValue _enum%s_values[] = {' % (enum.tag)
83 for value in enum.values:
84 print ' {"%s", %s},' % (value, value)
87 print 'static const trace::EnumSig _enum%s_sig = {' % (enum.tag)
88 print ' %u, %u, _enum%s_values' % (enum.id, len(enum.values), enum.tag)
92 def visitBitmask(self, bitmask):
93 print 'static const trace::BitmaskFlag _bitmask%s_flags[] = {' % (bitmask.tag)
94 for value in bitmask.values:
95 print ' {"%s", %s},' % (value, value)
98 print 'static const trace::BitmaskSig _bitmask%s_sig = {' % (bitmask.tag)
99 print ' %u, %u, _bitmask%s_flags' % (bitmask.id, len(bitmask.values), bitmask.tag)
103 def visitPointer(self, pointer):
104 self.visit(pointer.type)
106 def visitIntPointer(self, pointer):
109 def visitObjPointer(self, pointer):
110 self.visit(pointer.type)
112 def visitLinearPointer(self, pointer):
113 self.visit(pointer.type)
115 def visitHandle(self, handle):
116 self.visit(handle.type)
118 def visitReference(self, reference):
119 self.visit(reference.type)
121 def visitAlias(self, alias):
122 self.visit(alias.type)
124 def visitOpaque(self, opaque):
127 def visitInterface(self, interface):
130 def visitPolymorphic(self, polymorphic):
131 if not polymorphic.contextLess:
133 print 'static void _write__%s(int selector, const %s & value) {' % (polymorphic.tag, polymorphic.expr)
134 print ' switch (selector) {'
135 for cases, type in polymorphic.iterSwitch():
138 self.serializer.visit(type, 'static_cast<%s>(value)' % (type,))
145 class ValueSerializer(stdapi.Visitor):
146 '''Visitor which generates code to serialize any type.
148 Simple types are serialized inline here, whereas the serialization of
149 complex types is dispatched to the serialization functions generated by
150 ComplexValueSerializer visitor above.
154 #stdapi.Visitor.__init__(self)
158 def expand(self, expr):
159 # Expand a C expression, replacing certain variables
162 variables['self'] = self.instances[-1]
166 variables['i'] = self.indices[-1]
169 expandedExpr = expr.format(**variables)
170 if expandedExpr != expr:
171 sys.stderr.write(" %r -> %r\n" % (expr, expandedExpr))
174 def visitLiteral(self, literal, instance):
175 print ' trace::localWriter.write%s(%s);' % (literal.kind, instance)
177 def visitString(self, string, instance):
179 cast = 'const char *'
182 cast = 'const wchar_t *'
184 if cast != string.expr:
185 # reinterpret_cast is necessary for GLubyte * <=> char *
186 instance = 'reinterpret_cast<%s>(%s)' % (cast, instance)
187 if string.length is not None:
188 length = ', %s' % string.length
191 print ' trace::localWriter.write%s(%s%s);' % (suffix, instance, length)
193 def visitConst(self, const, instance):
194 self.visit(const.type, instance)
196 def visitStruct(self, struct, instance):
197 print ' trace::localWriter.beginStruct(&_struct%s_sig);' % (struct.tag,)
198 self.instances.append(instance)
200 for type, name in struct.members:
201 self.visit(type, '(%s).%s' % (instance, name,))
204 print ' trace::localWriter.endStruct();'
206 def visitArray(self, array, instance):
207 length = '_c' + array.type.tag
208 index = '_i' + array.type.tag
209 print ' if (%s) {' % instance
210 print ' size_t %s = %s > 0 ? %s : 0;' % (length, array.length, array.length)
211 print ' trace::localWriter.beginArray(%s);' % length
212 print ' for (size_t %s = 0; %s < %s; ++%s) {' % (index, index, length, index)
213 print ' trace::localWriter.beginElement();'
214 self.indices.append(index)
216 self.visit(array.type, '(%s)[%s]' % (instance, index))
219 print ' trace::localWriter.endElement();'
221 print ' trace::localWriter.endArray();'
223 print ' trace::localWriter.writeNull();'
226 def visitBlob(self, blob, instance):
227 print ' trace::localWriter.writeBlob(%s, %s);' % (instance, self.expand(blob.size))
229 def visitEnum(self, enum, instance):
230 print ' trace::localWriter.writeEnum(&_enum%s_sig, %s);' % (enum.tag, instance)
232 def visitBitmask(self, bitmask, instance):
233 print ' trace::localWriter.writeBitmask(&_bitmask%s_sig, %s);' % (bitmask.tag, instance)
235 def visitPointer(self, pointer, instance):
236 print ' if (%s) {' % instance
237 print ' trace::localWriter.beginArray(1);'
238 print ' trace::localWriter.beginElement();'
239 self.visit(pointer.type, "*" + instance)
240 print ' trace::localWriter.endElement();'
241 print ' trace::localWriter.endArray();'
243 print ' trace::localWriter.writeNull();'
246 def visitIntPointer(self, pointer, instance):
247 print ' trace::localWriter.writePointer((uintptr_t)%s);' % instance
249 def visitObjPointer(self, pointer, instance):
250 print ' trace::localWriter.writePointer((uintptr_t)%s);' % instance
252 def visitLinearPointer(self, pointer, instance):
253 print ' trace::localWriter.writePointer((uintptr_t)%s);' % instance
255 def visitReference(self, reference, instance):
256 self.visit(reference.type, instance)
258 def visitHandle(self, handle, instance):
259 self.visit(handle.type, instance)
261 def visitAlias(self, alias, instance):
262 self.visit(alias.type, instance)
264 def visitOpaque(self, opaque, instance):
265 print ' trace::localWriter.writePointer((uintptr_t)%s);' % instance
267 def visitInterface(self, interface, instance):
270 def visitPolymorphic(self, polymorphic, instance):
271 if polymorphic.contextLess:
272 print ' _write__%s(%s, %s);' % (polymorphic.tag, polymorphic.switchExpr, instance)
274 print ' switch (%s) {' % polymorphic.switchExpr
275 for cases, type in polymorphic.iterSwitch():
278 self.visit(type, 'static_cast<%s>(%s)' % (type, instance))
283 class WrapDecider(stdapi.Traverser):
284 '''Type visitor which will decide wheter this type will need wrapping or not.
286 For complex types (arrays, structures), we need to know this before hand.
290 self.needsWrapping = False
292 def visitLinearPointer(self, void):
295 def visitInterface(self, interface):
296 self.needsWrapping = True
299 class ValueWrapper(stdapi.Traverser):
300 '''Type visitor which will generate the code to wrap an instance.
302 Wrapping is necessary mostly for interfaces, however interface pointers can
303 appear anywhere inside complex types.
306 def visitStruct(self, struct, instance):
307 for type, name in struct.members:
308 self.visit(type, "(%s).%s" % (instance, name))
310 def visitArray(self, array, instance):
311 print " if (%s) {" % instance
312 print " for (size_t _i = 0, _s = %s; _i < _s; ++_i) {" % array.length
313 self.visit(array.type, instance + "[_i]")
317 def visitPointer(self, pointer, instance):
318 print " if (%s) {" % instance
319 self.visit(pointer.type, "*" + instance)
322 def visitObjPointer(self, pointer, instance):
323 elem_type = pointer.type.mutable()
324 if isinstance(elem_type, stdapi.Interface):
325 self.visitInterfacePointer(elem_type, instance)
327 self.visitPointer(pointer, instance)
329 def visitInterface(self, interface, instance):
330 raise NotImplementedError
332 def visitInterfacePointer(self, interface, instance):
333 print " if (%s) {" % instance
334 print " %s = new %s(%s);" % (instance, getWrapperInterfaceName(interface), instance)
337 def visitPolymorphic(self, type, instance):
338 # XXX: There might be polymorphic values that need wrapping in the future
339 raise NotImplementedError
342 class ValueUnwrapper(ValueWrapper):
343 '''Reverse of ValueWrapper.'''
347 def visitArray(self, array, instance):
348 if self.allocated or isinstance(instance, stdapi.Interface):
349 return ValueWrapper.visitArray(self, array, instance)
350 elem_type = array.type.mutable()
351 print " if (%s && %s) {" % (instance, array.length)
352 print " %s * _t = static_cast<%s *>(alloca(%s * sizeof *_t));" % (elem_type, elem_type, array.length)
353 print " for (size_t _i = 0, _s = %s; _i < _s; ++_i) {" % array.length
354 print " _t[_i] = %s[_i];" % instance
355 self.allocated = True
356 self.visit(array.type, "_t[_i]")
358 print " %s = _t;" % instance
361 def visitInterfacePointer(self, interface, instance):
362 print r' if (%s) {' % instance
363 print r' const %s *pWrapper = static_cast<const %s*>(%s);' % (getWrapperInterfaceName(interface), getWrapperInterfaceName(interface), instance)
364 print r' if (pWrapper && pWrapper->m_dwMagic == 0xd8365d6c) {'
365 print r' %s = pWrapper->m_pInstance;' % (instance,)
367 print r' os::log("apitrace: warning: %%s: unexpected %%s pointer\n", __FUNCTION__, "%s");' % interface.name
373 '''Base class to orchestrate the code generation of API tracing.'''
378 def serializerFactory(self):
379 '''Create a serializer.
381 Can be overriden by derived classes to inject their own serialzer.
384 return ValueSerializer()
386 def traceApi(self, api):
392 for header in api.headers:
396 # Generate the serializer functions
397 types = api.getAllTypes()
398 visitor = ComplexValueSerializer(self.serializerFactory())
399 map(visitor.visit, types)
403 self.traceInterfaces(api)
406 self.interface = None
408 map(self.traceFunctionDecl, api.functions)
409 map(self.traceFunctionImpl, api.functions)
414 def header(self, api):
415 print '#ifdef _WIN32'
416 print '# include <malloc.h> // alloca'
417 print '# ifndef alloca'
418 print '# define alloca _alloca'
421 print '# include <alloca.h> // alloca'
424 print '#include "trace.hpp"'
427 def footer(self, api):
430 def traceFunctionDecl(self, function):
431 # Per-function declarations
433 if not function.internal:
435 print 'static const char * _%s_args[%u] = {%s};' % (function.name, len(function.args), ', '.join(['"%s"' % arg.name for arg in function.args]))
437 print 'static const char ** _%s_args = NULL;' % (function.name,)
438 print 'static const trace::FunctionSig _%s_sig = {%u, "%s", %u, _%s_args};' % (function.name, function.id, function.name, len(function.args), function.name)
441 def isFunctionPublic(self, function):
444 def traceFunctionImpl(self, function):
445 if self.isFunctionPublic(function):
446 print 'extern "C" PUBLIC'
448 print 'extern "C" PRIVATE'
449 print function.prototype() + ' {'
450 if function.type is not stdapi.Void:
451 print ' %s _result;' % function.type
453 # No-op if tracing is disabled
454 print ' if (!trace::isTracingEnabled()) {'
455 Tracer.invokeFunction(self, function)
456 if function.type is not stdapi.Void:
457 print ' return _result;'
462 self.traceFunctionImplBody(function)
463 if function.type is not stdapi.Void:
464 print ' return _result;'
468 def traceFunctionImplBody(self, function):
469 if not function.internal:
470 print ' unsigned _call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
471 for arg in function.args:
473 self.unwrapArg(function, arg)
474 self.serializeArg(function, arg)
475 print ' trace::localWriter.endEnter();'
476 self.invokeFunction(function)
477 if not function.internal:
478 print ' trace::localWriter.beginLeave(_call);'
479 for arg in function.args:
481 self.serializeArg(function, arg)
482 self.wrapArg(function, arg)
483 if function.type is not stdapi.Void:
484 self.serializeRet(function, "_result")
485 print ' trace::localWriter.endLeave();'
486 if function.type is not stdapi.Void:
487 self.wrapRet(function, "_result")
489 def invokeFunction(self, function, prefix='_', suffix=''):
490 if function.type is stdapi.Void:
493 result = '_result = '
494 dispatch = prefix + function.name + suffix
495 print ' %s%s(%s);' % (result, dispatch, ', '.join([str(arg.name) for arg in function.args]))
497 def serializeArg(self, function, arg):
498 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
499 self.serializeArgValue(function, arg)
500 print ' trace::localWriter.endArg();'
502 def serializeArgValue(self, function, arg):
503 self.serializeValue(arg.type, arg.name)
505 def wrapArg(self, function, arg):
506 assert not isinstance(arg.type, stdapi.ObjPointer)
508 from specs.winapi import REFIID
510 for other_arg in function.args:
511 if not other_arg.output and other_arg.type is REFIID:
513 if riid is not None \
514 and isinstance(arg.type, stdapi.Pointer) \
515 and isinstance(arg.type.type, stdapi.ObjPointer):
516 self.wrapIid(function, riid, arg)
519 self.wrapValue(arg.type, arg.name)
521 def unwrapArg(self, function, arg):
522 self.unwrapValue(arg.type, arg.name)
524 def serializeRet(self, function, instance):
525 print ' trace::localWriter.beginReturn();'
526 self.serializeValue(function.type, instance)
527 print ' trace::localWriter.endReturn();'
529 def serializeValue(self, type, instance):
530 serializer = self.serializerFactory()
531 serializer.visit(type, instance)
533 def wrapRet(self, function, instance):
534 self.wrapValue(function.type, instance)
536 def unwrapRet(self, function, instance):
537 self.unwrapValue(function.type, instance)
539 def needsWrapping(self, type):
540 visitor = WrapDecider()
542 return visitor.needsWrapping
544 def wrapValue(self, type, instance):
545 if self.needsWrapping(type):
546 visitor = ValueWrapper()
547 visitor.visit(type, instance)
549 def unwrapValue(self, type, instance):
550 if self.needsWrapping(type):
551 visitor = ValueUnwrapper()
552 visitor.visit(type, instance)
554 def traceInterfaces(self, api):
555 interfaces = api.getAllInterfaces()
558 map(self.declareWrapperInterface, interfaces)
559 self.implementIidWrapper(api)
560 map(self.implementWrapperInterface, interfaces)
563 def declareWrapperInterface(self, interface):
564 print "class %s : public %s " % (getWrapperInterfaceName(interface), interface.name)
567 print " %s(%s * pInstance);" % (getWrapperInterfaceName(interface), interface.name)
568 print " virtual ~%s();" % getWrapperInterfaceName(interface)
570 for method in interface.iterMethods():
571 print " " + method.prototype() + ";"
574 for type, name, value in self.enumWrapperInterfaceVariables(interface):
575 print ' %s %s;' % (type, name)
579 def enumWrapperInterfaceVariables(self, interface):
581 ("DWORD", "m_dwMagic", "0xd8365d6c"),
582 ("%s *" % interface.name, "m_pInstance", "pInstance"),
585 def implementWrapperInterface(self, interface):
586 self.interface = interface
588 print '%s::%s(%s * pInstance) {' % (getWrapperInterfaceName(interface), getWrapperInterfaceName(interface), interface.name)
589 for type, name, value in self.enumWrapperInterfaceVariables(interface):
590 print ' %s = %s;' % (name, value)
593 print '%s::~%s() {' % (getWrapperInterfaceName(interface), getWrapperInterfaceName(interface))
597 for base, method in interface.iterBaseMethods():
599 self.implementWrapperInterfaceMethod(interface, base, method)
603 def implementWrapperInterfaceMethod(self, interface, base, method):
604 print method.prototype(getWrapperInterfaceName(interface) + '::' + method.name) + ' {'
605 if method.type is not stdapi.Void:
606 print ' %s _result;' % method.type
608 self.implementWrapperInterfaceMethodBody(interface, base, method)
610 if method.type is not stdapi.Void:
611 print ' return _result;'
615 def implementWrapperInterfaceMethodBody(self, interface, base, method):
616 assert not method.internal
618 print ' static const char * _args[%u] = {%s};' % (len(method.args) + 1, ', '.join(['"this"'] + ['"%s"' % arg.name for arg in method.args]))
619 print ' static const trace::FunctionSig _sig = {%u, "%s", %u, _args};' % (method.id, interface.name + '::' + method.name, len(method.args) + 1)
621 print ' %s *_this = static_cast<%s *>(m_pInstance);' % (base, base)
623 print ' unsigned _call = trace::localWriter.beginEnter(&_sig);'
624 print ' trace::localWriter.beginArg(0);'
625 print ' trace::localWriter.writePointer((uintptr_t)m_pInstance);'
626 print ' trace::localWriter.endArg();'
627 for arg in method.args:
629 self.unwrapArg(method, arg)
630 self.serializeArg(method, arg)
631 print ' trace::localWriter.endEnter();'
633 self.invokeMethod(interface, base, method)
635 print ' trace::localWriter.beginLeave(_call);'
636 for arg in method.args:
638 self.serializeArg(method, arg)
639 self.wrapArg(method, arg)
641 if method.type is not stdapi.Void:
642 self.serializeRet(method, '_result')
643 print ' trace::localWriter.endLeave();'
644 if method.type is not stdapi.Void:
645 self.wrapRet(method, '_result')
647 if method.name == 'Release':
648 assert method.type is not stdapi.Void
649 print ' if (!_result)'
650 print ' delete this;'
652 def implementIidWrapper(self, api):
654 print r'warnIID(const char *functionName, REFIID riid, const char *reason) {'
655 print r' os::log("apitrace: warning: %s: %s IID {0x%08lX,0x%04X,0x%04X,{0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X}}\n",'
656 print r' functionName, reason,'
657 print r' riid.Data1, riid.Data2, riid.Data3,'
658 print r' riid.Data4[0], riid.Data4[1], riid.Data4[2], riid.Data4[3], riid.Data4[4], riid.Data4[5], riid.Data4[6], riid.Data4[7]);'
662 print r'wrapIID(const char *functionName, REFIID riid, void * * ppvObj) {'
663 print r' if (!ppvObj || !*ppvObj) {'
667 for iface in api.getAllInterfaces():
668 print r' %sif (riid == IID_%s) {' % (else_, iface.name)
669 print r' *ppvObj = new Wrap%s((%s *) *ppvObj);' % (iface.name, iface.name)
672 print r' %s{' % else_
673 print r' warnIID(functionName, riid, "unknown");'
678 def wrapIid(self, function, riid, out):
679 # Cast output arg to `void **` if necessary
681 obj_type = out.type.type.type
682 if not obj_type is stdapi.Void:
683 assert isinstance(obj_type, stdapi.Interface)
684 out_name = 'reinterpret_cast<void * *>(%s)' % out_name
686 print r' if (%s && *%s) {' % (out.name, out.name)
687 functionName = function.name
689 if self.interface is not None:
690 functionName = self.interface.name + '::' + functionName
691 print r' if (*%s == m_pInstance &&' % (out_name,)
692 print r' (%s)) {' % ' || '.join('%s == IID_%s' % (riid.name, iface.name) for iface in self.interface.iterBases())
693 print r' *%s = this;' % (out_name,)
696 print r' %s{' % else_
697 print r' wrapIID("%s", %s, %s);' % (functionName, riid.name, out_name)
701 def invokeMethod(self, interface, base, method):
702 if method.type is stdapi.Void:
705 result = '_result = '
706 print ' %s_this->%s(%s);' % (result, method.name, ', '.join([str(arg.name) for arg in method.args]))
708 def emit_memcpy(self, dest, src, length):
709 print ' unsigned _call = trace::localWriter.beginEnter(&trace::memcpy_sig);'
710 print ' trace::localWriter.beginArg(0);'
711 print ' trace::localWriter.writePointer((uintptr_t)%s);' % dest
712 print ' trace::localWriter.endArg();'
713 print ' trace::localWriter.beginArg(1);'
714 print ' trace::localWriter.writeBlob(%s, %s);' % (src, length)
715 print ' trace::localWriter.endArg();'
716 print ' trace::localWriter.beginArg(2);'
717 print ' trace::localWriter.writeUInt(%s);' % length
718 print ' trace::localWriter.endArg();'
719 print ' trace::localWriter.endEnter();'
720 print ' trace::localWriter.beginLeave(_call);'
721 print ' trace::localWriter.endLeave();'
723 def fake_call(self, function, args):
724 print ' unsigned _fake_call = trace::localWriter.beginEnter(&_%s_sig);' % (function.name,)
725 for arg, instance in zip(function.args, args):
726 assert not arg.output
727 print ' trace::localWriter.beginArg(%u);' % (arg.index,)
728 self.serializeValue(arg.type, instance)
729 print ' trace::localWriter.endArg();'
730 print ' trace::localWriter.endEnter();'
731 print ' trace::localWriter.beginLeave(_fake_call);'
732 print ' trace::localWriter.endLeave();'