dynamic languages need dynamic compilers
play

Dynamic Languages need Dynamic Compilers Maxime Chevalier-Boisvert - PowerPoint PPT Presentation

Dynamic Languages need Dynamic Compilers Maxime Chevalier-Boisvert mloc.js 2014 Introduction PhD candidate at the Universit de Montral, prof. Marc Feeley Research: compilers, optimizing dynamic languages, JS This talk is about:


  1. Dynamic Languages need Dynamic Compilers Maxime Chevalier-Boisvert mloc.js 2014

  2. Introduction ● PhD candidate at the Université de Montréal, prof. Marc Feeley ● Research: compilers, optimizing dynamic languages, JS ● This talk is about: – Dynamic languages – JIT compilation & optimization – The Higgs JS compiler – Basic block versioning – Lazy incremental compilation 2

  3. Dynamic languages ● JS is not an "interpreted language" – Originally ran in an interpreter, back in 1995 – Today, all browsers have JIT compilers ● Family of languages sharing “dynamic” characteristics – e.g.: JS, Python, Ruby, PHP, Perl, MATLAB, LISPs ● Huge gain in popularity with web development – Rapid prototyping, short development cycles 3

  4. Defining dynamic languages ● Dynamic typing – Variables can change type over time – Types associated with values – No type annotations ● Late binding – Symbols resolved dynamically (e.g.: globals) – Dynamic loading of code (eval, load) ● Dynamic growth of objects – Dynamic arrays – Objects as dictionaries/maps 4

  5. "I think of a programming language as a tool to convert a programmer's mental images into precise operations that a machine can perform. The main idea is to match the user's intuition as well as possible . […]" – Donald Knuth 5

  6. Higher-level thinking ● Reduce the cognitive burden on programmers ● Hope to make you more productive – Write less code for the same result – Each line of code conveys more meaning ● Leave more details implicit, assumed – Invisible work happen behind the scenes – This invisible work carries extra overhead 6

  7. Dynamic type tests ● Operators change meaning based on types – Different operations for different inputs ● For example, the + operator could mean: – Integer addition – Floating-point addition – String concatenation – Array appending ● Inside each operator hide many type tests – Functions with cascades of if statements testing types 7

  8. 8

  9. 9

  10. JIT compilation ● Key advantages over static compilers – Observe, monitor programs as they run – Modify code at run time ● In theory, JITs can produce faster code – Code adapted to program's behavior – Don't account for unexecuted code ● Opinion: modern JITs still overly static – Compiler books are all about AOT compilers 11

  11. Higgs ● JavaScript JIT compiler for x86-64 – Open source, mostly written in D – Self-hosted runtime library, in JS – Relatively small codebase (~ 50 KLOC) ● Support for most of ECMAScript 5 – No with statement, no getters/setters – Extras: Foreign Function Interface (FFI) ● Experimental platform – Try new ideas, uncharted territory – Basic block versioning, lazy incremental compilation 12

  12. Self-hosting ● Runtime and standard library are self-hosted ● JS primitives (e.g.: + operator) written in extended JS – Exposes low-level operations (e.g.: machine integer ops) ● Primitives compiled & inlined like any other JS code – Avoids opaque calls into C or D code ● Easy to change & extend runtime ● Inlining critical for performance 13

  13. Basic block versioning ● Similarities with tracing, procedure cloning ● As you compile code, accumulate facts – e.g.: type information – Branch tests add type & shape information ● Specialize based on accumulated facts – Type information: type tags, variables, objects – Potentially: register allocation state ● May compile multiple versions of code

  14. true false A B C D 15

  15. true false is_int32(n)? B C D 16

  16. if ( is_int32(n) ) { // B ... } else { // C ... } // D ... 17

  17. true false is_int32(n)? B C D 18

  18. true false is_int32(n)? n is int32 B C D 19

  19. true false is_int32(n)? n is int32 n is not int32 B C D 20

  20. true false is_int32(n)? n is int32 n is not int32 B C n is ??? D 21

  21. true false is_int32(n)? n is int32 n is not int32 B C n is int32 n is not int32 D' D'' 22

  22. var v = 4294967296; for (var i = 0; i < 600000; i++) v = v & i; // From the SunSpider bitwise-and benchmark 23

  23. var v = 4294967296; for (var i = 0; less_than (i,600000); i = add (i,1)) v = bitwise_and (v,i); 24

  24. var v = 4294967296; for (var i = 0; less_than(i,600000); i = add(i,1)) v = bitwise_and (v,i); function bitwise_and (x,y) { if ( is_int32 (x) && is_int32 (y)) return bitwise_and_int32(x,y); // Fast path return bitwise_and_int32(toInt32(x), toInt32(y)); } 25

  25. var v = 4294967296; for (var i = 0; less_than(i,600000); i = add (i,1)) v = bitwise_and(v,i); function bitwise_and(x,y) { if ( is_int32 (x) && is_int32 (y)) return bitwise_and_int32(x,y); // Fast path return bitwise_and_int32(toInt32(x), toInt32(y)); } function add (x,y) { if ( is_int32 (x) && is_int32 (y)) { var r = add_int32(x,y); // Fast path if (cpu_overflow_flag) r = add_double(toDouble(x), toDouble(y)); return r; } return add_general(x,y); 26 }

  26. var v = 4294967296; for (var i = 0; less_than(i,600000); i = add (i,1)) v = bitwise_and(v,i); function bitwise_and(x,y) { if ( is_int32 (x) && is_int32 (y)) return bitwise_and_int32(x,y); // Fast path return bitwise_and_int32(toInt32(x), toInt32(y)); } function add (x,y) { if ( is_int32 (x) && is_int32 (y)) { var r = add_int32(x,y); // Fast path if ( cpu_overflow_flag ) r = add_double(toDouble(x), toDouble(y)); return r; } return add_general(x,y); 27 }

  27. var v = 4294967296; var i = 0; for (;;) { // if (i >= 600000) break; if ( is_int32 (i) && is_int32 (600000)) if (greater_eq_int32(i, 600000)) break; else if (greater_eq_general(i, 600000) break; // v = v & i if ( is_int32 (v) && is_int32 (i)) v = bitwise_and_int32(v,i); else v = bitwise_and _int32 (toInt32(v), toInt32(i)); // i = i + 1 if ( is_int32 (i) && is_int32 (1)) { i = add_int32(i,1); if (cpu_overflow_flag) i = add_double(toDouble(i), toDouble(1)); } else i = add_general(i,1); 28 }

  28. var v = 4294967296; var i = 0; for (;;) { // if (i >= 600000) break; if (is_int32(i) && is_int32 (600000)) if (greater_eq_int32(i, 600000)) break; else if (greater_eq_general(i, 600000) break; // v = v & i if (is_int32(v) && is_int32(i)) v = bitwise_and_int32(v,i); else v = bitwise_and _int32 (toInt32(v), toInt32(i)); // i = i + 1 if (is_int32(i) && is_int32 (1)) { i = add_int32(i,1); if (cpu_overflow_flag) i = add_double(toDouble(i), toDouble(1)); } else i = add_general(i,1); 29 }

  29. var v = 4294967296; var i = 0; for (;;) { // if (i >= 600000) break; if ( is_int32 (i)) if (greater_eq_int32(i, 600000)) break; else if (greater_eq_general(i, 600000) break; // v = v & i if ( is_int32 (v) && is_int32 (i)) v = bitwise_and_int32(v,i); else v = bitwise_and _int32 (toInt32(v), toInt32(i)); // i = i + 1 if ( is_int32 (i)) { i = add_int32(i,1); if (cpu_overflow_flag) i = add_double(toDouble(i), toDouble(1)); } else i = add_general(i,1); 30 }

  30. var v = 4294967296; var i = 0; // when we enter the loop, i is int32 for (;;) { // if (i >= 600000) break; if ( is_int32 (i)) if (greater_eq_int32(i, 600000)) break; else if (greater_eq_general(i, 600000) break; // v = v & i if ( is_int32 (v) && is_int32 (i)) v = bitwise_and_int32(v,i); else v = bitwise_and _int32 (toInt32(v), toInt32(i)); // i = i + 1 if ( is_int32 (i)) { i = add_int32(i,1); if (cpu_overflow_flag) i = add_double(toDouble(i), toDouble(1)); } else i = add_general(i,1); 31 }

  31. var v = 4294967296; var i = 0; for (;;) { // assume i is int32 when entering loop // if (i >= 600000) break; if ( is_int32 (i)) if (greater_eq_int32(i, 600000)) break; else if (greater_eq_general(i, 600000) break; // v = v & i if ( is_int32 (v) && is_int32 (i)) v = bitwise_and_int32(v,i); else v = bitwise_and _int32 (toInt32(v), toInt32(i)); // i = i + 1 if ( is_int32 (i)) { i = add_int32(i,1); if (cpu_overflow_flag) i = add_double(toDouble(i), toDouble(1)); } else i = add_general(i,1); 32 }

  32. var v = 4294967296; var i = 0; for (;;) { // assume i is int32 when entering loop // if (i >= 600000) break; if ( is_int32 (i)) if (greater_eq_int32(i, 600000)) break; else if (greater_eq_general(i, 600000) break; // v = v & i if ( is_int32 (v) && is_int32 (i)) v = bitwise_and_int32(v,i); else v = bitwise_and _int32 (toInt32(v), toInt32(i)); // i = i + 1 if ( is_int32 (i)) { i = add_int32(i,1); if (cpu_overflow_flag) i = add_double(toDouble(i), toDouble(1)); } else i = add_general(i,1); 33 }

  33. var v = 4294967296; var i = 0; for (;;) { // if (i >= 600000) break; if (greater_eq_int32(i, 600000)) break; // v = v & i if ( is_int32 (v) && is_int32 (i)) v = bitwise_and_int32(v,i); else v = bitwise_and_int32(toInt32(v), toInt32(i)); // i = i + 1 if ( is_int32 (i)) { i = add_int32(i,1); if (cpu_overflow_flag) i = add_double(toDouble(i), toDouble(1)); } else i = add_general(i,1); } 34

  34. var v = 4294967296; var i = 0; for (;;) { // if (i >= 600000) break; if (greater_eq_int32(i, 600000)) break; // v = v & i if ( is_int32 (v) && is_int32 (i)) v = bitwise_and_int32(v,i); else v = bitwise_and_int32(toInt32(v), toInt32(i)); // i = i + 1 if ( is_int32 (i)) { i = add_int32(i,1); if (cpu_overflow_flag) i = add_double(toDouble(i), toDouble(1)); } else i = add_general(i,1); } 35

Recommend


More recommend