kotlin bytecode generation and runtime performance

40
Kotlin Bytecode Generation and Runtime Performance Dmitry Jemerov Dmitry Jemerov, 11-13 May 2016

Upload: intelliyole

Post on 08-Jan-2017

1.591 views

Category:

Software


2 download

TRANSCRIPT

Kotlin Bytecode Generationand

Runtime Performance

Dmitry Jemerov

Dmitry Jemerov, 11-13 May 2016

What is Kotlin

What is Kotlin

What is Kotlin

• Statically typed programming language for JVM, Android and the browser

• Pragmatic, safe, concise, seamless Java interop

What is Kotlin

• Statically typed programming language for the JVM, Android and the browser

• Pragmatic, safe, concise, seamless Java interop

Compiling a mixed project

*.java

kotlinc

*.kt

*.class

javac *.class

*.jar

Metadata@Metadata(

mv = {1, 1, 1}, bv = {1, 0, 0}, k = 1, d1 = {"\u0000\"\n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0002\b\u0002\n\u0002\u0010\b\n\u0000\n\u0002\u0010\u0002\n\u0002\b\u0005\n\u0002\u0018\u0002\n\u0002\b\u0002\b\u0017\u0018\u00002\u00020\u0001B\u0005¢\u0006\u0002\u0010\u0002J\b\u0010\u0003\u001a\u00020\u0004H\u0007J\b\u0010\u0005\u001a\u00020\u0006H\u0007J\b\u0010\u0007\u001a\u00020\u0004H\u0007J\b\u0010\b\u001a\u00020\u0004H\u0007J!\u0010\t\u001a\u0002H\n\"\u0004\b\u0000\u0010\n2\f\u0010\u000b\u001a\b\u0012\u0004\u0012\u0002H\n0\fH\u0002¢\u0006\u0002\u0010\r¨\u0006\u000e"}, d2 = {"Lorg/jetbrains/LambdaBenchmark;", "Lorg/jetbrains/SizedBenchmark;", "()V", "capturingLambda", "", "init", "", "mutatingLambda", "noncapturingLambda", "runLambda", "T", "x", "Lkotlin/Function0;", "(Lkotlin/jvm/functions/Function0;)Ljava/lang/Object;", "production sources for module kotlin-benchmarks"}

) public class LambdaBenchmark extends SizedBenchmark { … }

Working with metadata

class A { fun foo(): String? = null fun bar(): String = ""} fun main(args: Array<String>) { println(A::class.functions.filter { it.returnType.isMarkedNullable }) }

File-level functions// Data.kt fun foo() {}

public final class DataKt { public static void foo() { } }

@JvmName@file:JvmName("FooUtils") fun foo() {}

public final class FooUtils { public static final void foo() { } }

Primary constructorsclass A(val x: Int) {}

public final class A { private final int x; public final int getX() { return this.x; } public A(int x) { this.x = x; }}

Data classesdata class A(val x: Int) {}

public final class A { …

public String toString() { return "A(x=" + this.x + ")"; } public int hashCode() { return this.x; } public boolean equals(Object o) { … } }

Propertiesclass A { var x: String? = null}

public final class A { @Nullable private String x; @Nullable public final String getX() { return this.x; } public final void setX( @Nullable String x) { this.x = x; }}

@JvmFieldclass A { @JvmField var x: String? = null}

public final class A { @JvmField @Nullable public String x;}

Not-null typesclass A { fun x(s: String) { println(s) }

private fun y(s: String) { println(s) } }

public final class A { public final void x(@NotNull String s) { Intrinsics. checkParameterIsNotNull(s, "s"); System.out.println(s); } private final void y(String s) { System.out.println(s); }}

Parameter null checks

1 parameter

8 parameters

ns0 2,25 4,5 6,75 9

Without @NotNull With @NotNull

Extension functionsclass A(val i: Int)fun A.foo(): Int { return i } fun useFoo() { A(1).foo() }

public final class ExtFunKt { public static final void foo( @NotNull A $receiver) { return $receiver.getI(); }}

public static final void useFoo() { foo(new A(1));}

Interface methodsinterface I { fun foo(): Int { return 42 } } class C : I {}

public interface I { int foo(); public static final class DefaultImpls { public static int foo(I $this) { return 42; } }}

public final class C implements I { public void foo() { I.DefaultImpls.foo(this); }}

Interface methods: Evolutioninterface I { fun foo(): Int { return 42 } fun bar(): Int { return 239 } } // -- separate compilation ——————class C : I {}

public interface I { int foo(); int bar(); public static final class DefaultImpls { … }} // -- separate compilation ——————

public final class C implements I { public void foo() { I.DefaultImpls.foo(this); }}

Default Argumentsfun foo(x: Int = 42) { println(x)} fun bar() { foo() }

public static final void foo(int x) { System.out.println(x);} public static void foo$default( int x, int mask, …) { if ((mask & 1) != 0) { x = 42; } foo(x);} public static final void bar() { foo$default(0, 1, …);}

Default Arguments

1 parameter

8 parameters

ns0 3,75 7,5 11,25 15

Without default values With default values

@JvmOverloads@JvmOverloadsfun foo(x: Int = 42) {}

public static final void foo(int x) { } public static void foo$default( int x, int mask, …) { … }public static void foo() { foo$default(0, 1, …);}

Lambdas: Functional typesfun <T> runLambda(x: () -> T): T = x()

private static final Object runLambda(Function0 x) { return x.invoke();}

package kotlin.jvm.functions/** A function that takes 0 arguments. */public interface Function0<out R> : Function<R> { /** Invokes the function. */ public operator fun invoke(): R}

Lambdas: Noncapturingvar value = 0 fun noncapLambda(): Int = runLambda { value }

final class LB$noncapLambda$1 extends Lambda implements Function0 { public static final LB$noncapLambda$1 INSTANCE = new LB$noncapLambda$1(); public final int invoke() { return LambdaBenchmarkKt.getValue(); }}

public static int noncapLambda() { return ((Number)runLambda( LB$noncapLambda$1.INSTANCE) ).intValue();}

Lambdas: Capturingfun capturingLambda(v: Int): Int = runLambda { v }

public static intcapturingLambda(int value) { return ((Number)RL.runLambda( new Function0(0) { public final int invoke() { return value; } }) ).intValue();

Lambdas: Capture and mutatefun mutatingLambda(): Int { var x = 0 runLambda { x++ } return x }

public static int mutatingLambda() { final IntRef x = new IntRef(); x.element = 0;

RL.runLambda(new Function0(0) { public final int invoke() { int var1 = x.element++; return var1; } }); return x.element;}

public static final class IntRef { public volatile int element; @Override public String toString() { return String.valueOf(element); }}

Lambdas

Noncapturing

Capturing

Mutating

ns0 45 90 135 180

Java Kotlin

Lambdas: inlinefun inlineLambda(x: Int): Int = run { x }

public static int inlineLambda(int x) { return x;}

/** * Calls the specified function [block] and returns its result. */public inline fun <R> run(block: () -> R): R = block()

Method Referencesprivate fun referenced() = 1 fun runReference() { runLambda(::referenced)}

final class MethodReferenceKt$runReference$1 extends FunctionReference implements Function0 { public static final MethodReferenceKt$runReference$1 INSTANCE = new MethodReferenceKt$runReference$1(); public final int invoke() { return MethodReferenceKt.access$referenced(); } public final KDeclarationContainer getOwner() { … } public final String getName() { … } public final String getSignature() { … }}

Loops: Rangefun rangeLoop() { for (i in 1..10) { println(i) }}

public static final void rangeLoop() { int i = 1; byte var1 = 10; if(i <= var1) { while(true) { System.out.println(i); if(i == var1) { break; } ++i; } }}

Loops: Arrayfun arrayLoop(x: Array<String>) { for (s in x) { println(s) }}

public static void arrayLoop(@NotNull String[] x) {

for(int var2 = 0; var2 < x.length; ++var2) {

String s = x[var2]; System.out.println(s); } }

Loops: Listfun listLoop(x: List<String>) { for (s in x) { println(s) }}

public static final void listLoop(@NotNull List x) { Iterator var2 = x.iterator(); while(var2.hasNext()) { String s = (String)var2.next(); System.out.println(s); }}

Loops

Range

Array

ArrayList

ns0 27,5 55 82,5 110

Java Kotlin

When: Table lookupfun tableWhen(x: Int): String = when(x) { 0 -> "zero" 1 -> "one" else -> "many"}

public static String tableWhen(int x) { String var10000; switch(x) { case 0: var10000 = "zero"; break; case 1: var10000 = "one"; break; default: var10000 = "many"; } return var10000;}

When: Constantsval ZERO = 0 val ONE = 1 fun constWhen(x: Int): String = when(x) { ZERO -> "zero" ONE -> "one" else -> "many"}

public static String constWhen( int x) { return x == ZERO ? “zero" : (x == ONE ? “one" : "many");}

When: enumenum class NumberValue { ZERO, ONE, MANY } fun enumWhen(x: NumberValue): String = when(x) { NumberValue.ZERO -> "zero" NumberValue.ONE -> "one" else -> "many"}

public static String enumWhen(@NotNull NumberValue x) { String var10000; switch(WhenEnumKt$WhenMappings.$EnumSwitchMapping$0[x.ordinal()]) { case 1: var10000 = "zero"; break; case 2: var10000 = "one"; break; default: var10000 = "many"; } return var10000;}

When

Lookup

Compare

Enum

ns0 5,5 11 16,5 22

Java Kotlin

Summary

• Kotlin allows writing code which is easy to use from Java

• Performance in most scenarios is on par with Java

• Inline functions 👍

• Measure the performance of your code, not micro-examples

https://www.manning.com/books/kotlin-in-action