| | We
have dealt with the complete life cycle of a full-fledged retail SDK comprised
from (among other things) C and C++ compilers developed from scratch: design,
implementation, and support. The said compilers were optimizing (multiple-pass)
and re-targetable: they had back-ends for the Hitachi H8S and Motorola 68k family
of CPUs, as well as Intel x86. Own C/C++ compilers developed
from scratchThese compilers were not modifications of GNU C/C++,
or any other compiler, but completely new designs. The need for these compilers
arose from the necessity to create a functionally rich system for a very limited
platform based on Hitachi H8S 32-bit processor. The amount of memory available
to applications was a mere 128k! This drove the decision to build compiler(s)
with bytecode back-end, allowing us to generate bytecode four (!) times
as small as native code. Other system highlights: Optimizing, multiple-pass
compilers - Re-targetable back-end, ultimately implemented for Intel x86,
Motorola 68k (Palm), Hitachi H8S, along with the original bytecode generator
- Unique
ability to switch between generating bytecode and native code with #pragma's
- Register
(vs. stack) bytecode interpreter model, allowing for very fast bytecode execution
- Bytecode interpreter as small as 400 bytes (yes, bytes, not kilobytes
- Optimizing assembler (see below)
 | Even
C compiler had "object extensions" making it simple, reliable, and efficient to
implement features like in-game objects. C++ compiler has had implementations
of almost all modern features (including inheritance, strong type system, etc.),
except exceptions and templates. | The package
had its own C pre-processor, linker, and... optimizing assembler. The assembler
would "profile" every module and: - Collect statistics on the most frequently
used bytecode instructions, providing information necessary to prioritize which
bytecodes should be the most optimized
- Collect statistics on most frequent
bytecode pairs not separated by a label and therefore providing hints as
to what new bytecode instructions – functional equivalents of bytecode pairs –
to introduce
- Replace bytecode pairs having single-bytecode equivalents
with those equivalents, thus performing both size and execution speed optimization
Extendable scripting languages
tailored for specific applicationsWith modern software, power and flexibility
is often synonymous to scripting. Just think about Microsoft's VBA, Autodesk MAX
script, and ActionScript of Adobe Flash. We can help you unleash that power
for your applications. Furthermore, we can also tailor our generic script
engine to your applications' specific needs, meaning: - Introduction of
application-specific data types (e.g. implement a particular type of image, or
a sound, as base data type)
- Introduction of application-specific methods,
procedures, or even operators
- Introduction of application-specific interfaces
within interpreter's sandbox
Industrial-strength
resource managementThe term "industrial-strength" applied to "resource
management" in this particular case means that: - Resource management
is efficient. For instance, by default, assignment of a variable of type 'image'
to another variable of same type would not lead to data copying; instead, just
the reference count will be incremented
- Resource management is rubust: destruction
(e.g. going out of scope) of the last variable/reference to a resource would deallocate
that resource ("garbage collection")
- Resource management is flexible: almost
any type can be converted to almost any other type whenever necessary
- Resource
management is extendable: for every script data type there is a C/C++ equivalent;
script language can be extended with native procedures accepting and returning
such data types
Java machines
(KVM) and toolsOur experience is not limited to the development of C/C++
compilers and interpreters.
| We have had experience with custom Java machines development (KVMs),
and are familiar with Sun's certification process. Also, we have experience
with tools facilitating Java to C/C++ porting (e.g. semi-automated code translation).
| We have developed other related tools, like Java
class decompilers and Java preprocessors. The latter comes in handy on projects
requiring extra flexibility (conditional preprocessing) or efficiency (compile-time
expression folding, etc.) Optimization techniquesKnowing
exactly how compilers and interpreters work helps us understand how to write optimum
code, both in size and speed. However, sometimes it's necessary to bring in the
heavy artillery:  | In
this case, the "heavy artillery" is, of course, Intel's VTune — the profiler that
can help squeeze every last cycle out of one's application. A brief account
of how VTune helped us optimize POVPro application and make it 5% to 50% faster
than its "official" predecessor (POV-Ray, the photorealistic ray tracer), can be read
here. | PortabilityWhatever we build,
we build it with portability in mind. A good example is our SDKs: they run on
Windows and Linux, and their C/C++ compilers have back-ends for Intel, Motorola,
and Hitachi CPUs. To achieve such level of portability, we: - Explicitly
subdivide the code into platform-agnostic and platform-dependent parts
- Do
not use compiler-specific features, and stick to ISO standards
- Implement I/O
in endianness-agnostic way (e.g. read words byte by byte, so that is works on
both LE and BE systems)
- Try not to use even standard language features not
found in other languages; for instance, we try to only use C++ templates to implement
generic containers and such — this way, we make sure C++ code is quite portable
to even Java
- ... and so on, and so forth
| |