Copyright 2012, Oracle and/or its affiliates. All rights reserved. Insert Information Protection Policy Classification from Slide 16

Similar documents
Compiler construction 2009

JVML Instruction Set. How to get more than 256 local variables! Method Calls. Example. Method Calls

Building a Compiler with. JoeQ. Outline of this lecture. Building a compiler: what pieces we need? AKA, how to solve Homework 2

Static Analysis of Dynamic Languages. Jennifer Strater

Compiler construction 2009

JVM. What This Topic is About. Course Overview. Recap: Interpretive Compilers. Abstract Machines. Abstract Machines. Class Files and Class File Format

Exercise 7 Bytecode Verification self-study exercise sheet

Code Generation. Frédéric Haziza Spring Department of Computer Systems Uppsala University

Part VII : Code Generation

CS1622. Semantic Analysis. The Compiler So Far. Lecture 15 Semantic Analysis. How to build symbol tables How to use them to find

Oak Intermediate Bytecodes

CSE P 501 Compilers. Java Implementation JVMs, JITs &c Hal Perkins Winter /11/ Hal Perkins & UW CSE V-1

Translating JVM Code to MIPS Code 1 / 43

Agenda. CSE P 501 Compilers. Java Implementation Overview. JVM Architecture. JVM Runtime Data Areas (1) JVM Data Types. CSE P 501 Su04 T-1

Administration CS 412/413. Why build a compiler? Compilers. Architectural independence. Source-to-source translator

Announcements. My office hours are today in Gates 160 from 1PM-3PM. Programming Project 3 checkpoint due tomorrow night at 11:59PM.

Running class Timing on Java HotSpot VM, 1

Static Program Analysis

Run-time Program Management. Hwansoo Han

Code Generation Introduction

CS2110 Fall 2011 Lecture 25. Under the Hood: The Java Virtual Machine, Part II

Java Class Loading and Bytecode Verification

Where We Are. Lexical Analysis. Syntax Analysis. IR Generation. IR Optimization. Code Generation. Machine Code. Optimization.

Just-In-Time Compilation

Course Overview. PART I: overview material. PART II: inside a compiler. PART III: conclusion

EXAMINATIONS 2014 TRIMESTER 1 SWEN 430. Compiler Engineering. This examination will be marked out of 180 marks.

Java byte code verification

JSR 292 Cookbook: Fresh Recipes with New Ingredients

Project Compiler. CS031 TA Help Session November 28, 2011

Compiling Faster, Compiling Better with Falcon. Iván

COMP-520 GoLite Tutorial

CSE 431S Final Review. Washington University Spring 2013

Code Generation. Lecture 12

Compiler-guaranteed Safety in Code-copying Virtual Machines

Scala: Byte-code Fancypants. David Pollak JVM Language Summit 2009

Trace Compilation. Christian Wimmer September 2009

Java: framework overview and in-the-small features

Just In Time Compilation

Semantic Analysis. Lecture 9. February 7, 2018

COMP3131/9102: Programming Languages and Compilers

Run-time Environments. Lecture 13. Prof. Alex Aiken Original Slides (Modified by Prof. Vijay Ganesh) Lecture 13

Functions CHAPTER 5. FIGURE 1. Concrete syntax for the P 2 subset of Python. (In addition to that of P 1.)

Syntax Errors; Static Semantics

Static Semantics. Lecture 15. (Notes by P. N. Hilfinger and R. Bodik) 2/29/08 Prof. Hilfinger, CS164 Lecture 15 1

CSc 453 Interpreters & Interpretation

Chapter 5. A Closer Look at Instruction Set Architectures. Chapter 5 Objectives. 5.1 Introduction. 5.2 Instruction Formats

The Compiler So Far. CSC 4181 Compiler Construction. Semantic Analysis. Beyond Syntax. Goals of a Semantic Analyzer.

CSC 4181 Handout : JVM

Chapter 5. A Closer Look at Instruction Set Architectures

Java Security. Compiler. Compiler. Hardware. Interpreter. The virtual machine principle: Abstract Machine Code. Source Code

Improving Java Performance

Improving Java Code Performance. Make your Java/Dalvik VM happier

CA Compiler Construction

Project. there are a couple of 3 person teams. a new drop with new type checking is coming. regroup or see me or forever hold your peace

The Java Virtual Machine. CSc 553. Principles of Compilation. 3 : The Java VM. Department of Computer Science University of Arizona

Faculty of Electrical Engineering, Mathematics, and Computer Science Delft University of Technology

LLVM for a Managed Language What we've learned

Types. Type checking. Why Do We Need Type Systems? Types and Operations. What is a type? Consensus

UNIVERSITY OF CALIFORNIA Department of Electrical Engineering and Computer Sciences Computer Science Division. P. N. Hilfinger

Lecture 16: Static Semantics Overview 1

The Java Language Implementation

Programming Language Systems

Compilers. Intermediate representations and code generation. Yannis Smaragdakis, U. Athens (original slides by Sam

Java Instrumentation for Dynamic Analysis

Mnemonics Type-Safe Bytecode Generation in Scala

CS24: INTRODUCTION TO COMPUTING SYSTEMS. Spring 2018 Lecture 11

Compilation /15a Lecture 7. Activation Records Noam Rinetzky

Code Generation. Lecture 19

invokedynamic under the hood

Compiler Construction

Copyright 2013, Oracle and/or its affiliates. All rights reserved.

Let s make some Marc R. Hoffmann Eclipse Summit Europe

Today. Instance Method Dispatch. Instance Method Dispatch. Instance Method Dispatch 11/29/11. today. last time

CMSC430 Spring 2014 Midterm 2 Solutions

<Insert Picture Here> Implementing lambda expressions in Java

Combining Analyses, Combining Optimizations - Summary

Lecture 25: Register Allocation

Control Flow Analysis

An Introduction to Multicodes. Ben Stephenson Department of Computer Science University of Western Ontario

Group B Assignment 8. Title of Assignment: Problem Definition: Code optimization using DAG Perquisite: Lex, Yacc, Compiler Construction

Plan for Today. Safe Programming Languages. What is a secure programming language?

Compilers and computer architecture: A realistic compiler to MIPS

javac 29: pop 30: iconst_0 31: istore_3 32: jsr [label_51]

JOHANNES KEPLER UNIVERSITÄT LINZ

Compiling Techniques

What is a compiler? var a var b mov 3 a mov 4 r1 cmpi a r1 jge l_e mov 2 b jmp l_d l_e: mov 3 b l_d: ;done

CSE 501: Compiler Construction. Course outline. Goals for language implementation. Why study compilers? Models of compilation

Preconditions. CMSC 330: Organization of Programming Languages. Signaling Errors. Dealing with Errors

invokedynamic IN 45 MINUTES!!! Wednesday, February 6, 13

How do you create a programming language for the JVM?

Intermediate Code & Local Optimizations

Joeq Analysis Framework. CS 243, Winter

Course Overview. Levels of Programming Languages. Compilers and other translators. Tombstone Diagrams. Syntax Specification

Lecture 3 Local Optimizations, Intro to SSA

COMP 520 Fall 2009 Virtual machines (1) Virtual machines

Recap: Printing Trees into Bytecodes

CS113: Lecture 4. Topics: Functions. Function Activation Records

Deriving Code Coverage Information from Profiling Data Recorded for a Trace-based Just-in-time Compiler

Run-time Environments

Run-time Environments

Transcription:

1 Copyright 2012, Oracle and/or its affiliates. All rights reserved. Insert Information Protection Policy Classification from Slide 16

Towards JVM Dynamic Languages Toolchain Insert Picture Here Attila Szegedi Principal Member of Technical Staff 2 Copyright 2012, Oracle and/or its affiliates. All rights reserved. Insert Information Protection Policy Classification from Slide 16

The following is intended to outline our general product direction. It is intended for information purposes only, and may not be incorporated into any contract. It is not a commitment to deliver any material, code, or functionality, and should not be relied upon in making purchasing decisions. The development, release, and timing of any features or functionality described for Oracle s products remains at the sole discretion of Oracle. 3

Why? Source code Interpreter Compiler Runtime JVM Assumption: you talk to JVM in bytecode 4

Reuse V8 has 972k lines of code Nashorn has 213k lines of code Because underlying Java platform provides lots of services Imagine your language runtime tapping some of Nashorn s 213k LOC. 5

What can Nashorn do today? Parameter type specialized compilation Gradual deoptimization with on-stack code replacement a.k.a. optimistic typing Splitting large methods and array initializers Static code analysis Compiler optimizations 6

Parameter type specialized compilation Here s code versions for f generated when invoked with int and double: function square(x) { return x*x; } print(square(500)); print(square(500.1)); public static square(object;i)i 0 iload 1 1 iload 1 2 invokedynamic imul(ii)i 7 ireturn public static square(object;d)d 0 dload 1 1 dload 1 2 dmul 3 dreturn 7

Parameter type specialized compilation Here s code version for f generated when invoked with object: function square(x) { return x*x; } var a = { valueof: function() { return 500; } }; print(square(a)); public static square(object;object;)d 0 aload 1 1 invokestatic JSType.toNumber(Object;)D 4 aload 1 5 invokestatic JSType.toNumber(Object;)D 8 dmul 9 dreturn 8

Parameter type specialized compilation tonumber is invoked twice: object-to-number can have side effects function square(x) { return x*x; } var i = 500; var a = { valueof: function() { return i++; } } print(square(a)) public static square(object;object;)d 0 aload 1 1 invokestatic JSType.toNumber(Object;)D 4 aload 1 5 invokestatic JSType.toNumber(Object;)D 8 dmul 9 dreturn 9

Deoptimizing compilation: arithmetic overflow can t just use IMUL. function square(x) { return x*x; } print(square(500)); public static square(object;i)i 0 iload 1 1 iload 1 2 invokedynamic imul(ii)i 7 ireturn 10

L0 L1 L2 Deoptimizing compilation: arithmetic overflow public static square(object;i)i try L0 L1 L2 UnwarrantedOptimismException 0 iload 1 1 iload 1 2 invokedynamic imul(ii)i [static mathbootstrap'] 7 ireturn 8 iconst_2 9 anewarray Object 12 aload 0 13 iload 1 14 invokedynamic populatearray([object;object;i)[object;[ populatearraybootstrp'] 23 invokestatic RewriteException.create(UnwarrantedOptimismException; [Object;)RewriteException; 26 athrow 11

Deoptimizing compilation: arithmetic overflow public static int mulexact(final int x, final int y, final int programpoint) throws UnwarrantedOptimismException { try { return Math.multiplyExact(x, y); } catch (final ArithmeticException e) { throw new UnwarrantedOptimismException((long)x * (long)y, programpoint); } } Math.multiplyExact() is intrinsified by HotSpot We must perform the operation and return the result in the exception 12

Deoptimizing compilation: property type function f(a) { return a.foo * 2; } f({foo: 5.5}) 13

Deoptimizing compilation: property type L0 L1 L3 L4 L2 public static f(object;object;)i try L0 L1 L2 UnwarrantedOptimismException try L3 L4 L2 UnwarrantedOptimismException 0 aload 1 1 invokedynamic dyn:getprop getelem getmethod:foo(object;)i [static bootstrap pp=2] 6 iconst_2 7 invokedynamic imul(ii)i [static mathbootstrap pp=3] 12 ireturn 13 iconst_2 14 anewarray Object 17 aload 0 18 aload 1 19 invokedynamic populatearray([object;object;object;)[object;... 14

Deoptimizing compilation: property type public static f(object;object;)d 0 aload 1 1 invokedynamic dyn:getprop getelem getmethod:foo(object;)d [static 'bootstrap'] 6 ldc 2.0 9 dmul 10 dreturn Since first argument is now double, second is also widened to double. Static analysis FTW Multiplication can no longer overflow, so implicitly it also becomes nonoptimistic in a single deoptimizing recompilation pass. 15

Deoptimizing compilation: rest-of method public static f(rewriteexception;)d 0 goto L0 3 nop... 8 athrow L2 9 ldc 2.0 12 dmul 13 dreturn L0 14 aload 0 15 astore 2 16 aload 0 17 invokevirtual RewriteException.getByteCodeSlots()[Object; 20 dup 21 iconst_0 22 aaload 23 astore 0 25 iconst_1 26 aaload 27 astore 1 32 invokevirtual RewriteException.getReturnValueDestructive()Object; 35 invokestatic JSType.toNumber(Object;)D 38 goto L2 16

Sometimes we don t want to be optimistic Static analysis can help us avoid optimism when it s not needed. E.g. overflow semantics is sufficient because an operator would coerce anyway: (i*i) 0 (logical or coerces to 32-bit int in JS) 17

Type inference Static analysis in a dynamic language is great when you re targeting a statically typed runtime. Nashorn calculates types of expressions and local variables. Local variable types are propagated from def to use sites. Handles tricky control flow situations. Examples: Control transfer into catch blocks break from a finally Operates on AST 18

Handling undefined function f(x) { var i; print(i); var sum = 0; for(i = 0; i < x; ++i) { sum += i; } } print(f(5)) undefined is a type in the type calculator with a single value. When known undefined is loaded, we just load it as a constant. Otherwise, it s an object. But that s rare. 19

Variables with multiple types function f(x) { var i; var y; if(x) { i = 1; y = i * 2; // i int here } return i; // i object here } print(f(5)) Even then, we preserve it as int within the branch range and add an implicit boxing before the join point. This preservation of narrower types in ranges is true for all types. Variables can be stored in slots of different types at different times. Here, we emit a synthetic else block that initializes i to Undefined.INSTANCE. 20

Parameters with multiple types function f(x, y) { x = x * 2.1; return x * y; } print(f(5, 6)) Currently, storage for locals of multiple types is contiguous. Method prologue is emitted to shift incoming parameters to the right as necessary. public static f(object;ii)d iload 2 istore 4 iload 1 i2d ldc 2.1 dmul dstore 2 dload 2 iload 4 i2d dmul dreturn local x L0 L2 1 I local :this L0 L4 0 Object; local x L2 L4 2 D local y L0 L4 4 I 21

Dead code elimination Due to type specialization functions are compiled only on first invocation. Dead stores are eliminated, as well as some side-effect free parts of their right sides. Since we don t have full liveness analysis on AST, we resorted to weaker type liveness analysis for variables to avoid unnecessary conversions at joins. Almost as a side effect, partial dead store elimination came out of it. 22

Nashorn compiler pipeline Source code Parser AST Atf1 Atfn AST CodeGen Bytecode After parser, there are lots of AST transformation steps (lowering, splitting, symbol assignment, type calculation) Code generator translate AST to JVM bytecode. It s heavy machinery. Emits code for optimistic operations, continuation handling, loads vs. stores, self-assignment stores (++, += operations), split functions control flow handover, 23

Separate AST linearization Dynamic bytecode Atfn AST DynCodeGen Dtfn CodeGen Bytecode Code generator heavy lifting doesn t need to produce JVM bytecode. It could produce dynamically typed bytecode. Separate optimization steps could work on this bytecode. Some optimizations work better on a basic-block representation. Finally, a light straightforward new codegen could emit JVM bytecode from dynamic bytecode. 24

Benefits of new intermediate representation Some calculations are impossible or near impossible on AST, but easy and well understood on basic blocks. E.g. liveness analysis needs backwards control flow traversal. AST is language dependent, bytecode isn t. Or less so. The proposed dynamic bytecode is still very close to JVM bytecode, so can be targeted by many languages. This is the reusability/toolchain idea. Similar in idea to LLVM s IR. 25

Arithmetic example: Source code: function f(x, y) { return x * y; } Dynamic bytecode: f(int x, INT y) LOAD x LOAD y MUL RETURN JVM bytecode: public static f(object;ii)i iload 1 iload 2 invokedynamic imul(ii)i ['mathbootstrap'] ireturn catch UnwarrantedOptimismException iconst_3 anewarray Object aload 0 iload 1 iload 2 invokedynamic populatearray([object;object;ii)[object; invokestatic RewriteException.create(...)RewriteException; athrow local :this L3 L2 0 Object; local x L3 L2 1 I local y L3 L2 2 I 26

Benefits of new intermediate representation You can emit symbolic identifiers for variables; final codegen will take care of mapping to JVM local variable slots. It ll infer types for variables and other values (with pluggable language specific rules for operations). It ll emit optimistic operations when needed, set up exception handlers, and emit continuation restart methods. It ll infer JVM return types for functions. 27

Property getter example: Source code: function f(x, y) { return x.foo * y; } Dynamic bytecode: f(object x, INT y) LOAD x GETPROP foo LOAD y MUL RETURN JVM bytecode: public static f(object;ii)i aload 1 invokedynamic dyn:getprop getelem getmethod:foo(object;)i iload 2 invokedynamic imul(ii)i ['mathbootstrap'] ireturn catch UnwarrantedOptimismException iconst_3 anewarray Object aload 0 aload 1 iload 2 invokedynamic populatearray([object;object;object;i)[object; invokestatic RewriteException.create(...)RewriteException; athrow local :this L3 L2 0 Object; local x L3 L2 1 Object; local y L3 L2 2 I 28

Code regeneration reasons foo might turn out not to be an int (but a double, or even an object) multiplication can overflow. If needed, function type during regeneration will also evolve from int to long or double. 29

Lexical scope getter example: Source code: function f(x, y) { function g(z) { return x.foo * z; } return g(z); } Dynamic bytecode: g(int y) LOAD x GETPROP foo LOAD y MUL RETURN JVM bytecode: public static f$g(scriptfunction;object;i)i aload 0 invokevirtual ScriptFunction.getScope()ScriptObject; astore 3 aload 3 invokedynamic dyn:getprop getelem getmethod:x(object;)object; invokedynamic dyn:getprop getelem getmethod:foo(object;)i iload 2 invokedynamic imul(ii)i ireturn catch UnwarrantedOptimismException 30

Lexical scope Most dynamic languages have the concept of accessing variables from outer lexical scope. JVM bytecode doesn t. We can bridge that. In dynamic bytecode, you can symbolically reference those variables as if they were locals. JVM code generator will emit necessary load scope, get variable as property from it sequence, complete with optimism if needed. 31

Dynamic bytecode to JVM bytecode Types are inferred; statically non-provable types are optimistically presumed; some operations are emitted as indy invocations LOAD x ILOAD 3 or DLOAD 3 etc. LOAD x ALOAD 2 // scope INVOKEDYNAMIC getprop:x MUL IMUL or INVOKEDYNAMIC imul ALOAD x ALOAD 5 GETPROP y INVOKEDYNAMIC getprop:y 32

Other things we can do automatically Splitting of large methods into less than 64k JVM bytecode chunks. Current Nashorn AST splitter makes conservative size estimates. Dynamic bytecode size much better approximates JVM bytecode size. Passing local variables used by split chunks needs artificial lexical scope objects. Split functions are also subject to deoptimizing recompilation. Trickier as possibly multiple stack frames need to be saved/restored. 33

Things you don t even think about Remember how we capture local variables in the optimism exception handler? Know what we can t capture? Stack state. We ll add artificial stores into temporary local variable slots for anything that needs to remain on stack, e.g. 34

Things you don t even think about function f(x, y) { return (x * x) + (y * y); } If squaring y overflows, we already have square of x on stack, and it must be captured and restored. If a value on stack isn t already a load of a local variable, we store it into a new temporary and load it back on stack, thus stashing them away in a place accessible to the exception handler. 35

Things you don t even think about public static f(object;ii)i try L0 L1 L2 UnwarrantedOptimismException try L3 L4 L5 UnwarrantedOptimismException try L4 L6 L2 UnwarrantedOptimismException 0 iload 1 1 iload 1 L0 [bci=2] 2 invokedynamic imul(ii)i L1 [bci=7] 7 istore 3 8 iload 3 9 iload 2 10 iload 2 L3 [bci=11] 11 invokedynamic imul(ii)i L4 [bci=16] 16 invokedynamic iadd(ii)i L6 [bci=21] 21 ireturn L5 [bci=22] 22 iconst_4 23 anewarray Object 26 iload 3 27 invokedynamic populatearray([object;i)[object; 32 goto L8 L2 [bci=35] 35 iconst_3 36 anewarray Object L8 [bci=39] 39 aload 0 40 iload 1 41 iload 2 42 invokedynamic populatearray([object;object;ii) 47 iconst_0 51 invokestatic RewriteException.create( ); 54 athrow local :this L7 L5 0 Object; local x L7 L5 1 I local y L7 L5 2 I 36

Could be improved function f(x,y) { function g() {} return g(x*x, x, y*y); } Generates: iload 1 iload 1 invokedynamic imul(ii)i iload 1 pop istore 5 iload 5 iload 1 iload 2 iload 2 invokedynamic imul(ii)i Could be: iload 1 iload 1 invokedynamic imul(ii)i istore 5 iload 1 iload 2 iload 2 invokedynamic imul(ii)i 37

Could be improved We detect the need to store the value too late (after load of the next one was emitted). Hard to solve with AST, as it doesn't have the stack-machine model in it. Easier with a CFG of basic blocks in an already stack-machine language. We could also avoid synthetic stores for all values that are constants or pure functions of local variables. (Currently: locals only). 38

Linking aspect There is also a linking aspect involving MethodHandles.catchException combinator that jumps into deoptimizing recompilation and runs a rest-of method when a function exits with RewriteException. Won t go into details here. 39

Summary Some things are hard: static analysis, type-specialized on-demand compilation, optimistic types with on-stack-replacement deoptimizing recompilation, etc. We have solved a bunch of those with Nashorn, and would like to offer them as a reusable library. The library needs an input code representation to work on. AST is too high level, JVM bytecode is too statically typed. We think something almost bytecode, but with optional types. 40

Summary We want to give you a framework that: takes dynamic bytecode as its input with given parameter types proves JVM types of expressions statically where they can t be proven or could overflow, inserts optimistic operations allows for running various optimizing transforms on it emits the final JVM bytecode, with all the smarts presented earlier. helps you with method handle combinators for linking call sites to functions that can get deoptimized. 41

42 Copyright 2012, Oracle and/or its affiliates. All rights reserved. Insert Information Protection Policy Classification from Slide 16

43 Copyright 2012, Oracle and/or its affiliates. All rights reserved. Insert Information Protection Policy Classification from Slide 16