From d272979b09e605ced6cba2d10c27177383411309 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Wed, 7 Dec 2011 11:51:50 +0200 Subject: [PATCH] thread ring benchmark and related bug fixes (non null array creation and wrong signature of enclosing class) --- .../jetbrains/jet/codegen/ClosureCodegen.java | 5 +- .../jetbrains/jet/codegen/CodegenContext.java | 34 ++--- .../jet/codegen/ExpressionCodegen.java | 19 +-- .../jet/codegen/GenerationState.java | 2 +- .../codegen/ImplementationBodyCodegen.java | 2 +- .../testData/codegen/classes/nonnullarray.jet | 8 + .../testData/codegen/regressions/kt694.jet | 9 ++ .../jetbrains/jet/codegen/ArrayGenTest.java | 5 + .../jetbrains/jet/codegen/ClassGenTest.java | 6 + examples/src/benchmarks/ThreadRing.java | 137 ++++++++++++++++++ examples/src/benchmarks/ThreadRing.kt | 95 ++++++++++++ 11 files changed, 284 insertions(+), 38 deletions(-) create mode 100644 compiler/testData/codegen/classes/nonnullarray.jet create mode 100644 compiler/testData/codegen/regressions/kt694.jet create mode 100644 examples/src/benchmarks/ThreadRing.java create mode 100644 examples/src/benchmarks/ThreadRing.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java index 75241d6dc74..085dfb7f5c3 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java @@ -10,7 +10,6 @@ import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.psi.JetDeclarationWithBody; import org.jetbrains.jet.lang.psi.JetExpression; -import org.jetbrains.jet.lang.psi.JetFunctionLiteral; import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.scopes.JetScope; @@ -100,7 +99,7 @@ public class ClosureCodegen extends ObjectOrClosureCodegen { generateBridge(name, funDescriptor, fun, cv); captureThis = generateBody(funDescriptor, cv, fun.getFunctionLiteral()); ClassDescriptor thisDescriptor = context.getThisDescriptor(); - final Type enclosingType = thisDescriptor == null ? null : Type.getObjectType(thisDescriptor.getName()); + final Type enclosingType = thisDescriptor == null ? null : state.getTypeMapper().mapType(thisDescriptor.getDefaultType()); if (enclosingType == null) captureThis = false; @@ -164,7 +163,7 @@ public class ClosureCodegen extends ObjectOrClosureCodegen { Collections.emptyList(), Collections.singleton((funDescriptor.getReceiverParameter().exists() ? JetStandardClasses.getReceiverFunction(arity) : JetStandardClasses.getFunction(arity)).getDefaultType()), JetScope.EMPTY, Collections.emptySet(), null); - final CodegenContext.ClosureContext closureContext = context.intoClosure(funDescriptor, function, name, this); + final CodegenContext.ClosureContext closureContext = context.intoClosure(funDescriptor, function, name, this, state.getTypeMapper()); FunctionCodegen fc = new FunctionCodegen(closureContext, cv, state); fc.generateMethod(body, invokeSignature(funDescriptor), funDescriptor); return closureContext.outerWasUsed; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java index a5d3447e98c..88ce2d7883b 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java @@ -104,24 +104,24 @@ public abstract class CodegenContext { return new ClassContext(descriptor, kind, this, typeMapper); } - public CodegenContext intoAnonymousClass(@NotNull ObjectOrClosureCodegen closure, ClassDescriptor descriptor, OwnerKind kind) { - return new AnonymousClassContext(descriptor, kind, this, closure); + public CodegenContext intoAnonymousClass(@NotNull ObjectOrClosureCodegen closure, ClassDescriptor descriptor, OwnerKind kind, JetTypeMapper typeMapper) { + return new AnonymousClassContext(descriptor, kind, this, closure, typeMapper); } public MethodContext intoFunction(FunctionDescriptor descriptor) { return new MethodContext(descriptor, getContextKind(), this); } - public ConstructorContext intoConstructor(ConstructorDescriptor descriptor) { + public ConstructorContext intoConstructor(ConstructorDescriptor descriptor, JetTypeMapper typeMapper) { if(descriptor == null) { descriptor = new ConstructorDescriptorImpl(getThisDescriptor(), Collections.emptyList(), true) .initialize(Collections.emptyList(), Collections.emptyList(), Modality.OPEN, Visibility.PUBLIC); } - return new ConstructorContext(descriptor, getContextKind(), this); + return new ConstructorContext(descriptor, getContextKind(), this, typeMapper); } - public ClosureContext intoClosure(FunctionDescriptor funDescriptor, ClassDescriptor classDescriptor, String internalClassName, ClosureCodegen closureCodegen) { - return new ClosureContext(funDescriptor, classDescriptor, this, closureCodegen, internalClassName); + public ClosureContext intoClosure(FunctionDescriptor funDescriptor, ClassDescriptor classDescriptor, String internalClassName, ClosureCodegen closureCodegen, JetTypeMapper typeMapper) { + return new ClosureContext(funDescriptor, classDescriptor, this, closureCodegen, internalClassName, typeMapper); } public FrameMap prepareFrame(JetTypeMapper mapper) { @@ -170,12 +170,12 @@ public abstract class CodegenContext { return parentContext != null ? parentContext.lookupInContext(d, v, result) : null; } - public Type enclosingClassType() { + public Type enclosingClassType(JetTypeMapper typeMapper) { CodegenContext cur = getParentContext(); while(cur != null && !(cur.getContextDescriptor() instanceof ClassDescriptor)) cur = cur.getParentContext(); - return cur == null ? null : Type.getObjectType(cur.getContextDescriptor().getName()); + return cur == null ? null : typeMapper.mapType(((ClassDescriptor)cur.getContextDescriptor()).getDefaultType()); } public int getTypeInfoConstantIndex(JetType type) { @@ -290,8 +290,8 @@ public abstract class CodegenContext { return getParentContext().lookupInContext(d, v, result); } - public Type enclosingClassType() { - return getParentContext().enclosingClassType(); + public Type enclosingClassType(JetTypeMapper typeMapper) { + return getParentContext().enclosingClassType(typeMapper); } @Override @@ -305,10 +305,10 @@ public abstract class CodegenContext { } public static class ConstructorContext extends MethodContext { - public ConstructorContext(ConstructorDescriptor contextType, OwnerKind kind, CodegenContext parent) { + public ConstructorContext(ConstructorDescriptor contextType, OwnerKind kind, CodegenContext parent, JetTypeMapper typeMapper) { super(contextType, kind, parent); - final Type type = enclosingClassType(); + final Type type = enclosingClassType(typeMapper); outerExpression = type != null ? local1 : null; @@ -323,7 +323,7 @@ public abstract class CodegenContext { public ClassContext(ClassDescriptor contextType, OwnerKind contextKind, CodegenContext parentContext, JetTypeMapper typeMapper) { super(contextType, contextKind, parentContext, null); - final Type type = enclosingClassType(); + final Type type = enclosingClassType(typeMapper); outerExpression = type != null ? StackValue.field(type, typeMapper.getFQName(contextType), "this$0", false) : null; @@ -341,10 +341,10 @@ public abstract class CodegenContext { } public static class AnonymousClassContext extends CodegenContext { - public AnonymousClassContext(ClassDescriptor contextType, OwnerKind contextKind, CodegenContext parentContext, @NotNull ObjectOrClosureCodegen closure) { + public AnonymousClassContext(ClassDescriptor contextType, OwnerKind contextKind, CodegenContext parentContext, @NotNull ObjectOrClosureCodegen closure, JetTypeMapper typeMapper) { super(contextType, contextKind, parentContext, closure); - final Type type = enclosingClassType(); + final Type type = enclosingClassType(typeMapper); outerExpression = type != null ? StackValue.field(type, closure.state.getTypeMapper().mapType(contextType.getDefaultType(), OwnerKind.IMPLEMENTATION).getInternalName(), "this$0", false) : null; @@ -364,11 +364,11 @@ public abstract class CodegenContext { public static class ClosureContext extends ReceiverContext { private ClassDescriptor classDescriptor; - public ClosureContext(FunctionDescriptor contextType, ClassDescriptor classDescriptor, CodegenContext parentContext, @NotNull ObjectOrClosureCodegen closureCodegen, String internalClassName) { + public ClosureContext(FunctionDescriptor contextType, ClassDescriptor classDescriptor, CodegenContext parentContext, @NotNull ObjectOrClosureCodegen closureCodegen, String internalClassName, JetTypeMapper typeMapper) { super(contextType, OwnerKind.IMPLEMENTATION, parentContext, closureCodegen); this.classDescriptor = classDescriptor; - final Type type = enclosingClassType(); + final Type type = enclosingClassType(typeMapper); outerExpression = type != null ? StackValue.field(type, internalClassName, "this$0", false) : null; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index e77bf07342d..9f29c28ce15 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1958,26 +1958,13 @@ public class ExpressionCodegen extends JetVisitor { } else { ClassDescriptor classDecl = (ClassDescriptor) constructorDescriptor.getContainingDeclaration(); - receiver.put(receiver.type, v); v.anew(type); + v.dup(); // TODO typechecker must verify that we're the outer class of the instance being created //noinspection ConstantConditions - if (classDecl.getContainingDeclaration() instanceof ClassDescriptor) { - if(!receiver.type.equals(Type.VOID_TYPE)) { - // class object is in receiver - v.dupX1(); - v.swap(); - } - else { - // this$0 need to be put on stack - v.dup(); - v.load(0, typeMapper.mapType(classDecl.getDefaultType(), OwnerKind.IMPLEMENTATION)); - } - } - else { - // regular case - v.dup(); + if(!receiver.type.equals(Type.VOID_TYPE)) { + receiver.put(receiver.type, v); } CallableMethod method = typeMapper.mapToCallableMethod((ConstructorDescriptor) constructorDescriptor, OwnerKind.IMPLEMENTATION); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java b/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java index e83fd50e11e..8ddc2d7f5a1 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java @@ -140,7 +140,7 @@ public class GenerationState { closure.cv = nameAndVisitor.getSecond(); closure.name = nameAndVisitor.getFirst(); - final CodegenContext objectContext = closure.context.intoAnonymousClass(closure, getBindingContext().get(BindingContext.CLASS, objectDeclaration), OwnerKind.IMPLEMENTATION); + final CodegenContext objectContext = closure.context.intoAnonymousClass(closure, getBindingContext().get(BindingContext.CLASS, objectDeclaration), OwnerKind.IMPLEMENTATION, typeMapper); new ImplementationBodyCodegen(objectDeclaration, objectContext, nameAndVisitor.getSecond(), this).generate(null); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index d9a6678e5f2..5a552c69372 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -267,7 +267,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { ConstructorDescriptor constructorDescriptor = bindingContext.get(BindingContext.CONSTRUCTOR, myClass); - CodegenContext.ConstructorContext constructorContext = context.intoConstructor(constructorDescriptor); + CodegenContext.ConstructorContext constructorContext = context.intoConstructor(constructorDescriptor, typeMapper); Method constructorMethod; CallableMethod callableMethod; diff --git a/compiler/testData/codegen/classes/nonnullarray.jet b/compiler/testData/codegen/classes/nonnullarray.jet new file mode 100644 index 00000000000..2e480979e6b --- /dev/null +++ b/compiler/testData/codegen/classes/nonnullarray.jet @@ -0,0 +1,8 @@ +class A() { + class B(val i: Int) { + } + + fun test() = Array (10, { B(it) }) +} + +fun box() = if(A().test()[5].i == 5) "OK" else "fail" diff --git a/compiler/testData/codegen/regressions/kt694.jet b/compiler/testData/codegen/regressions/kt694.jet new file mode 100644 index 00000000000..698558d3642 --- /dev/null +++ b/compiler/testData/codegen/regressions/kt694.jet @@ -0,0 +1,9 @@ +namespace org2 + +enum class Test { + A + B + C +} + +fun box() = Test.A.toString() diff --git a/compiler/tests/org/jetbrains/jet/codegen/ArrayGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/ArrayGenTest.java index f5e8faf941a..5de65ac38f6 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/ArrayGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/ArrayGenTest.java @@ -286,4 +286,9 @@ public class ArrayGenTest extends CodegenTestCase { // System.out.println(generateToText()); blackBox(); } + + public void testNonNullArray() throws Exception { + blackBoxFile("classes/nonnullarray.jet"); + System.out.println(generateToText()); + } } diff --git a/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java index 1f300ca6406..d588a2b8207 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java @@ -1,5 +1,7 @@ package org.jetbrains.jet.codegen; +import org.jetbrains.jet.lang.psi.JetNamespace; + import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -216,6 +218,10 @@ public class ClassGenTest extends CodegenTestCase { blackBoxFile("regressions/kt500.jet"); } + public void testKt694 () throws Exception { + blackBoxFile("regressions/kt694.jet"); + } + public void testKt285 () throws Exception { // blackBoxFile("regressions/kt285.jet"); } diff --git a/examples/src/benchmarks/ThreadRing.java b/examples/src/benchmarks/ThreadRing.java new file mode 100644 index 00000000000..f4ffe660979 --- /dev/null +++ b/examples/src/benchmarks/ThreadRing.java @@ -0,0 +1,137 @@ +/** + * The Computer Language Benchmarks Game + * http://shootout.alioth.debian.org/ + * + * contributed by Fabien Le Floc'h + * + * Java implementation of thread-ring benchmark. Best performance is achieved with + * MAX_THREAD=1 as the thread-ring test is bested with only 1 os thread. + * This implementation shows using a simple thread pool solves the thread context + * switch issue. + */ + +import java.util.concurrent.*; + +public class ThreadRing { + private static final int MAX_NODES = 503; + private static final int MAX_THREADS = 503; + + private ExecutorService executor; + private final int N; + + static final CountDownLatch cdl = new CountDownLatch(1); + + public static void main(String[] args) throws InterruptedException { + long start = System.currentTimeMillis(); + int n = 5000000; + try { + n = Integer.parseInt(args[0]); + } catch (Exception e) {} + ThreadRing ring = new ThreadRing(n); + Node node = ring.start(MAX_NODES); + node.sendMessage(new TokenMessage(1,0)); + cdl.await(); + + long total = System.currentTimeMillis() - start; + System.out.println("[ThreadRing-" + System.getProperty("project.name")+ " Benchmark Result: " + total + "]"); + } + + public ThreadRing(int n) { + N = n; + } + + public Node start(int n) { + Node[] nodes = spawnNodes(n); + connectNodes(n, nodes); + return nodes[0]; + } + + private Node[] spawnNodes(int n) { + executor = Executors.newFixedThreadPool(MAX_THREADS); + Node[] nodes = new Node[n+1]; + for (int i = 0; i < n ; i++) { + nodes[i] = new Node(i+1, null); + } + return nodes; + } + + public void connectNodes(int n, Node[] nodes) { + nodes[n] = nodes[0]; + for (int i=0; i queue = new LinkedBlockingQueue(); + private boolean isActive = false; + private int counter; + + public Node(int id, Node nextNode) { + this.nodeId = id; + this.nextNode = nextNode; + this.counter = 0; + } + + public void connect(Node node) { + this.nextNode = node; + isActive = true; + } + + public void sendMessage(TokenMessage m) { + queue.add(m); + executor.execute(this); + } + + + public void run() { + if (isActive) { + try { + TokenMessage m = queue.take(); + if (m.isStop) { + int nextValue = m.value+1; + if (nextValue == MAX_NODES) { +// System.out.println("last one"); + executor.shutdown(); + cdl.countDown(); + } else { + m.value = nextValue; + nextNode.sendMessage(m); + } + isActive = false; +// System.out.println("ending node "+nodeId); + } else { + if (m.value == N) { + System.out.println(nodeId); + nextNode.sendMessage(new TokenMessage(nodeId, 0, true)); + } else { + m.value = m.value + 1; + nextNode.sendMessage(m); + } + } + } catch (InterruptedException ie) { + ie.printStackTrace(); + } + } + } + } +} \ No newline at end of file diff --git a/examples/src/benchmarks/ThreadRing.kt b/examples/src/benchmarks/ThreadRing.kt new file mode 100644 index 00000000000..17547adefdd --- /dev/null +++ b/examples/src/benchmarks/ThreadRing.kt @@ -0,0 +1,95 @@ +namespace threadring + +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; + +val MAX_NODES = 503 +val MAX_THREADS = 503 + +val cdl = CountDownLatch(1) + +fun main(args: Array) { + val start = System.currentTimeMillis() + var n = 5000000; + try { + n = Integer.parseInt(args[0]); + } catch (e: Throwable) { + } + + val ring = ThreadRing(n) + ring.sendMessage(TokenMessage(1,0,false)) + cdl.await(); + + val total = System.currentTimeMillis() - start + System.out?.println("[ThreadRing-" + System.getProperty("project.name")+ " Benchmark Result: " + total + "]") +} + +class TokenMessage(val nodeId : Int, value: Int, val isStop: Boolean) : AtomicInteger(value){ +} + +class ThreadRing(val N: Int) { + val executor = Executors.newFixedThreadPool(MAX_THREADS).sure() + + val nodes : Array = Array(MAX_NODES+1, { Node(it+1) }) + + { + connectNodes() + } + + fun connectNodes() { + nodes[nodes.size-1] = nodes[0] + for (i in 0..nodes.size-2) { + nodes[i].connect(nodes[i+1]); + } + } + + fun sendMessage(m : TokenMessage) { + nodes[0].sendMessage(m) + } + class Node(val nodeId : Int) : Runnable { + val queue = LinkedBlockingQueue() + var isActive = false + var nextNode : Node? = null + + fun sendMessage(m: TokenMessage) { + queue.add(m) + executor.execute(this) + } + + fun connect(next: Node) { + nextNode = next + isActive = true + } + + override fun run() { + if(isActive) { + try { + val m = queue.take() + if(m.isStop) { + val nextValue = m.get()+1 + if (nextValue == MAX_NODES) { + executor.shutdown() + cdl.countDown() + } else { + m.set(nextValue) + nextNode.sure().sendMessage(m) + } + isActive = false + } + else { + if (m.get() == N) { + System.out?.println(nodeId); + nextNode.sure().sendMessage(TokenMessage(nodeId, 0, true)); + } else { + m.incrementAndGet() + nextNode.sure().sendMessage(m); + } + } + } + catch(e: InterruptedException) { + e.printStackTrace() + } + } + } + } +}