vmm2016-eclipse omr jitbuilder for better performance

57
Eclipse OMR Eclipse OMR JITBuilder for Better Performance Charlie Gracie, Project Lead IBM Advisory Software Developer 1

Upload: charlie-gracie

Post on 12-Jan-2017

137 views

Category:

Software


0 download

TRANSCRIPT

Page 1: VMM2016-Eclipse OMR JITBuilder for better performance

1

Eclipse OMREclipse OMR JITBuilder for Better Performance

Charlie Gracie, Project LeadIBM Advisory Software Developer

Page 2: VMM2016-Eclipse OMR JITBuilder for better performance

The Legal Stuff

2

IBM’s statements regarding its plans, directions, and intent are subject to change or withdrawal without notice at IBM’s sole discretion. Information regarding potential future products is intended to outline our general product direction and it should not be relied on in making a purchasing decision. The information mentioned regarding potential future products is not a commitment, promise, or legal obligation to deliver any material, code or functionality. Information about potential future products may not be incorporated into any contract. The development, release, and timing of any future features or functionality described for our products remains at our sole discretion.

IBM, the IBM logo, and ibm.com are trademarks or registered trademarks of International Business Machines Corp., registered in many jurisdictions worldwide. Other product and service names might be trademarks of IBM or other companies. A current list of other IBM trademarks is available on the web at "Copyright and trademark information" at http://www.ibm.com/legal/copytrade.shtml

Other company, product, or service names may be trademarks or service marks of others.

THE INFORMATION CONTAINED IN THIS PRESENTATION IS PROVIDED FOR INFORMATIONAL PURPOSES ONLY. WHILE EFFORTS WERE MADE TO VERIFY THE COMPLETENESS AND ACCURACY OF THE INFORMATION CONTAINED IN THIS PRESENTATION, IT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. IN ADDITION, THIS INFORMATION IS BASED ON IBM’S CURRENT PRODUCT PLANS AND STRATEGY, WHICH ARE SUBJECT TO CHANGE BY IBM WITHOUT NOTICE. IBM SHALL NOT BE RESPONSIBLE FOR ANY DAMAGES ARISING OUT OF THE USE OF, OR OTHERWISE RELATED TO, THIS PRESENTATION OR ANY OTHER DOCUMENTATION. NOTHING CONTAINED IN THIS PRESENTATION IS INTENDED TO, NOR SHALL HAVE THE EFFECT OF, CREATING ANY WARRANTIES OR REPRESENTATIONS FROM IBM (OR ITS SUPPLIERS OR LICENSORS), OR ALTERING THE TERMS AND CONDITIONS OF ANY AGREEMENT OR LICENSE GOVERNING THE USE OF IBM PRODUCTS OR SOFTWARE.

© Copyright International Business Machines Corporation 2016. All rights reserved.

Page 3: VMM2016-Eclipse OMR JITBuilder for better performance

More Legal Stuff (!)

THE INFORMATION CONTAINED IN THIS PRESENTATION IS PROVIDED FOR INFORMATIONAL PURPOSES ONLY.

WHILST EFFORTS WERE MADE TO VERIFY THE COMPLETENESS AND ACCURACY OF THE INFORMATION CONTAINED IN THIS PRESENTATION, IT IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED.

ALL PERFORMANCE DATA INCLUDED IN THIS PRESENTATION HAVE BEEN GATHERED IN A CONTROLLED ENVIRONMENT. YOUR OWN TEST RESULTS MAY VARY BASED ON HARDWARE, SOFTWARE OR INFRASTRUCTURE DIFFERENCES.

ALL DATA INCLUDED IN THIS PRESENTATION ARE MEANT TO BE USED ONLY AS A GUIDE.

IN ADDITION, THE INFORMATION CONTAINED IN THIS PRESENTATION IS BASED ON IBM’S CURRENT PRODUCT PLANS AND STRATEGY, WHICH ARE SUBJECT TO CHANGE BY IBM, WITHOUT NOTICE.

IBM AND ITS AFFILIATED COMPANIES SHALL NOT BE RESPONSIBLE FOR ANY DAMAGES ARISING OUT OF THE USE OF, OR OTHERWISE RELATED TO, THIS PRESENTATION OR ANY OTHER DOCUMENTATION.

NOTHING CONTAINED IN THIS PRESENTATION IS INTENDED TO, OR SHALL HAVE THE EFFECT OF:

- CREATING ANY WARRANT OR REPRESENTATION FROM IBM, ITS AFFILIATED COMPANIES OR ITS OR THEIR SUPPLIERS AND/OR LICENSORS

3

Page 4: VMM2016-Eclipse OMR JITBuilder for better performance

This Talk1. Eclipse OMR project

• Created March 2016• OMR JIT to be open source Fall 2016

2. Introduction to OMR JitBuilder• Native code generation toolkit using OMR JIT

3. Experiments with adding a JIT to SOM++ using JitBuilder• Design decisions and limitations• Walkthrough of some of the code• Performance results

4

Page 5: VMM2016-Eclipse OMR JITBuilder for better performance

5

Eclipse OMR MissionBuild an open reusable language runtime foundation for cloud platforms

• To accelerate advancement and innovation

• In full cooperation with existing language communities

• Engaging a diverse community of people interested in language runtimes• Professional developers• Researchers• Students• Hobbyists

Page 6: VMM2016-Eclipse OMR JITBuilder for better performance

6

1. OMR has no language semantics

2. OMR is for building language runtimes but is not itself a language runtime

3. OMR components can be independently integrated into any language runtime, new or existing, without influencing language semantics

Key Goals for Eclipse OMR

Page 7: VMM2016-Eclipse OMR JITBuilder for better performance

http://www.eclipse.org/omrhttps://github.com/eclipse/omr

https://developer.ibm.com/open/omr/

Dual License:Eclipse Public License V1.0

Apache 2.0

Contributors very welcome https://github.com/eclipse/omr/blob/master/CONTRIBUTING.md

Eclipse OMRCreated March 2016

7

Page 8: VMM2016-Eclipse OMR JITBuilder for better performance

8

Eclipse OMR Components Currently Availableport platform abstraction (porting) librarythread cross platform pthread-like threading libraryvm APIs to manage per-interpreter and per-thread contextsgc garbage collection framework for managed heapsomrtrace library for publishing trace events for monitoring/diagnosticsomrsigcompat signal handling compatibility libraryexample demonstration code to show how a language runtime might consume OMR components, also used for testingfvtest language independent test framework built on the example glue so that components can be tested outside of a language runtime, uses Google Test 1.7 framework+ a few others

…400KLOC at this point, more components coming!

Page 9: VMM2016-Eclipse OMR JITBuilder for better performance

9

JitBuilder Library

Just In Time (JIT) CompilersMade Easy(er)

Page 10: VMM2016-Eclipse OMR JITBuilder for better performance

10

What is JitBuilder?• Prototype interface to the OMR JIT compiler technology: Prototype Alert!

• Designed to simplify work to bootstrap a JIT compiler to generate native instructions for interpreted methods• Really a general native code generation toolkit

• OMR JIT is not open source just yet (coming this fall!)• That means JitBuilder is not available as part of Eclipse OMR project just yet• Can be used independently of Eclipse OMR

• JitBuilder Docker image available via Box.com download:• https://ibm.box.com/v/JitBuilder-x86-64-image

• Ease into it with this first blog article below, more coming shortlyhttps://developer.ibm.com/open/2016/07/19/jitbuilder-library-and-eclipse-omr-just-in-time-compilers-made-easy/

Page 11: VMM2016-Eclipse OMR JITBuilder for better performance

11

Simple API• InitializeJit() gets the OMR JIT ready to go

• Among other things, allocates a code cache into which compiled methods go

• ShutdownJit() when you’re done with your native code• It will free the code cache, so compiled methods go away after this call

• Then there’s the compiling part• Need to write a MethodBuilder

Page 12: VMM2016-Eclipse OMR JITBuilder for better performance

What is a MethodBuilder?• MethodBuilder corresponds to a method callable with system linkage

taking whatever parameters you want, returning a value if you want

• 2 basic parts to this C++ class:• Constructor describes return and parameter types• ::buildIL() describes the method’s code

• MethodBuilder class provides services to inject code operations

12

Page 13: VMM2016-Eclipse OMR JITBuilder for better performance

13

What can you generate with JitBuilder?• Data Types

• Primitives: Int8, Int16, Int32, Int64, Float, Double• Arbitrary structs of primitives• Arrays and pointers, but aliasing isn’t yet perfect

• Arithmetic• Add, Sub, Mul, Div, And, Xor, ShiftL, ShiftR, UnsignedShiftR

• Conditional• EqualTo, NotEqualTo, LessThan, GreaterThan

• Type Conversion• ConvertTo

• Memory• Load, Store, IndexAt, LoadAt, StoreAt, LoadField, StoreField• VectorLoad, VectorStore, VectorLoadAt, VectorStoreAt

• Call (use DefineFunction to enable arbitrary C functions to be called)• Control flow

• IfThen, IfThenElse, Switch, ForLoopUp, ForLoopDown, DoWhile, WhileDo, variants with break, continue, etc.• Return

Page 14: VMM2016-Eclipse OMR JITBuilder for better performance

14

Operations are (mostly) typeless• You say “Add” not “Add 32-bit integers”

• Jit Builder will derive type from operands• Leaves of expression trees are typically Load or Const operations

• Current exceptions are things like: LoadAt, StoreAt, IndexAt

• Types of params and/or locals described in constructor• Every Store to a new variable assigns its type (cannot change)

• Store to a new name creates a new slot in the native stack frame

Page 15: VMM2016-Eclipse OMR JITBuilder for better performance

Simple MethodBuilder ExampleSimpleMB::SimpleMB(TR::TypeDictionary *d)

: MethodBuilder(d)

{

DefineName("increment");

DefineParameter("value", Int32);

DefineReturnType(Int32);

}

boolSimpleMB::buildIL(){ Return( Add( Load("value"), ConstInt32(1))); return true;}

15

Page 16: VMM2016-Eclipse OMR JITBuilder for better performance

Simple MethodBuilder ExampleSimpleMB::SimpleMB(TR::TypeDictionary *d)

: MethodBuilder(d)

{

DefineName("increment");

DefineParameter("value", Int32);

DefineReturnType(Int32);

}

boolSimpleMB::buildIL(){ Return( Add( Load("value"), ConstInt32(1))); return true;}

Set the name of the function

16

Page 17: VMM2016-Eclipse OMR JITBuilder for better performance

17

Simple MethodBuilder ExampleSimpleMB::SimpleMB(TR::TypeDictionary *d)

: MethodBuilder(d)

{

DefineName("increment");

DefineParameter("value", Int32);

DefineReturnType(Int32);

}

boolSimpleMB::buildIL(){ Return( Add( Load("value"), ConstInt32(1))); return true;}

Define a 32-bit integer parameter called “value”

Page 18: VMM2016-Eclipse OMR JITBuilder for better performance

18

Simple MethodBuilder ExampleSimpleMB::SimpleMB(TR::TypeDictionary *d)

: MethodBuilder(d)

{

DefineName("increment");

DefineParameter("value", Int32);

DefineReturnType(Int32);

}

boolSimpleMB::buildIL() { Return( Add( Load("value"), ConstInt32(1))); return true; }

increment will return a 32-bit integer

Page 19: VMM2016-Eclipse OMR JITBuilder for better performance

19

Simple MethodBuilder ExampleSimpleMB::SimpleMB(TR::TypeDictionary *d)

: MethodBuilder(d)

{

DefineName("increment");

DefineParameter("value", Int32);

DefineReturnType(Int32);

}

boolSimpleMB::buildIL(){ Return( Add( Load("value"), ConstInt32(1))); return true;}

Used to record and lookup types (e.g. Int32)

Page 20: VMM2016-Eclipse OMR JITBuilder for better performance

20

Simple MethodBuilder ExampleSimpleMB::SimpleMB(TR::TypeDictionary *d)

: MethodBuilder(d)

{

DefineName("increment");

DefineParameter("value", Int32);

DefineReturnType(Int32);

}

boolSimpleMB::buildIL(){ Return( Add( Load("value"), ConstInt32(1))); return true;}

Describes what code to generate for incrementConstruct expression trees from simple operations

Page 21: VMM2016-Eclipse OMR JITBuilder for better performance

21

Simple MethodBuilder ExampleSimpleMB::SimpleMB(TR::TypeDictionary *d)

: MethodBuilder(d)

{

DefineName("increment");

DefineParameter("value", Int32);

DefineReturnType(Int32);

}

boolSimpleMB::buildIL(){ Return( Add( Load("value"), ConstInt32(1))); return true;}

Reference parameters by name e.g. “value”You can also create new locals by name

Page 22: VMM2016-Eclipse OMR JITBuilder for better performance

22

Create IlBuilders for new code paths// if-then-else constructIlBuilder *thenPath=OrphanBuilder();IlBuilder *elsePath=OrphanBuilder();IfThenElse(&thenPath, &elsePath, LessThan(Load(“a”), Load(”b”));

// put then operations into thenPath builderthenPath->Store(“T”,thenPath-> ConstInt32(1));

// put else operations into elsePath builderelsePath->Store(“T”,elsePath-> ConstInt32(0));

// code after merge goes into “this” builderReturn( Load(“T”));

Page 23: VMM2016-Eclipse OMR JITBuilder for better performance

23

Create IlBuilders for new code paths// if-then-else constructIlBuilder *thenPath=OrphanBuilder();IlBuilder *elsePath=OrphanBuilder();IfThenElse(&thenPath, &elsePath, LessThan(Load(“a”), Load(”b”));

// put then operations into thenPath builderthenPath->Store(“T”,thenPath-> ConstInt32(1));

// put else operations into elsePath builderelsePath->Store(“T”,elsePath-> ConstInt32(0));

// code after merge goes into “this” builderReturn( Load(“T”));

Creates two new code paths (thenPath, elsePath)

Page 24: VMM2016-Eclipse OMR JITBuilder for better performance

24

Create IlBuilders for new code paths// if-then-else constructIlBuilder *thenPath=OrphanBuilder();IlBuilder *elsePath=OrphanBuilder();IfThenElse(&thenPath, &elsePath, LessThan(Load(“a”), Load(”b”));

// put then operations into thenPath builderthenPath->Store(“T”,thenPath-> ConstInt32(1));

// put else operations into elsePath builderelsePath->Store(“T”,elsePath-> ConstInt32(0));

// code after merge goes into “this” builderReturn( Load(“T”));

IfThenElse connects the new code paths in a diamond,Decide based on (a < b)

Page 25: VMM2016-Eclipse OMR JITBuilder for better performance

25

Create IlBuilders for new code paths// if-then-else constructIlBuilder *thenPath=OrphanBuilder();IlBuilder *elsePath=OrphanBuilder();IfThenElse(&thenPath, &elsePath, LessThan(Load(“a”), Load(”b”));

// put then operations into thenPath builderthenPath->Store(“T”,thenPath-> ConstInt32(1));

// put else operations into elsePath builderelsePath->Store(“T”,elsePath-> ConstInt32(0));

// code after merge goes into “this” builderReturn( Load(“T”));

Inject operations directly onto the code path where they should execute

Page 26: VMM2016-Eclipse OMR JITBuilder for better performance

26

Create IlBuilders for new code paths// if-then-else constructIlBuilder *thenPath=OrphanBuilder();IlBuilder *elsePath=OrphanBuilder();IfThenElse(&thenPath, &elsePath, LessThan(Load(“a”), Load(”b”));

// put then operations into thenPath builderthenPath->Store(“T”,thenPath-> ConstInt32(1));

// put else operations into elsePath builderelsePath->Store(“T”,elsePath-> ConstInt32(0));

// code after merge goes into “this” builderReturn( Load(“T”));

On then path, T=1

Page 27: VMM2016-Eclipse OMR JITBuilder for better performance

27

Create IlBuilders for new code paths// if-then-else constructIlBuilder *thenPath=OrphanBuilder();IlBuilder *elsePath=OrphanBuilder();IfThenElse(&thenPath, &elsePath, LessThan(Load(“a”), Load(”b”));

// put then operations into thenPath builderthenPath->Store(“T”,thenPath-> ConstInt32(1));

// put else operations into elsePath builderelsePath->Store(“T”,elsePath-> ConstInt32(0));

// code after merge goes into “this” builderReturn( Load(“T”));

On else path, T=0

Page 28: VMM2016-Eclipse OMR JITBuilder for better performance

28

Create IlBuilders for new code paths// if-then-else constructIlBuilder *thenPath=OrphanBuilder();IlBuilder *elsePath=OrphanBuilder();IfThenElse(&thenPath, &elsePath, LessThan(Load(“a”), Load(”b”));

// put then operations into thenPath builderthenPath->Store(“T”,thenPath-> ConstInt32(1));

// put else operations into elsePath builderelsePath->Store(“T”,elsePath-> ConstInt32(0));

// code after merge goes into “this” builderReturn( Load(“T”));

Operations are appended to the code path you specifyReturn(Load(“T”)) happens after the merge for IfThenElse

Page 29: VMM2016-Eclipse OMR JITBuilder for better performance

29

Create IlBuilders for new code paths// if-then-else constructIlBuilder *thenPath=OrphanBuilder();IlBuilder *elsePath=OrphanBuilder();IfThenElse(&thenPath, &elsePath, LessThan(Load(“a”), Load(”b”));

// put then operations into thenPath builderthenPath->Store(“T”,thenPath-> ConstInt32(1));

// put else operations into elsePath builderelsePath->Store(“T”,elsePath-> ConstInt32(0));

// else path returns, but then path does notelsePath->Return(elsePath-> Load(“T”));

Return(Load(”T”)) directly from the elsePath

Page 30: VMM2016-Eclipse OMR JITBuilder for better performance

30

TypeDictionary for managing types• Primitive types: NoType, Int8, Int16, Int32, Int64, Float, Double• Pointer (array) types: pInt8, pInt16, pInt32, pInt64, pFloat, pDouble• Can define structures with fields

• Then LoadIndirect() or StoreIndirect() to access fields offset from a base pointer

TR::IlType *elementType = DefineStruct(“Element”);

DefineField(“Element”, “next”, PointerTo(elementType));

DefineField(“Element”, “key”, Int32);

DefineField(“Element”, “value”, Double);

// load ((Element *)ptr)->key

TR::IlValue *result = LoadIndirect(“Element”, “key”, Load(“ptr”));

Page 31: VMM2016-Eclipse OMR JITBuilder for better performance

31

BytecodeBuilders for easy(er) JIT writing• Write a handler for each type of bytecode to inject code to execute that type

of bytecode• Create a BytecodeBuilder object for every bytecode index• Iterate over bytecodes in a method:

• Call the right handler on BytecodeBuilder object for this bytecode index• Tell the object how control flows out from this bytecode

bytecodeBuilder->AddFallThroughBuilder(nextBuilderObject);bytecodeBuilder->AddSuccessorBuilder(branchesToBuilderObject);

• MethodBuilder must call AppendBuilder(bytecodeBuilder[0]);• More explanation in developerworksOpen talk from July 20:

https://developer.ibm.com/open/videos/eclipse-omr-tech-talk/

Page 32: VMM2016-Eclipse OMR JITBuilder for better performance

32

• Group of implementations written in different languages• C, C++, Java, Python, Truffle/Graal, RPython, etc.• SOM++ is the C++ implementation

• Spent 2-3 weeks implementing a JitBuilder for SOM++• Benchmark improvements of 2.5-15x

http://som-st.github.io

Page 33: VMM2016-Eclipse OMR JITBuilder for better performance

33

JitBuilder Design for SOM++• On N executions of a method add it to queue to be JIT’d• Create a JIT thread to compile methods asynchronously• Call the JIT’d version of a method on sends if it exists

• JitBuilder methods are generated as C callable functions

• Keep shape of the interpreter frame• This allows easy fallback to the interpreter

• Make the interpreter loop callable so it can be called from JIT’d code• Assume objects do not move

Page 34: VMM2016-Eclipse OMR JITBuilder for better performance

34

SOM++ Interpreter Basics• Every Smalltalk method’s source code is compiled to an array of bytecodes• Interpreter iterates over those bytecodes• Every bytecode has a bytecode handler that executes actions for that

bytecode• Most bytecodes pop and/or push values to the operand stack

• E.g. BC_PUSH_CONSTANT pushes a constant value onto the operand stack• E.g. BC_DUP conceptually pops a value from the operand stack, then pushes two

copies of that value back onto the operand stack

• Some bytecodes cause interpreter to read at another location in bytecode array

• E.g. BC_JUMP or BC_JUMP_IF_TRUE

Page 35: VMM2016-Eclipse OMR JITBuilder for better performance

35

JitBuilder for Bytecode Basics• Just like interpreter needs a handler for every bytecode, so does JitBuilder

• Every bytecode needs a BytecodeBuilder handler• Handler describes how to generate code for that bytecode

• Also like interpreter, need to iterate over bytecode array• For each bytecode, create a BytecodeBuilder object and call BytecodeBuilder

handler on it• BytecodeBuilder object represents the native code to execute a particular bytecode

• Also need to indicate where control goes after each bytecode:• Most bytecodes just fall through to next bytecode• Some (e.g. BC_JUMP) branch to some other bytecode

• Best to create all BytecodeBuilder objects up front, then call handler to generate code

Page 36: VMM2016-Eclipse OMR JITBuilder for better performance

36

SOM++ MethodBuilder SOMppMethodSOMppMethod::SOMppMethod(TR::TypeDictionary *types, VMMethod *vmMethod)

: MethodBuilder(types),

method(vmMethod)

{ DefineName(methodName); //methodName is class>>#signature

DefineReturnType(NoType);

defineStructures(types);

DefineParameter("interpreter", Int64);

DefineParameter("frame", pVMFrame);

}

Page 37: VMM2016-Eclipse OMR JITBuilder for better performance

37

SOM++ MethodBuilder SOMppMethodSOMppMethod::SOMppMethod(TR::TypeDictionary *types, VMMethod *vmMethod)

: MethodBuilder(types),

method(vmMethod)

{ DefineName(methodName); //methodName is class>>#signature

DefineReturnType(NoType);

defineStructures(types);

DefineParameter("interpreter", Int64);

DefineParameter("frame", pVMFrame);

}

Page 38: VMM2016-Eclipse OMR JITBuilder for better performance

38

SOM++ MethodBuilder SOMppMethodSOMppMethod::SOMppMethod(TR::TypeDictionary *types, VMMethod *vmMethod)

: MethodBuilder(types),

method(vmMethod)

{ DefineName(methodName); //methodName is class>>#signature

DefineReturnType(NoType);

defineStructures(types);

DefineParameter("interpreter", Int64);

DefineParameter("frame", pVMFrame);

}

Page 39: VMM2016-Eclipse OMR JITBuilder for better performance

39

SOMppMethod defined structuresvoid

SOMppMethod::defineStructures(TR::TypeDictionary *types)

{

defineVMObjectStructure(types);

defineVMFrameStructure(types);

}

Page 40: VMM2016-Eclipse OMR JITBuilder for better performance

40

SOMppMethod defined structuresvoid

SOMppMethod::defineStructures(TR::TypeDictionary *types)

{

defineVMObjectStructure(types);

defineVMFrameStructure(types);

}

Page 41: VMM2016-Eclipse OMR JITBuilder for better performance

41

SOMppMethod VMFramevoid

SOMppMethod::defineVMFrameStructure(TR::TypeDictionary *types)

{

vmFrame = types->DefineStruct("VMFrame");

pVMFrame = types->PointerTo("VMFrame");

types->DefineField("VMFrame", "vTable", Int64);

....

types->DefineField("VMFrame", "arguments", pVMObject);

types->DefineField("VMFrame", "locals", pVMObject);

types->DefineField("VMFrame", "stack_ptr", pVMObject);

types->CloseStruct("VMFrame");

}

Page 42: VMM2016-Eclipse OMR JITBuilder for better performance

42

SOMppMethod::buildIL()bool SOMppMethod::buildIL()

{

TR::BytecodeBuilder **bytecodeBuilderTable = allocBytecodeBuilderTable(method);

if (nullptr == bytecodeBuilderTable) {

return false;

}

createBytecodeBuilders(bytecodeBuilderTable, method);

AppendBuilder(bytecodeBuilderTable[0]); //append the first bytecode builder

bool generated = generateIlForBytecodes(bytecodeBuilderTable, method)

free((void *)bytecodeBuilderTable);

return generated;

}

Page 43: VMM2016-Eclipse OMR JITBuilder for better performance

43

SOMppMethod::buildIL()bool SOMppMethod::buildIL()

{

TR::BytecodeBuilder **bytecodeBuilderTable = allocBytecodeBuilderTable(method);

if (nullptr == bytecodeBuilderTable) {

return false;

}

createBytecodeBuilders(bytecodeBuilderTable, method);

AppendBuilder(bytecodeBuilderTable[0]); //append the first bytecode builder

bool generated = generateIlForBytecodes(bytecodeBuilderTable, method)

free((void *)bytecodeBuilderTable);

return generated;

}

Page 44: VMM2016-Eclipse OMR JITBuilder for better performance

44

SOM++ MethodBuildervoid createBytecodeBuilders(TR::BytecodeBuilder **table, VMMethod *method)

{

long bytecodeIndex = 0;

while (bytecodeIndex < method->GetNumberOfBytecodes()) {

uint8_t bc = method->GetBytecode(bytecodeIndex);

table[bytecodeIndex] = OrphanBytecodeBuilder(bytecodeIndex, Bytecode::GetBytecodeName(bc));

bytecodeIndex += Bytecode::GetBytecodeLength(bc);

}

}

Page 45: VMM2016-Eclipse OMR JITBuilder for better performance

45

BytecodeBuilder table for example bytecodes

PUSH_CONSTANT0

PUSH_LOCAL15

JUMP_IF_TRUE000

15PUSH_CONSTANT

1PUSH_LOCAL

25

OrphanBytecodeBuilder(0, “PUSH_CONSTANT”)

OrphanBytecodeBuilder(2, “PUSH_LOCAL”)

OrphanBytecodeBuilder(5, “JUMP_IF_TRUE”)

0:1:2:3:4:5:6:7:8:9:10:11:12:13:14:

0:1:2:3:4:5:6:7:8:9:10:11:12:13:14:

OrphanBytecodeBuilder(10, “PUSH_CONSTANT”)

OrphanBytecodeBuilder(12, “PUSH_LOCAL”)

bytecodes builders

Page 46: VMM2016-Eclipse OMR JITBuilder for better performance

46

SOMppMethod::buildIL()bool SOMppMethod::buildIL()

{

TR::BytecodeBuilder **bytecodeBuilderTable = allocBytecodeBuilderTable(method);

if (nullptr == bytecodeBuilderTable) {

return false;

}

createBytecodeBuilders(bytecodeBuilderTable, method);

AppendBuilder(bytecodeBuilderTable[0]); //append the first bytecode builder

bool generated = generateIlForBytecodes(bytecodeBuilderTable, method);

free((void *)bytecodeBuilderTable);

return generated;

}

Page 47: VMM2016-Eclipse OMR JITBuilder for better performance

47

Call Builder Handlers for each bytecodeboolgenerateIlForBytecodes(TR::BytecodeBuilder **table, VMMethod *method) { while (bcIndex < method->GetNumberOfBytecodes()) { uint8_t bc = method->GetBytecode(bcIndex); switch(bc) { case BC_PUSH_CONSTANT : { doPushConstant(builders[bcIndex], method->GetBytecode(bcIndex+1)); bcIndex += 2; // this bytecode has a length of 2 break; } case BC_PUSH_LOCAL : …

Page 48: VMM2016-Eclipse OMR JITBuilder for better performance

48

BC_ PUSH_CONSTANT <constant index>void Interpreter::doPushConstant(long bytecodeIndex) { vm_oop_t constant = method->GetConstant(bytecodeIndex); GetFrame()->Push(constant);}

Boils down to:uint8_t index = bytecodes[bytecodeIndex + 1];vm_oop_t constant = method->indexableFields[index];++frame->stack_ptr;*frame->stack_ptr = constant;

Page 49: VMM2016-Eclipse OMR JITBuilder for better performance

49

BC_ PUSH_CONSTANT <constant index>bool

doPushConstant(TR::BytecodeBuilder *b, uint8_t index) {

b->Store(“constant”, // can load/store native locals by name

b-> LoadAt(pInt64, // pInt64 is a type: pointer to Int64

b-> IndexAt(pInt64, // for simplicity, treating vm_oop_t as pInt64

b-> LoadIndirect(“VMMethod”, “indexableFields”,

b-> Load(“method”)),

b-> ConstInt64(index))));

vm_oop_t constant = method->indexableFields[index];++frame->stack_ptr;*frame->stack_ptr = constant;

Page 50: VMM2016-Eclipse OMR JITBuilder for better performance

50

BC_ PUSH_CONSTANT <constant index>bool

doPushConstant(TR::BytecodeBuilder *b, uint8_t bc)

b->Store("newSP", // store the value of frame->stack_ptr + 8 into a temp

b-> Add( // using 8 to simply the code and make it more readable

b-> LoadIndirect("VMFrame", "stack_ptr",

b-> Load(frame)),

b-> ConstInt64(8)));

b->StoreIndirect("VMFrame", "stack_ptr", // store newSP into frame->stack_ptr

b-> Load(frame),

b-> Load("newSP"));

b->StoreAt(pInt64, // store the constant value into the frame->stack_ptr

b-> Load("newSP"),

b-> Load("constant"));

return true;

}

vm_oop_t constant = method->indexableFields[index];++frame->stack_ptr;*frame->stack_ptr = constant;

Page 51: VMM2016-Eclipse OMR JITBuilder for better performance

51

What should happen after bytecode at 0?Control should fall through to bytecode at 2!

PUSH_CONSTANT0

PUSH_LOCAL15

JUMP_IF_TRUE000

15PUSH_CONSTANT

1PUSH_LOCAL

25

0:1:2:3:4:5:6:7:8:9:10:11:12:13:14:

bytecodeswhile (bcIndex < method->GetNumberOfBytecodes()) { switch(bc) { case BC_PUSH_CONSTANT : { doPushConstant(builders[bcIndex], method->GetBytecode(bcIndex+1)); builders[bcIndex]->AddFallthroughBuilder(builders[bcIndex+2]); bcIndex += 2; // this bytecode has a length of 2 break; } case BC_PUSH_LOCAL …

Page 52: VMM2016-Eclipse OMR JITBuilder for better performance

52

Branches: add successor builder for destination

bytecodes while (bc < method->GetNumberOfBytecodes()) { switch(method->GetBytecode(bc)) { case BC_JUMP_IF_TRUE : { long destIndex = calculateBranchDestinationForJump(bc); doJumpIfTrue(builders[bc], destIndex); builders[bc]->AddFallthroughBuilder(builders[bc+5]); builders[bc]->AddSuccessorBuilder(builders[destIndex]); bc += 5; // this bytecode has a length of 5 break; } case BC_PUSH_LOCAL : …

PUSH_CONSTANT0

PUSH_LOCAL15

JUMP_IF_TRUE000

15PUSH_CONSTANT

1PUSH_LOCAL

25

0:1:2:3:4:5:6:7:8:9:10:11:12:13:14:

Page 53: VMM2016-Eclipse OMR JITBuilder for better performance

53

Generating and Calling JIT’d methodsvoid VMMethod::Invoke(Interpreter* interp, VMFrame* frame) { VMFrame* frm = interp->PushNewFrame(this); frm->CopyArgumentsFrom(frame); if(NULL != compiledMethod) { compiledMethod((int64_t)interp, (int64_t)frm); } else if (invokedCount > 0) { if ((0 == --invokedCount) && enableJIT) { TR::TypeDictionary types; SOMppMethod methodBuilder(&types, this); rc = (*compileMethodBuilder)(&methodBuilder, &compiledMethod); if (0 != rc) compiledMethod = (SOMppFunctionType *)NULL;………..}

Page 54: VMM2016-Eclipse OMR JITBuilder for better performance

54

SOM++ JitBuilder performance

Fibonacci

Dispatch

BounceLoop

Permute

QueensLis

t

Recurse

StorageSieve

BubbleSort

QuickSort

SumTowers

TreeSort

IntegerLoop

FieldLoop0

20

40

60

80

100

120

140

160

180

SOM++ Benchmarks (lower is better)

default "-jit"

Page 55: VMM2016-Eclipse OMR JITBuilder for better performance

55

Future improvements to SOM++ JIT• Do not keep frame->stack_ptr up to date

• Use a JIT operand stack• If required write to the actual stack (for sends)

• Modify VM so that inline allocation is possible• Allocate frame objects on JIT stack for sends from the JIT• Improve JIT to JIT calls / returns

Page 56: VMM2016-Eclipse OMR JITBuilder for better performance

56

Wrap Up• Eclipse OMR mission to create an open reusable language runtime foundation• Building an open community for everyone to share and discuss ideas,

technology, and best practices to build language runtimes• JitBuilder is available now for you to play with

• Includes the current OMR JIT just not in source form (coming in the Fall!)• Write your own JIT compiler• Part of a layered strategy to incrementally improve performance via JIT technology

• The SOM++ JitBuilder strategy and code could easily be used by any C/C++ runtime to add JIT support in a very short period of time

• Everyone is welcome to join us at Eclipse OMR and we hope you will !

Page 57: VMM2016-Eclipse OMR JITBuilder for better performance

57

Where to contact us• Charlie Gracie [email protected] @crgracie• Mailing List [email protected]

Subscribe at https://dev.eclipse.org/mailman/listinfo/omr-dev

• Eclipse OMR Web Site https://www.eclipse.org/omr

• Eclipse OMR pages on DeveloperWorks Open https://developer.ibm.com/open/omr/

• Eclipse OMR Github project https://github.com/eclipse/omr

• JitBuilder Docker image https://ibm.box.com/v/JitBuilder-x86-64-image

• SOM++ with OMR and JitBuilder (omr_jitbuilder) https://github.com/charliegracie/SOMpp

• OMR developers will be at:• Ruby Kaigi in September• Java One in September• ReUsable Modular Programming Language Environments (RUMPLE) workshop in October