LockPerf benchmark and related fixes (try/break/continue interoperability)
This commit is contained in:
@@ -43,9 +43,6 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
|||||||
private static final String CLASS_NO_PATTERN_MATCHED_EXCEPTION = "jet/NoPatternMatchedException";
|
private static final String CLASS_NO_PATTERN_MATCHED_EXCEPTION = "jet/NoPatternMatchedException";
|
||||||
private static final String CLASS_TYPE_CAST_EXCEPTION = "jet/TypeCastException";
|
private static final String CLASS_TYPE_CAST_EXCEPTION = "jet/TypeCastException";
|
||||||
|
|
||||||
private final Stack<Label> myContinueTargets = new Stack<Label>();
|
|
||||||
private final Stack<Label> myBreakTargets = new Stack<Label>();
|
|
||||||
|
|
||||||
private int myLastLineNumber = -1;
|
private int myLastLineNumber = -1;
|
||||||
|
|
||||||
final InstructionAdapter v;
|
final InstructionAdapter v;
|
||||||
@@ -60,7 +57,29 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
|||||||
private final CodegenContext context;
|
private final CodegenContext context;
|
||||||
private final IntrinsicMethods intrinsics;
|
private final IntrinsicMethods intrinsics;
|
||||||
|
|
||||||
private final ArrayList<JetTryExpression> stackOfFinallyBlocks = new ArrayList<JetTryExpression>();
|
private final Stack<BlockStackElement> blockStackElements = new Stack<BlockStackElement>();
|
||||||
|
|
||||||
|
static class BlockStackElement {
|
||||||
|
}
|
||||||
|
|
||||||
|
static class LoopBlockStackElement extends BlockStackElement {
|
||||||
|
final Label continueLabel;
|
||||||
|
final Label breakLabel;
|
||||||
|
|
||||||
|
LoopBlockStackElement(Label breakLabel, Label continueLabel) {
|
||||||
|
this.breakLabel = breakLabel;
|
||||||
|
this.continueLabel = continueLabel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class FinallyBlockStackElement extends BlockStackElement {
|
||||||
|
final JetTryExpression expression;
|
||||||
|
|
||||||
|
FinallyBlockStackElement(JetTryExpression expression) {
|
||||||
|
this.expression = expression;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public ExpressionCodegen(MethodVisitor v,
|
public ExpressionCodegen(MethodVisitor v,
|
||||||
FrameMap myMap,
|
FrameMap myMap,
|
||||||
@@ -225,11 +244,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
|||||||
@Override
|
@Override
|
||||||
public StackValue visitWhileExpression(JetWhileExpression expression, StackValue receiver) {
|
public StackValue visitWhileExpression(JetWhileExpression expression, StackValue receiver) {
|
||||||
Label condition = new Label();
|
Label condition = new Label();
|
||||||
myContinueTargets.push(condition);
|
|
||||||
v.mark(condition);
|
v.mark(condition);
|
||||||
|
|
||||||
Label end = continueLabel != null ? continueLabel : new Label();
|
Label end = continueLabel != null ? continueLabel : new Label();
|
||||||
myBreakTargets.push(end);
|
blockStackElements.push(new LoopBlockStackElement(end, condition));
|
||||||
|
|
||||||
Label savedContinueLabel = continueLabel;
|
Label savedContinueLabel = continueLabel;
|
||||||
continueLabel = condition;
|
continueLabel = condition;
|
||||||
@@ -243,8 +261,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
|||||||
continueLabel = savedContinueLabel;
|
continueLabel = savedContinueLabel;
|
||||||
if(end != continueLabel)
|
if(end != continueLabel)
|
||||||
v.mark(end);
|
v.mark(end);
|
||||||
myBreakTargets.pop();
|
|
||||||
myContinueTargets.pop();
|
blockStackElements.pop();
|
||||||
|
|
||||||
return StackValue.onStack(Type.VOID_TYPE);
|
return StackValue.onStack(Type.VOID_TYPE);
|
||||||
}
|
}
|
||||||
@@ -253,10 +271,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
|||||||
public StackValue visitDoWhileExpression(JetDoWhileExpression expression, StackValue receiver) {
|
public StackValue visitDoWhileExpression(JetDoWhileExpression expression, StackValue receiver) {
|
||||||
Label condition = new Label();
|
Label condition = new Label();
|
||||||
v.mark(condition);
|
v.mark(condition);
|
||||||
myContinueTargets.push(condition);
|
|
||||||
|
|
||||||
Label end = new Label();
|
Label end = new Label();
|
||||||
myBreakTargets.push(end);
|
|
||||||
|
blockStackElements.push(new LoopBlockStackElement(end, condition));
|
||||||
|
|
||||||
gen(expression.getBody(), Type.VOID_TYPE);
|
gen(expression.getBody(), Type.VOID_TYPE);
|
||||||
|
|
||||||
@@ -265,8 +283,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
|||||||
|
|
||||||
v.mark(end);
|
v.mark(end);
|
||||||
|
|
||||||
myBreakTargets.pop();
|
blockStackElements.pop();
|
||||||
myContinueTargets.pop();
|
|
||||||
return StackValue.onStack(Type.VOID_TYPE);
|
return StackValue.onStack(Type.VOID_TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,8 +345,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Label begin = new Label();
|
Label begin = new Label();
|
||||||
myContinueTargets.push(begin);
|
blockStackElements.push(new LoopBlockStackElement(end, begin));
|
||||||
myBreakTargets.push(end);
|
|
||||||
|
|
||||||
v.mark(begin);
|
v.mark(begin);
|
||||||
v.load(iteratorVar, asmIterType);
|
v.load(iteratorVar, asmIterType);
|
||||||
@@ -365,8 +381,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
|||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
v.visitLocalVariable(loopParameter.getName(), asmParamType.getDescriptor(), null, begin, end, paramIndex);
|
v.visitLocalVariable(loopParameter.getName(), asmParamType.getDescriptor(), null, begin, end, paramIndex);
|
||||||
myFrameMap.leaveTemp();
|
myFrameMap.leaveTemp();
|
||||||
myBreakTargets.pop();
|
|
||||||
myContinueTargets.pop();
|
blockStackElements.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
private OwnerKind contextKind() {
|
private OwnerKind contextKind() {
|
||||||
@@ -398,8 +414,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
|||||||
Label condition = new Label();
|
Label condition = new Label();
|
||||||
Label increment = new Label();
|
Label increment = new Label();
|
||||||
v.mark(condition);
|
v.mark(condition);
|
||||||
myContinueTargets.push(increment);
|
|
||||||
myBreakTargets.push(end);
|
blockStackElements.push(new LoopBlockStackElement(end, increment));
|
||||||
|
|
||||||
generateCondition(asmParamType, end);
|
generateCondition(asmParamType, end);
|
||||||
|
|
||||||
@@ -414,8 +430,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
|||||||
final int paramIndex = myFrameMap.leave(parameterDescriptor);
|
final int paramIndex = myFrameMap.leave(parameterDescriptor);
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
v.visitLocalVariable(expression.getLoopParameter().getName(), asmParamType.getDescriptor(), null, condition, end, paramIndex);
|
v.visitLocalVariable(expression.getLoopParameter().getName(), asmParamType.getDescriptor(), null, condition, end, paramIndex);
|
||||||
myBreakTargets.pop();
|
|
||||||
myContinueTargets.pop();
|
blockStackElements.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void generatePrologue() {
|
protected void generatePrologue() {
|
||||||
@@ -536,21 +552,51 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
|||||||
@Override
|
@Override
|
||||||
public StackValue visitBreakExpression(JetBreakExpression expression, StackValue receiver) {
|
public StackValue visitBreakExpression(JetBreakExpression expression, StackValue receiver) {
|
||||||
JetSimpleNameExpression labelElement = expression.getTargetLabel();
|
JetSimpleNameExpression labelElement = expression.getTargetLabel();
|
||||||
|
|
||||||
Label label = labelElement == null ? myBreakTargets.peek() : null; // TODO:
|
for(int i = blockStackElements.size()-1; i >= 0; --i) {
|
||||||
|
BlockStackElement stackElement = blockStackElements.get(i);
|
||||||
v.goTo(label);
|
if(stackElement instanceof FinallyBlockStackElement) {
|
||||||
return StackValue.none();
|
FinallyBlockStackElement finallyBlockStackElement = (FinallyBlockStackElement) stackElement;
|
||||||
|
JetTryExpression jetTryExpression = finallyBlockStackElement.expression;
|
||||||
|
gen(jetTryExpression.getFinallyBlock().getFinalExpression(), Type.VOID_TYPE);
|
||||||
|
}
|
||||||
|
else if(stackElement instanceof LoopBlockStackElement) {
|
||||||
|
LoopBlockStackElement loopBlockStackElement = (LoopBlockStackElement) stackElement;
|
||||||
|
Label label = labelElement == null ? loopBlockStackElement.breakLabel : null; // TODO:
|
||||||
|
v.goTo(label);
|
||||||
|
return StackValue.none();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StackValue visitContinueExpression(JetContinueExpression expression, StackValue receiver) {
|
public StackValue visitContinueExpression(JetContinueExpression expression, StackValue receiver) {
|
||||||
String labelName = expression.getLabelName();
|
JetSimpleNameExpression labelElement = expression.getTargetLabel();
|
||||||
|
|
||||||
Label label = labelName == null ? myContinueTargets.peek() : null; // TODO:
|
for(int i = blockStackElements.size()-1; i >= 0; --i) {
|
||||||
|
BlockStackElement stackElement = blockStackElements.get(i);
|
||||||
|
if(stackElement instanceof FinallyBlockStackElement) {
|
||||||
|
FinallyBlockStackElement finallyBlockStackElement = (FinallyBlockStackElement) stackElement;
|
||||||
|
JetTryExpression jetTryExpression = finallyBlockStackElement.expression;
|
||||||
|
gen(jetTryExpression.getFinallyBlock().getFinalExpression(), Type.VOID_TYPE);
|
||||||
|
}
|
||||||
|
else if(stackElement instanceof LoopBlockStackElement) {
|
||||||
|
LoopBlockStackElement loopBlockStackElement = (LoopBlockStackElement) stackElement;
|
||||||
|
Label label = labelElement == null ? loopBlockStackElement.continueLabel : null; // TODO:
|
||||||
|
v.goTo(label);
|
||||||
|
return StackValue.none();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
v.goTo(label);
|
throw new UnsupportedOperationException();
|
||||||
return StackValue.none();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private StackValue generateSingleBranchIf(StackValue condition, JetExpression expression, boolean inverse) {
|
private StackValue generateSingleBranchIf(StackValue condition, JetExpression expression, boolean inverse) {
|
||||||
@@ -763,12 +809,18 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void doFinallyOnReturnOrThrow() {
|
private void doFinallyOnReturnOrThrow() {
|
||||||
if(stackOfFinallyBlocks.size() > 0) {
|
for(int i = blockStackElements.size()-1; i >= 0; --i) {
|
||||||
JetTryExpression jetTryExpression = stackOfFinallyBlocks.remove(stackOfFinallyBlocks.size()-1);
|
BlockStackElement stackElement = blockStackElements.get(i);
|
||||||
//noinspection ConstantConditions
|
if(stackElement instanceof FinallyBlockStackElement) {
|
||||||
gen(jetTryExpression.getFinallyBlock().getFinalExpression(), Type.VOID_TYPE);
|
FinallyBlockStackElement finallyBlockStackElement = (FinallyBlockStackElement) stackElement;
|
||||||
doFinallyOnReturnOrThrow();
|
JetTryExpression jetTryExpression = finallyBlockStackElement.expression;
|
||||||
stackOfFinallyBlocks.add(jetTryExpression);
|
blockStackElements.pop();
|
||||||
|
gen(jetTryExpression.getFinallyBlock().getFinalExpression(), Type.VOID_TYPE);
|
||||||
|
blockStackElements.push(finallyBlockStackElement);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2208,9 +2260,12 @@ The "returned" value of try expression with no finally is either the last expres
|
|||||||
|
|
||||||
If finally block is present, its last expression is the value of try expression.
|
If finally block is present, its last expression is the value of try expression.
|
||||||
*/
|
*/
|
||||||
|
Label savedContinueLabel = continueLabel;
|
||||||
|
continueLabel = null;
|
||||||
|
|
||||||
JetFinallySection finallyBlock = expression.getFinallyBlock();
|
JetFinallySection finallyBlock = expression.getFinallyBlock();
|
||||||
if(finallyBlock != null) {
|
if(finallyBlock != null) {
|
||||||
stackOfFinallyBlocks.add(expression);
|
blockStackElements.push(new FinallyBlockStackElement(expression));
|
||||||
}
|
}
|
||||||
|
|
||||||
JetType jetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression);
|
JetType jetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression);
|
||||||
@@ -2267,9 +2322,11 @@ If finally block is present, its last expression is the value of try expression.
|
|||||||
v.nop();
|
v.nop();
|
||||||
|
|
||||||
if(finallyBlock != null) {
|
if(finallyBlock != null) {
|
||||||
stackOfFinallyBlocks.remove(stackOfFinallyBlocks.size()-1);
|
blockStackElements.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
continueLabel = savedContinueLabel;
|
||||||
|
|
||||||
return StackValue.onStack(expectedAsmType);
|
return StackValue.onStack(expectedAsmType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,12 +41,48 @@ fun test4() : Int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun test5() : Int {
|
||||||
|
var x = 0
|
||||||
|
System.out?.println("test 5")
|
||||||
|
while(true) {
|
||||||
|
System.out?.println(x)
|
||||||
|
try {
|
||||||
|
if(x < 10)
|
||||||
|
x++
|
||||||
|
else
|
||||||
|
break
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
x++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test6() : Int {
|
||||||
|
var x = 0
|
||||||
|
System.out?.println("test 6")
|
||||||
|
while(x < 10) {
|
||||||
|
System.out?.println(x)
|
||||||
|
try {
|
||||||
|
x++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
x++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
fun box() : String {
|
fun box() : String {
|
||||||
if(test1()) return "test1 failed"
|
if(test1()) return "test1 failed"
|
||||||
if(test2()) return "test2 failed"
|
if(test2()) return "test2 failed"
|
||||||
if(test3() != 2) return "test3 failed"
|
if(test3() != 2) return "test3 failed"
|
||||||
System.out?.println(test4())
|
System.out?.println(test4())
|
||||||
if(test4() != 3) return "test4 failed"
|
if(test4() != 3) return "test4 failed"
|
||||||
|
if(test5() != 11) return "test5 failed"
|
||||||
|
if(test6() != 10) return "test6 failed"
|
||||||
|
|
||||||
return "OK"
|
return "OK"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
|
public class LockPerf {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
int processors = Runtime.getRuntime().availableProcessors();
|
||||||
|
for (int threadNum = 1; threadNum <= 1024; threadNum = threadNum < 2 * processors ? threadNum + 1 : threadNum * 2) {
|
||||||
|
final AtomicInteger counter = new AtomicInteger();
|
||||||
|
final CountDownLatch cdl = new CountDownLatch(threadNum);
|
||||||
|
|
||||||
|
final ReentrantLock lock = new ReentrantLock();
|
||||||
|
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
for (int i = 0; i < threadNum; ++i) {
|
||||||
|
new Thread(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
for (;;) {
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
if (counter.get() == 100000000) {
|
||||||
|
cdl.countDown();
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
counter.incrementAndGet();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
cdl.await();
|
||||||
|
} catch (InterruptedException e) {//
|
||||||
|
}
|
||||||
|
System.out.println(threadNum + " " + (System.currentTimeMillis() - start));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
namespace lockperformance
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
|
fun thread(f: fun ()) {
|
||||||
|
val thread = Thread(
|
||||||
|
object: Runnable {
|
||||||
|
override fun run() {
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
thread.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
val processors = Runtime.getRuntime().sure().availableProcessors()
|
||||||
|
var threadNum = 1
|
||||||
|
while(threadNum <= 1024) {
|
||||||
|
val counter = AtomicInteger()
|
||||||
|
val cdl = CountDownLatch(threadNum)
|
||||||
|
val lock = ReentrantLock()
|
||||||
|
|
||||||
|
val start = System.currentTimeMillis()
|
||||||
|
for(i in 0..threadNum-1) {
|
||||||
|
thread {
|
||||||
|
while(true) {
|
||||||
|
lock.lock()
|
||||||
|
try {
|
||||||
|
if (counter.get() == 100000000) {
|
||||||
|
cdl.countDown();
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
counter.incrementAndGet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
lock.unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cdl.await()
|
||||||
|
|
||||||
|
System.out?.println(threadNum.toString() + " " + (System.currentTimeMillis() - start));
|
||||||
|
|
||||||
|
if(threadNum < 2 * processors)
|
||||||
|
threadNum = threadNum + 1
|
||||||
|
else
|
||||||
|
threadNum = threadNum * 2
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user