154 research outputs found
Speculative Staging for Interpreter Optimization
Interpreters have a bad reputation for having lower performance than
just-in-time compilers. We present a new way of building high performance
interpreters that is particularly effective for executing dynamically typed
programming languages. The key idea is to combine speculative staging of
optimized interpreter instructions with a novel technique of incrementally and
iteratively concerting them at run-time.
This paper introduces the concepts behind deriving optimized instructions
from existing interpreter instructions---incrementally peeling off layers of
complexity. When compiling the interpreter, these optimized derivatives will be
compiled along with the original interpreter instructions. Therefore, our
technique is portable by construction since it leverages the existing
compiler's backend. At run-time we use instruction substitution from the
interpreter's original and expensive instructions to optimized instruction
derivatives to speed up execution.
Our technique unites high performance with the simplicity and portability of
interpreters---we report that our optimization makes the CPython interpreter up
to more than four times faster, where our interpreter closes the gap between
and sometimes even outperforms PyPy's just-in-time compiler.Comment: 16 pages, 4 figures, 3 tables. Uses CPython 3.2.3 and PyPy 1.
Linear Haskell: practical linearity in a higher-order polymorphic language
Linear type systems have a long and storied history, but not a clear path
forward to integrate with existing languages such as OCaml or Haskell. In this
paper, we study a linear type system designed with two crucial properties in
mind: backwards-compatibility and code reuse across linear and non-linear users
of a library. Only then can the benefits of linear types permeate conventional
functional programming. Rather than bifurcate types into linear and non-linear
counterparts, we instead attach linearity to function arrows. Linear functions
can receive inputs from linearly-bound values, but can also operate over
unrestricted, regular values.
To demonstrate the efficacy of our linear type system - both how easy it can
be integrated in an existing language implementation and how streamlined it
makes it to write programs with linear types - we implemented our type system
in GHC, the leading Haskell compiler, and demonstrate two kinds of applications
of linear types: mutable data with pure interfaces; and enforcing protocols in
I/O-performing functions
Recommended from our members
Stack-based Typed Assembly Language
In previous work, we presented a Typed Assembly Language (TAL). TAL is sufficiently expressive to serve as a target language for compilers of high-level languages such as ML. This work assumed such a compiler would perform a continuation-passing style transform and eliminate the control stack by heap-allocating activation records. However, most compilers are based on stack allocation. This paper presents STAL, an extension of TAL with stack constructs and stack types to support the stack allocation style. We show that STAL is sufficiently expressive to support languages such as Java, Pascal, and ML; constructs such as exceptions and displays; and optimizations such as tail call elimination and callee-saves registers. This paper also formalizes the typing connection between CPS-based compilation and stack-based compilation and illustrates how STAL can formally model calling conventions by specifying them as formal translations of source function types to STAL types.Engineering and Applied Science
Simple optimizing JIT compilation of higher-order dynamic programming languages
ImplĂ©menter efficacement les langages de programmation dynamiques demande beaucoup dâeffort de dĂ©veloppement.
Les compilateurs ne cessent de devenir de plus en plus complexes.
Aujourdâhui, ils incluent souvent une phase dâinterprĂ©tation, plusieurs phases de compilation, plusieurs reprĂ©sentations intermĂ©diaires et des analyses de code. Toutes ces techniques permettent dâimplĂ©menter efficacement un langage de programmation dynamique, mais leur mise en oeuvre est difficile dans un contexte oĂč les ressources de dĂ©veloppement sont limitĂ©es.
Nous proposons une nouvelle approche et de nouvelles techniques dynamiques permettant de développer des compilateurs performants pour les langages dynamiques avec de relativement bonnes performances et un faible effort de développement.
Nous prĂ©sentons une approche simple de compilation Ă la volĂ©e qui permet dâimplĂ©menter un langage en une seule phase de compilation, sans transformation vers des reprĂ©sentations intermĂ©diaires.
Nous expliquons comment le versionnement de blocs de base, une technique de compilation existante, peut ĂȘtre Ă©tendue, sans effort de dĂ©veloppement significatif, pour fonctionner interprocĂ©duralement avec les langages de programmation dâordre supĂ©rieur, permettant dâappliquer des optimisations interprocĂ©durales sur ces langages.
Nous expliquons également comment le versionnement de blocs de base permet de supprimer certaines opérations utilisées pour implémenter les langages dynamiques et qui impactent les performances comme les vérifications de type.
Nous expliquons aussi comment les compilateurs peuvent exploiter les reprĂ©sentations dynamiques des valeurs par Tagging et NaN-boxing pour optimiser le code gĂ©nĂ©rĂ© avec peu dâeffort de dĂ©veloppement.
Nous prĂ©sentons Ă©galement notre expĂ©rience de dĂ©veloppement dâun compilateur Ă la volĂ©e pour le langage de programmation Scheme, pour montrer que ces techniques permettent effectivement de construire un compilateur avec un effort moins important que les compilateurs actuels et quâelles permettent de gĂ©nĂ©rer du code efficace, qui rivalise avec les meilleures implĂ©mentations du langage Scheme.Efficiently implementing dynamic programming languages requires a significant development
effort. Over the years, compilers have become more complex. Today, they typically include
an interpretation phase, several compilation phases, several intermediate representations and
code analyses. These techniques allow efficiently implementing these programming languages
but are difficult to implement in contexts in which development resources are limited. We
propose a new approach and new techniques to build optimizing just-in-time compilers for
dynamic languages with relatively good performance and low development effort.
We present a simple just-in-time compilation approach to implement a language with
a single compilation phase, without the need to use code transformations to intermediate
representations. We explain how basic block versioning, an existing compilation technique,
can be extended without significant development effort, to work interprocedurally with higherorder
programming languages allowing interprocedural optimizations on these languages. We
also explain how basic block versioning allows removing operations used to implement dynamic
languages that degrade performance, such as type checks, and how compilers can use Tagging
and NaN-boxing to optimize the generated code with low development effort. We present our
experience of building a JIT compiler using these techniques for the Scheme programming
language to show that they indeed allow building compilers with less development effort
than other implementations and that they allow generating efficient code that competes with
current mature implementations of the Scheme language
Benchmarking Implementations of Functional Languages with ``Pseudoknot'', a Float-Intensive Benchmark
Over 25 implementations of different functional languages are benchmarked using the same program, a floatingpoint intensive application taken from molecular biology. The principal aspects studied are compile time and execution time for the various implementations that were benchmarked. An important consideration is how the program can be modified and tuned to obtain maximal performance on each language implementation.\ud
With few exceptions, the compilers take a significant amount of time to compile this program, though most compilers were faster than the then current GNU C compiler (GCC version 2.5.8). Compilers that generate C or Lisp are often slower than those that generate native code directly: the cost of compiling the intermediate form is normally a large fraction of the total compilation time.\ud
There is no clear distinction between the runtime performance of eager and lazy implementations when appropriate annotations are used: lazy implementations have clearly come of age when it comes to implementing largely strict applications, such as the Pseudoknot program. The speed of C can be approached by some implemtations, but to achieve this performance, special measures such as strictness annotations are required by non-strict implementations.\ud
The benchmark results have to be interpreted with care. Firstly, a benchmark based on a single program cannot cover a wide spectrum of 'typical' applications.j Secondly, the compilers vary in the kind and level of optimisations offered, so the effort required to obtain an optimal version of the program is similarly varied
Overcoming Restraint: Composing Verification of Foreign Functions with Cogent
Cogent is a restricted functional language designed to reduce the cost of
developing verified systems code. Because of its sometimes-onerous
restrictions, such as the lack of support for recursion and its strict
uniqueness type system, Cogent provides an escape hatch in the form of a
foreign function interface (FFI) to C code. This poses a problem when verifying
Cogent programs, as imported C components do not enjoy the same level of static
guarantees that Cogent does. Previous verification of file systems implemented
in Cogent merely assumed that their C components were correct and that they
preserved the invariants of Cogent's type system. In this paper, we instead
prove such obligations. We demonstrate how they smoothly compose with existing
Cogent theorems, and result in a correctness theorem of the overall Cogent-C
system. The Cogent FFI constraints ensure that key invariants of Cogent's type
system are maintained even when calling C code. We verify reusable higher-order
and polymorphic functions including a generic loop combinator and array
iterators and demonstrate their application to several examples including
binary search and the BilbyFs file system. We demonstrate the feasibility of
verification of mixed Cogent-C systems, and provide some insight into
verification of software comprised of code in multiple languages with differing
levels of static guarantees
- âŠ