Abstract The recent multicore revolution presents us with a great challenge: If we want our software to take advantage of multicore processors, we need to switch to parallel computing, after more than sixty years of mainly sequential thinking. In this dissertation, we take the stance that the physical parallelism offered by multicore processors should be treated as a resource that is managed by the virtual machine. That is to say, we envision virtual machines that automatically parallelize the execution of existing sequential programming languages. As a concrete case study, we develop an interpreter that automatically parallelizes the execution of arbitrary (recursive) Scheme code. We choose Scheme for our experiments because it is a minimal language with all the basic ingredients for expressing the major programming paradigms. Our interpreter by default parallelizes the execution of procedure calls, speculatively evaluates conditional expressions, and relies on work stealing for scheduling the generated parallelism. We identify a set of requirements for correctly combining parallel procedure calling, speculative computation, and side effects, so that the parallel execution of a program matches the sequential semantics of Scheme. Our most important contribution is the continuator concept, which automatically manages all of these requirements. The continuator is essentially a tree-based representation of the execution trace that the interpreter builds as a program runs, to keep track of the control dependences between program expressions. It allows the interpreter to manage the control flow of the different parallel threads, makes it possible to abort incorrectly speculated computations without entirely freezing the interpreter’s execution, and keeps track of the order of side effects to avoid data races. As one part of the validation, we discuss the results of running an optimized implementation of continuators against the Clinger benchmark suite for Scheme. The numbers show linear speedups for functional programs, but code with side effects currently runs in constant time, independent from the number of available processor cores. This is due to our conservative strategy to treat every side effect as a synchronization point, but it should be possible to optimize this in future work. We argue that the positive benchmark numbers show that the overhead of the continuator infrastructure is in an acceptable range, and that our approach can effectively lead to speedups. A second part of our validation investigates the reusability of the continuator concept for developing different kinds of parallel interpreters. To this end, we discuss the design of a pipelined interpreter that also uses the continuator—without any changes—for managing the control flow of a program. In future work, we plan to integrate our interpreter with dynamic compilation and hotspot analysis, for example to detect at runtime which parts of a program are interesting to parallelize, to perform branch prediction, or to detect side effects before their execution is parallelized. Keywords: Multicore processors, automatic parallelization, parallel programming, interpreters, speculative computation, continuator Samenvatting De recente overschakeling naar multikernprocessoren vormt een ware uitdaging op het gebied van software-ontwikkeling. Indien we beogen dat onze programma’s voordeel halen uit multikernprocessoren, dan zullen we moeten overschakelen naar parallel programmeren, hoewel we ons de voorbije zestig jaar voornamelijk hebben toegespitst op het schrijven van sequentiële programma’s. In deze verhandeling nemen wij het standpunt in dat we het parallelisme in multikernprocessoren moeten behandelen als een systeemfaciliteit. Onze visie bestaat eruit virtuele machines te ontwerpen die de uitvoer van programma’s volledig automatisch paralleliseren. Als een concreet experiment ontwikkelen wij een vertolker die de uitvoer van Scheme programma’s—zonder enige beperkingen—automatisch paralleliseert. Wij hebben in onze experimenten voor Scheme gekozen omdat het enerzijds een zeer compacte programmeertaal is en anderzijds omdat het in Scheme mogelijk is om de meest gangbare programmeerparadigma’s uit te drukken. Onze vertolker paralleliseert per definitie de uitvoer van procedure-oproepen, speculeert over de uitvoer van conditionele expressies, en maakt gebruik van de work-stealing techniek om het parallelisme te verdelen over de verschillende processorkernen. In ons discours identificeren wij de vereisten om parallelle uitvoer van procedure-oproepen, speculatieve berekeningen, en instructies die de programmastaat veranderen, te combineren zodat de parallelle uitvoer van een programma overeenkomt met diens sequentiële semantiek. Onze belangrijkste bijdrage is de continuator, een concept dat ons toelaat om al deze vereisten in de vertolker in te bouwen. De continuator is een voorstelling van de programma-uitvoer in de vorm van een boom die door de vertolker opgebouwd wordt tijdens het uitvoeren van een programma. De vertolker gebruikt deze boomvoorstelling van de programma-uitvoer om de volgorde tussen programmaexpressies bij te houden. Het is dankzij de continuator dat onze parallelle vertolker in staat is om de volgorde-afhankelijkheden tussen de verschillende parallelle berekeningen bij te houden. De continuator maakt het ook mogelijk om verkeerdelijk gespeculeerde berekeningen te annuleren zonder dat de vertolker daarvoor gepauzeerd dient te worden. Tenslotte garandeert de continuator dat de volgorde behouden wordt van de instructies die de programmastaat aanpassen. Ter validatie hebben we een geoptimaliseerde implementatie gemaakt van een vertolker die gebruikt maakt van continuatoren. Wij bespreken de resultaten die we voor deze implementatie verkregen bij het uitvoeren van de Clinger benchmark-testen voor Scheme. Voor functionele code krijgen we lineaire speedups, maar voor programma’s die veelvuldig gebruik maken van instructies die de programmastaat aanpassen, krijgen we helemaal geen speedups. Dit is te wijten aan het feit dat we de uitvoer van zulke instructies altijd synchroniseren—hoewel dat eigenlijk niet altijd nodig is. Wij denken dit in de toekomst te kunnen verbeteren. Desalniettemin tonen de positieve benchmark-testen aan dat de overhead van de continuatorinfrastructuur aanvaardbaar is, en dat onze parallelisatiestrategie kan leiden tot speedups. Een tweede deel van onze validatie bestaat eruit na te gaan of de continuator als concept herbruikbaar is om andere parallelle vertolkers te implementeren. Om dit te onderzoeken, bespreken we de implementatie van een vertolker die georganiseerd is als een pipeline, en de continuator— zonder enige aanpassing—hergebruikt. In toekomstig werk zijn wij van plan om onze vertolker uit te breiden met dynamische analyse en compilatie, bijvoorbeeld om te detecteren welke delen van een programma het meeste baat hebben bij parallelle uitvoer, om te kunnen voorspellen welke tak van een conditionele expressie het meeste kans maakt om uitgevoerd te worden, of om instructies die de programmastaat aanpassen te detecteren voor ze geparalleliseerd worden. Trefwoorden: Multikernprocessoren, automatische parallelisatie, parallel programmeren, vertolkers, speculatieve uitvoer, continuator