changeset 1328:1345ad5a0155

7901735: JMH infrastructure classes (Blackhole, *Params, Control) should be treated specially
author shade
date Tue, 19 Jul 2016 21:57:50 +0300
parents c050a47b2b37
children 2d0b2fd926fb
files jmh-core-it/src/test/java/org/openjdk/jmh/it/infraparams/BenchmarkParamsTest.java jmh-core-it/src/test/java/org/openjdk/jmh/it/infraparams/IterationParamsTest.java jmh-core-it/src/test/java/org/openjdk/jmh/it/infraparams/ThreadParamsTest.java jmh-core/src/main/java/org/openjdk/jmh/generators/core/BenchmarkGenerator.java jmh-core/src/main/java/org/openjdk/jmh/generators/core/StateObjectHandler.java jmh-core/src/main/java/org/openjdk/jmh/infra/BenchmarkParams.java jmh-core/src/main/java/org/openjdk/jmh/infra/Blackhole.java jmh-core/src/main/java/org/openjdk/jmh/infra/Control.java jmh-core/src/main/java/org/openjdk/jmh/infra/IterationParams.java jmh-core/src/main/java/org/openjdk/jmh/infra/ThreadParams.java jmh-core/src/test/java/org/openjdk/jmh/BlackholeTest.java
diffstat 11 files changed, 420 insertions(+), 291 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/infraparams/BenchmarkParamsTest.java	Tue Jul 19 21:57:50 2016 +0300
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jmh.it.infraparams;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.infra.BenchmarkParams;
+import org.openjdk.jmh.it.Fixtures;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.CommandLineOptionException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+import org.openjdk.jmh.runner.options.TimeValue;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.IdentityHashMap;
+
+@State(Scope.Thread)
+public class BenchmarkParamsTest {
+
+    Collection<BenchmarkParams> set;
+
+    @Setup(Level.Iteration)
+    public void setup() {
+        set = Collections.synchronizedSet(Collections.newSetFromMap(new IdentityHashMap<BenchmarkParams, Boolean>()));
+    }
+
+    @TearDown(Level.Iteration)
+    public void verify() {
+        Assert.assertEquals(1, set.size());
+    }
+
+    @Benchmark
+    @Threads(4)
+    public void test(BenchmarkParams params) {
+        set.add(params);
+        Fixtures.work();
+    }
+
+    @Test
+    public void test() throws RunnerException, CommandLineOptionException {
+        Options opts = new OptionsBuilder()
+                .include(Fixtures.getTestMask(this.getClass()))
+                .warmupIterations(5)
+                .warmupTime(TimeValue.seconds(1))
+                .measurementIterations(5)
+                .measurementTime(TimeValue.seconds(1))
+                .forks(1)
+                .shouldFailOnError(true)
+                .build();
+
+        new Runner(opts).run();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/infraparams/IterationParamsTest.java	Tue Jul 19 21:57:50 2016 +0300
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jmh.it.infraparams;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.infra.IterationParams;
+import org.openjdk.jmh.it.Fixtures;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.CommandLineOptionException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+import org.openjdk.jmh.runner.options.TimeValue;
+
+import java.util.Collections;
+import java.util.IdentityHashMap;
+import java.util.Set;
+
+@State(Scope.Benchmark)
+public class IterationParamsTest {
+
+    Set<IterationParams> set;
+
+    @Setup(Level.Iteration)
+    public void setup() {
+        set = Collections.synchronizedSet(Collections.newSetFromMap(new IdentityHashMap<IterationParams, Boolean>()));
+    }
+
+    @TearDown(Level.Iteration)
+    public void verify() {
+        Assert.assertEquals(1, set.size());
+    }
+
+    @Benchmark
+    @Threads(4)
+    public void test(IterationParams params) {
+        set.add(params);
+        Fixtures.work();
+    }
+
+    @Test
+    public void test() throws RunnerException, CommandLineOptionException {
+        Options opts = new OptionsBuilder()
+                .include(Fixtures.getTestMask(this.getClass()))
+                .warmupIterations(5)
+                .warmupTime(TimeValue.seconds(1))
+                .measurementIterations(5)
+                .measurementTime(TimeValue.seconds(1))
+                .forks(1)
+                .shouldFailOnError(true)
+                .build();
+
+        new Runner(opts).run();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/infraparams/ThreadParamsTest.java	Tue Jul 19 21:57:50 2016 +0300
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jmh.it.infraparams;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.infra.ThreadParams;
+import org.openjdk.jmh.it.Fixtures;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.*;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.IdentityHashMap;
+
+@State(Scope.Benchmark)
+public class ThreadParamsTest {
+
+    Collection<ThreadParams> set;
+
+    @Setup(Level.Iteration)
+    public void setup() {
+        set = Collections.synchronizedSet(Collections.newSetFromMap(new IdentityHashMap<ThreadParams, Boolean>()));
+    }
+
+    @TearDown(Level.Iteration)
+    public void verify() {
+        Assert.assertEquals(4, set.size());
+    }
+
+    @Benchmark
+    @Threads(4)
+    public void test(ThreadParams params) {
+        set.add(params);
+        Fixtures.work();
+    }
+
+    @Test
+    public void test() throws RunnerException, CommandLineOptionException {
+        Options opts = new OptionsBuilder()
+                .include(Fixtures.getTestMask(this.getClass()))
+                .warmupIterations(5)
+                .warmupTime(TimeValue.seconds(1))
+                .measurementIterations(5)
+                .measurementTime(TimeValue.seconds(1))
+                .forks(1)
+                .shouldFailOnError(true)
+                .build();
+
+        new Runner(opts).run();
+    }
+
+}
--- a/jmh-core/src/main/java/org/openjdk/jmh/generators/core/BenchmarkGenerator.java	Wed Jul 13 19:35:00 2016 +0300
+++ b/jmh-core/src/main/java/org/openjdk/jmh/generators/core/BenchmarkGenerator.java	Tue Jul 19 21:57:50 2016 +0300
@@ -25,10 +25,7 @@
 package org.openjdk.jmh.generators.core;
 
 import org.openjdk.jmh.annotations.*;
-import org.openjdk.jmh.infra.BenchmarkParams;
-import org.openjdk.jmh.infra.Blackhole;
-import org.openjdk.jmh.infra.IterationParams;
-import org.openjdk.jmh.infra.ThreadParams;
+import org.openjdk.jmh.infra.*;
 import org.openjdk.jmh.results.*;
 import org.openjdk.jmh.runner.BenchmarkList;
 import org.openjdk.jmh.runner.BenchmarkListEntry;
@@ -467,9 +464,6 @@
         // benchmark instance is implicit
         states.bindImplicit(classInfo, "bench", Scope.Thread);
 
-        // default blackhole is implicit
-        states.bindImplicit(source.resolveClass(Blackhole.class.getCanonicalName()), "blackhole", Scope.Thread);
-
         // bind all methods
         states.bindMethodGroup(info.methodGroup);
 
@@ -491,6 +485,11 @@
         Paddings.padding(writer);
 
         writer.println(ident(1) + "int startRndMask;");
+        writer.println(ident(1) + "BenchmarkParams benchmarkParams;");
+        writer.println(ident(1) + "IterationParams iterationParams;");
+        writer.println(ident(1) + "ThreadParams threadParams;");
+        writer.println(ident(1) + "Blackhole blackhole;");
+        writer.println(ident(1) + "Control notifyControl;");
 
         // write all methods
         for (Mode benchmarkKind : Mode.values()) {
@@ -531,7 +530,8 @@
                 SampleTimeResult.class, SingleShotResult.class, SampleBuffer.class,
                 Mode.class, Fork.class, Measurement.class, Threads.class, Warmup.class,
                 BenchmarkMode.class, RawResults.class, ResultRole.class,
-                Field.class, BenchmarkParams.class, IterationParams.class
+                Field.class, BenchmarkParams.class, IterationParams.class,
+                Blackhole.class, Control.class
         };
 
         for (Class<?> c : imports) {
@@ -594,18 +594,14 @@
             writer.println();
 
             // control objects get a special treatment
-            for (StateObject so : states.getControls()) {
-                writer.println(ident(3) + so.localIdentifier + ".startMeasurement = true;");
-            }
+            writer.println(ident(3) + "notifyControl.startMeasurement = true;");
 
             // measurement loop call
             writer.println(ident(3) + method.getName() + "_" + benchmarkKind.shortLabel() + JMH_STUB_SUFFIX +
-                    "(control, res" + prefix(states.getArgList(method)) + ");");
+                    "(" + getStubArgs() + prefix(states.getArgList(method)) + ");");
 
             // control objects get a special treatment
-            for (StateObject so : states.getControls()) {
-                writer.println(ident(3) + so.localIdentifier + ".stopMeasurement = true;");
-            }
+            writer.println(ident(3) + "notifyControl.stopMeasurement = true;");
 
             // synchronize iterations epilog: announce ready
             writer.println(ident(3) + "control.announceWarmdownReady();");
@@ -641,8 +637,8 @@
                It's prudent to make the multiplication first to get more accuracy.
              */
 
-            writer.println(ident(3) + "int batchSize = control.iterationParams.getBatchSize();");
-            writer.println(ident(3) + "int opsPerInv = control.benchmarkParams.getOpsPerInvocation();");
+            writer.println(ident(3) + "int batchSize = iterationParams.getBatchSize();");
+            writer.println(ident(3) + "int opsPerInv = benchmarkParams.getOpsPerInvocation();");
 
             writer.println(ident(3) + "res.allOps *= opsPerInv;");
             writer.println(ident(3) + "res.allOps /= batchSize;");
@@ -650,13 +646,16 @@
             writer.println(ident(3) + "res.measuredOps /= batchSize;");
 
             writer.println(ident(3) + "BenchmarkTaskResult results = new BenchmarkTaskResult(res.allOps, res.measuredOps);");
-            writer.println(ident(3) + "results.add(new ThroughputResult(ResultRole.PRIMARY, \"" + method.getName() + "\", res.measuredOps, res.getTime(), control.benchmarkParams.getTimeUnit()));");
+            writer.println(ident(3) + "results.add(new ThroughputResult(ResultRole.PRIMARY, \"" + method.getName() + "\", res.measuredOps, res.getTime(), benchmarkParams.getTimeUnit()));");
             if (!isSingleMethod) {
-                writer.println(ident(3) + "results.add(new ThroughputResult(ResultRole.SECONDARY, \"" + method.getName() + "\", res.measuredOps, res.getTime(), control.benchmarkParams.getTimeUnit()));");
+                writer.println(ident(3) + "results.add(new ThroughputResult(ResultRole.SECONDARY, \"" + method.getName() + "\", res.measuredOps, res.getTime(), benchmarkParams.getTimeUnit()));");
             }
             for (String ops : states.getAuxResultNames(method)) {
-                writer.println(ident(3) + "results.add(new ThroughputResult(ResultRole.SECONDARY, \"" + ops + "\", " + states.getAuxResultAccessor(method, ops) + ", res.getTime(), control.benchmarkParams.getTimeUnit()));");
+                writer.println(ident(3) + "results.add(new ThroughputResult(ResultRole.SECONDARY, \"" + ops + "\", " + states.getAuxResultAccessor(method, ops) + ", res.getTime(), benchmarkParams.getTimeUnit()));");
             }
+
+            methodEpilog(writer, methodGroup);
+
             writer.println(ident(3) + "return results;");
             writer.println(ident(2) + "} else");
         }
@@ -671,7 +670,8 @@
 
             compilerControl.defaultForceInline(method);
 
-            writer.println(ident(1) + "public" + (methodGroup.isStrictFP() ? " strictfp" : "") + " void " + methodName + "(InfraControl control, RawResults result" + prefix(states.getTypeArgList(method)) + ") throws Throwable {");
+            writer.println(ident(1) + "public static" + (methodGroup.isStrictFP() ? " strictfp" : "") + " void " + methodName + "(" +
+                    getStubTypeArgs() + prefix(states.getTypeArgList(method)) + ") throws Throwable {");
             writer.println(ident(2) + "long operations = 0;");
             writer.println(ident(2) + "long realTime = 0;");
             writer.println(ident(2) + "result.startTime = System.nanoTime();");
@@ -722,17 +722,13 @@
             writer.println();
 
             // control objects get a special treatment
-            for (StateObject so : states.getControls()) {
-                writer.println(ident(3) + so.localIdentifier + ".startMeasurement = true;");
-            }
+            writer.println(ident(3) + "notifyControl.startMeasurement = true;");
 
             // measurement loop call
-            writer.println(ident(3) + method.getName() + "_" + benchmarkKind.shortLabel() + JMH_STUB_SUFFIX + "(control, res" + prefix(states.getArgList(method)) + ");");
+            writer.println(ident(3) + method.getName() + "_" + benchmarkKind.shortLabel() + JMH_STUB_SUFFIX + "(" + getStubArgs() + prefix(states.getArgList(method)) + ");");
 
             // control objects get a special treatment
-            for (StateObject so : states.getControls()) {
-                writer.println(ident(3) + so.localIdentifier + ".stopMeasurement = true;");
-            }
+            writer.println(ident(3) + "notifyControl.stopMeasurement = true;");
 
             // synchronize iterations epilog: announce ready
             writer.println(ident(3) + "control.announceWarmdownReady();");
@@ -767,8 +763,8 @@
                It's prudent to make the multiplication first to get more accuracy.
              */
 
-            writer.println(ident(3) + "int batchSize = control.iterationParams.getBatchSize();");
-            writer.println(ident(3) + "int opsPerInv = control.benchmarkParams.getOpsPerInvocation();");
+            writer.println(ident(3) + "int batchSize = iterationParams.getBatchSize();");
+            writer.println(ident(3) + "int opsPerInv = benchmarkParams.getOpsPerInvocation();");
 
             writer.println(ident(3) + "res.allOps *= opsPerInv;");
             writer.println(ident(3) + "res.allOps /= batchSize;");
@@ -776,13 +772,15 @@
             writer.println(ident(3) + "res.measuredOps /= batchSize;");
 
             writer.println(ident(3) + "BenchmarkTaskResult results = new BenchmarkTaskResult(res.allOps, res.measuredOps);");
-            writer.println(ident(3) + "results.add(new AverageTimeResult(ResultRole.PRIMARY, \"" + method.getName() + "\", res.measuredOps, res.getTime(), control.benchmarkParams.getTimeUnit()));");
+            writer.println(ident(3) + "results.add(new AverageTimeResult(ResultRole.PRIMARY, \"" + method.getName() + "\", res.measuredOps, res.getTime(), benchmarkParams.getTimeUnit()));");
             if (!isSingleMethod) {
-                writer.println(ident(3) + "results.add(new AverageTimeResult(ResultRole.SECONDARY, \"" + method.getName() + "\", res.measuredOps, res.getTime(), control.benchmarkParams.getTimeUnit()));");
+                writer.println(ident(3) + "results.add(new AverageTimeResult(ResultRole.SECONDARY, \"" + method.getName() + "\", res.measuredOps, res.getTime(), benchmarkParams.getTimeUnit()));");
             }
             for (String ops : states.getAuxResultNames(method)) {
-                writer.println(ident(3) + "results.add(new AverageTimeResult(ResultRole.SECONDARY, \"" + ops + "\", " + states.getAuxResultAccessor(method, ops) + ", res.getTime(), control.benchmarkParams.getTimeUnit()));");
+                writer.println(ident(3) + "results.add(new AverageTimeResult(ResultRole.SECONDARY, \"" + ops + "\", " + states.getAuxResultAccessor(method, ops) + ", res.getTime(), benchmarkParams.getTimeUnit()));");
             }
+            methodEpilog(writer, methodGroup);
+
             writer.println(ident(3) + "return results;");
             writer.println(ident(2) + "} else");
         }
@@ -796,8 +794,8 @@
             String methodName = method.getName() + "_" + benchmarkKind.shortLabel() + JMH_STUB_SUFFIX;
             compilerControl.defaultForceInline(method);
 
-            writer.println(ident(1) + "public" + (methodGroup.isStrictFP() ? " strictfp" : "") + " void " + methodName +
-                    "(InfraControl control, RawResults result" + prefix(states.getTypeArgList(method)) + ") throws Throwable {");
+            writer.println(ident(1) + "public static" + (methodGroup.isStrictFP() ? " strictfp" : "") + " void " + methodName +
+                    "(" + getStubTypeArgs() + prefix(states.getTypeArgList(method)) + ") throws Throwable {");
             writer.println(ident(2) + "long operations = 0;");
             writer.println(ident(2) + "long realTime = 0;");
             writer.println(ident(2) + "result.startTime = System.nanoTime();");
@@ -817,8 +815,27 @@
         }
     }
 
+    private String getStubArgs() {
+        return "control, res, benchmarkParams, iterationParams, threadParams, blackhole, notifyControl, startRndMask";
+    }
+
+    private String getStubTypeArgs() {
+        return "InfraControl control, RawResults result, " +
+                "BenchmarkParams benchmarkParams, IterationParams iterationParams, ThreadParams threadParams, " +
+                "Blackhole blackhole, Control notifyControl, int startRndMask";
+    }
+
     private void methodProlog(PrintWriter writer, MethodGroup methodGroup) {
         // do nothing
+        writer.println(ident(2) + "this.benchmarkParams = control.benchmarkParams;");
+        writer.println(ident(2) + "this.iterationParams = control.iterationParams;");
+        writer.println(ident(2) + "this.threadParams    = threadParams;");
+        writer.println(ident(2) + "this.notifyControl   = new Control();");
+        writer.println(ident(2) + "this.blackhole       = new Blackhole(\"Today's password is swordfish. I understand instantiating Blackholes directly is dangerous.\");");
+    }
+
+    private void methodEpilog(PrintWriter writer, MethodGroup methodGroup) {
+        writer.println(ident(3) + "this.blackhole = null;");
     }
 
     private String prefix(String argList) {
@@ -860,21 +877,18 @@
             writer.println();
 
             // control objects get a special treatment
-            for (StateObject so : states.getControls()) {
-                writer.println(ident(3) + so.localIdentifier + ".startMeasurement = true;");
-            }
+            writer.println(ident(3) + "notifyControl.startMeasurement = true;");
 
             // measurement loop call
             writer.println(ident(3) + "int targetSamples = (int) (control.getDuration(TimeUnit.MILLISECONDS) * 20); // at max, 20 timestamps per millisecond");
-            writer.println(ident(3) + "int batchSize = control.iterationParams.getBatchSize();");
-            writer.println(ident(3) + "int opsPerInv = control.benchmarkParams.getOpsPerInvocation();");
+            writer.println(ident(3) + "int batchSize = iterationParams.getBatchSize();");
+            writer.println(ident(3) + "int opsPerInv = benchmarkParams.getOpsPerInvocation();");
             writer.println(ident(3) + "SampleBuffer buffer = new SampleBuffer();");
-            writer.println(ident(3) + method.getName() + "_" + benchmarkKind.shortLabel() + JMH_STUB_SUFFIX + "(control, res, buffer, targetSamples, opsPerInv, batchSize" + prefix(states.getArgList(method)) + ");");
+            writer.println(ident(3) + method.getName() + "_" + benchmarkKind.shortLabel() + JMH_STUB_SUFFIX + "(" +
+                    getStubArgs() + ", buffer, targetSamples, opsPerInv, batchSize" + prefix(states.getArgList(method)) + ");");
 
             // control objects get a special treatment
-            for (StateObject so : states.getControls()) {
-                writer.println(ident(3) + so.localIdentifier + ".stopMeasurement = true;");
-            }
+            writer.println(ident(3) + "notifyControl.stopMeasurement = true;");
 
             // synchronize iterations epilog: announce ready
             writer.println(ident(3) + "control.announceWarmdownReady();");
@@ -912,10 +926,12 @@
             writer.println(ident(3) + "res.measuredOps *= opsPerInv;");
 
             writer.println(ident(3) + "BenchmarkTaskResult results = new BenchmarkTaskResult(res.allOps, res.measuredOps);");
-            writer.println(ident(3) + "results.add(new SampleTimeResult(ResultRole.PRIMARY, \"" + method.getName() + "\", buffer, control.benchmarkParams.getTimeUnit()));");
+            writer.println(ident(3) + "results.add(new SampleTimeResult(ResultRole.PRIMARY, \"" + method.getName() + "\", buffer, benchmarkParams.getTimeUnit()));");
             if (!isSingleMethod) {
-                writer.println(ident(3) + "results.add(new SampleTimeResult(ResultRole.SECONDARY, \"" + method.getName() + "\", buffer, control.benchmarkParams.getTimeUnit()));");
+                writer.println(ident(3) + "results.add(new SampleTimeResult(ResultRole.SECONDARY, \"" + method.getName() + "\", buffer, benchmarkParams.getTimeUnit()));");
             }
+            methodEpilog(writer, methodGroup);
+
             writer.println(ident(3) + "return results;");
             writer.println(ident(2) + "} else");
         }
@@ -929,7 +945,9 @@
             String methodName = method.getName() + "_" + benchmarkKind.shortLabel() + JMH_STUB_SUFFIX;
             compilerControl.defaultForceInline(method);
 
-            writer.println(ident(1) + "public" + (methodGroup.isStrictFP() ? " strictfp" : "") + " void " + methodName + "(InfraControl control, RawResults result, SampleBuffer buffer, int targetSamples, long opsPerInv, int batchSize" + prefix(states.getTypeArgList(method)) + ") throws Throwable {");
+            writer.println(ident(1) + "public static" + (methodGroup.isStrictFP() ? " strictfp" : "") + " void " + methodName + "(" +
+                    getStubTypeArgs() + ", SampleBuffer buffer, int targetSamples, long opsPerInv, int batchSize" + prefix(states.getTypeArgList(method)) + ") throws Throwable {");
+
             writer.println(ident(2) + "long realTime = 0;");
             writer.println(ident(2) + "long operations = 0;");
             writer.println(ident(2) + "int rnd = (int)System.nanoTime();");
@@ -991,8 +1009,9 @@
 
             // measurement loop call
             writer.println(ident(3) + "RawResults res = new RawResults();");
-            writer.println(ident(3) + "int batchSize = control.iterationParams.getBatchSize();");
-            writer.println(ident(3) + method.getName() + "_" + benchmarkKind.shortLabel() + JMH_STUB_SUFFIX + "(control, batchSize, res" + prefix(states.getArgList(method)) + ");");
+            writer.println(ident(3) + "int batchSize = iterationParams.getBatchSize();");
+            writer.println(ident(3) + method.getName() + "_" + benchmarkKind.shortLabel() + JMH_STUB_SUFFIX + "(" +
+                    getStubArgs() + ", batchSize" + prefix(states.getArgList(method)) + ");");
 
             writer.println(ident(3) + "control.preTearDown();");
 
@@ -1009,10 +1028,12 @@
             writer.println(ident(3) + "long totalOps = opsPerInv;");
 
             writer.println(ident(3) + "BenchmarkTaskResult results = new BenchmarkTaskResult(totalOps, totalOps);");
-            writer.println(ident(3) + "results.add(new SingleShotResult(ResultRole.PRIMARY, \"" + method.getName() + "\", res.getTime(), control.benchmarkParams.getTimeUnit()));");
+            writer.println(ident(3) + "results.add(new SingleShotResult(ResultRole.PRIMARY, \"" + method.getName() + "\", res.getTime(), benchmarkParams.getTimeUnit()));");
             if (!isSingleMethod) {
-                writer.println(ident(3) + "results.add(new SingleShotResult(ResultRole.SECONDARY, \"" + method.getName() + "\", res.getTime(), control.benchmarkParams.getTimeUnit()));");
+                writer.println(ident(3) + "results.add(new SingleShotResult(ResultRole.SECONDARY, \"" + method.getName() + "\", res.getTime(), benchmarkParams.getTimeUnit()));");
             }
+            methodEpilog(writer, methodGroup);
+
             writer.println(ident(3) + "return results;");
             writer.println(ident(2) + "} else");
         }
@@ -1026,8 +1047,8 @@
             String methodName = method.getName() + "_" + benchmarkKind.shortLabel() + JMH_STUB_SUFFIX;
             compilerControl.defaultForceInline(method);
 
-            writer.println(ident(1) + "public" + (methodGroup.isStrictFP() ? " strictfp" : "") + " void " + methodName +
-                    "(InfraControl control, int batchSize, RawResults result" + prefix(states.getTypeArgList(method)) + ") throws Throwable {");
+            writer.println(ident(1) + "public static" + (methodGroup.isStrictFP() ? " strictfp" : "") + " void " + methodName +
+                    "(" + getStubTypeArgs() + ", int batchSize" + prefix(states.getTypeArgList(method)) + ") throws Throwable {");
 
             writer.println(ident(2) + "long realTime = 0;");
             writer.println(ident(2) + "result.startTime = System.nanoTime();");
@@ -1090,7 +1111,7 @@
         if ("void".equalsIgnoreCase(method.getReturnType())) {
             return states.getImplicit("bench").localIdentifier + "." + method.getName() + "(" + states.getBenchmarkArgList(method) + ")";
         } else {
-            return states.getImplicit("blackhole").localIdentifier + ".consume(" + states.getImplicit("bench").localIdentifier + "." + method.getName() + "(" + states.getBenchmarkArgList(method) + "))";
+            return "blackhole.consume(" + states.getImplicit("bench").localIdentifier + "." + method.getName() + "(" + states.getBenchmarkArgList(method) + "))";
         }
     }
 
--- a/jmh-core/src/main/java/org/openjdk/jmh/generators/core/StateObjectHandler.java	Wed Jul 13 19:35:00 2016 +0300
+++ b/jmh-core/src/main/java/org/openjdk/jmh/generators/core/StateObjectHandler.java	Tue Jul 19 21:57:50 2016 +0300
@@ -25,12 +25,10 @@
 package org.openjdk.jmh.generators.core;
 
 import org.openjdk.jmh.annotations.*;
-import org.openjdk.jmh.infra.BenchmarkParams;
-import org.openjdk.jmh.infra.Control;
-import org.openjdk.jmh.infra.IterationParams;
-import org.openjdk.jmh.infra.ThreadParams;
+import org.openjdk.jmh.infra.*;
 import org.openjdk.jmh.util.HashMultimap;
 import org.openjdk.jmh.util.Multimap;
+import org.openjdk.jmh.util.Utils;
 
 import java.io.IOException;
 import java.io.PrintWriter;
@@ -45,21 +43,27 @@
 
     private final Identifiers identifiers;
 
-    private final Multimap<String, StateObject> args;
-    private final Multimap<String, StateObject> stateHelperArgs;
+    private final Multimap<String, StateObject> roots;
+    private final Multimap<String, ClassInfo> specials;
+
+    private final Set<StateObject> stateObjects;
+    private final Map<String, StateObject> implicits;
     private final Multimap<StateObject, StateObject> stateObjectDeps;
-    private final Map<String, StateObject> implicits;
-    private final Set<StateObject> stateObjects;
+
+    private final Multimap<String, String> benchmarkArgs;
+    private final Multimap<String, String> stateHelperArgs;
 
     private final Multimap<String, String> auxNames = new HashMultimap<String, String>();
     private final Map<String, String> auxAccessors = new HashMap<String, String>();
 
     public StateObjectHandler(CompilerControlPlugin compileControl) {
         this.compileControl = compileControl;
-        this.args = new HashMultimap<String, StateObject>();
+        this.roots = new HashMultimap<String, StateObject>();
+        this.benchmarkArgs = new HashMultimap<String, String>();
         this.implicits = new HashMap<String, StateObject>();
+        this.specials = new HashMultimap<String, ClassInfo>();
         this.stateObjects = new HashSet<StateObject>();
-        this.stateHelperArgs = new HashMultimap<String, StateObject>();
+        this.stateHelperArgs = new HashMultimap<String, String>();
         this.stateObjectDeps = new HashMultimap<StateObject, StateObject>();
         this.identifiers = new Identifiers();
     }
@@ -129,27 +133,43 @@
         // check @Setup/@TearDown have only @State arguments
         for (MethodInfo mi : BenchmarkGeneratorUtils.getAllMethods(state)) {
             if (mi.getAnnotation(Setup.class) != null || mi.getAnnotation(TearDown.class) != null) {
-                for (ParameterInfo var : mi.getParameters()) {
-                    if (BenchmarkGeneratorUtils.getAnnSuper(var.getType(), State.class) == null) {
-                        throw new GenerationException(
-                                "Method parameters should be @" + State.class.getSimpleName() + " classes.",
-                                mi);
-                    }
-                }
+                validateStateArgs(mi);
             }
         }
     }
 
     public static void validateStateArgs(MethodInfo e) {
         for (ParameterInfo var : e.getParameters()) {
-            if (BenchmarkGeneratorUtils.getAnnSuper(var.getType(), State.class) == null) {
-                throw new GenerationException(
-                        "Method parameters should be @" + State.class.getSimpleName() + " classes.",
+            if (BenchmarkGeneratorUtils.getAnnSuper(var.getType(), State.class) != null) continue;
+            if (isSpecialClass(var.getType())) continue;
+
+            throw new GenerationException(
+                        "Method parameters should be either @" + State.class.getSimpleName() + " classes", // TODO: Change the message
                         e);
-            }
         }
     }
 
+    private static boolean isSpecialClass(ClassInfo ci) {
+        String name = ci.getQualifiedName();
+        return
+                name.equals(BenchmarkParams.class.getCanonicalName()) ||
+                name.equals(IterationParams.class.getCanonicalName()) ||
+                name.equals(ThreadParams.class.getCanonicalName()) ||
+                name.equals(Blackhole.class.getCanonicalName()) ||
+                name.equals(Control.class.getCanonicalName())
+                ;
+    }
+
+    private String getSpecialClassAccessor(ClassInfo pci) {
+        String name = pci.getQualifiedName();
+        if (name.equals(BenchmarkParams.class.getCanonicalName()))  return "benchmarkParams";
+        if (name.equals(IterationParams.class.getCanonicalName()))  return "iterationParams";
+        if (name.equals(ThreadParams.class.getCanonicalName()))     return "threadParams";
+        if (name.equals(Blackhole.class.getCanonicalName()))        return "blackhole";
+        if (name.equals(Control.class.getCanonicalName()))          return "notifyControl";
+        throw new GenerationException("Internal error, unhandled special class: " + pci, pci);
+    }
+
     public State getState(ClassInfo ci, ParameterInfo pi) {
         State ann = BenchmarkGeneratorUtils.getAnnSuper(ci, State.class);
         if (ann == null) {
@@ -168,14 +188,20 @@
             for (ParameterInfo ppi : method.getParameters()) {
                 ClassInfo pci = ppi.getType();
 
-                StateObject pso = new StateObject(identifiers, pci, getState(pci, ppi).value());
-                stateObjects.add(pso);
-                args.put(method.getName(), pso);
-                bindState(method, pso, pci);
+                if (isSpecialClass(pci)) {
+                    benchmarkArgs.put(method.getName(), getSpecialClassAccessor(pci));
+                    specials.put(method.getName(), pci);
+                } else {
+                    StateObject pso = new StateObject(identifiers, pci, getState(pci, ppi).value());
+                    stateObjects.add(pso);
+                    roots.put(method.getName(), pso);
+                    benchmarkArgs.put(method.getName(), pso.toLocal());
+                    bindState(method, pso, pci);
 
-                seen.add(pso);
+                    seen.add(pso);
 
-                recursiveStateResolve(method, pci, pso, seen);
+                    recursiveStateResolve(method, pci, pso, seen);
+                }
             }
         }
     }
@@ -190,24 +216,30 @@
                 for (ParameterInfo pi : mi.getParameters()) {
                     ClassInfo ci = pi.getType();
 
-                    StateObject so = new StateObject(identifiers, ci, getState(ci, pi).value());
+                    if (isSpecialClass(ci)) {
+                        stateHelperArgs.put(mi.getQualifiedName(), getSpecialClassAccessor(ci));
+                        specials.put(mi.getQualifiedName(), ci);
+                    } else {
+                        StateObject so = new StateObject(identifiers, ci, getState(ci, pi).value());
 
-                    if (!seen.add(so)) {
-                        throw new GenerationException("@" + State.class.getSimpleName() + " dependency cycle is detected.", pi);
-                    }
+                        if (!seen.add(so)) {
+                            throw new GenerationException("@" + State.class.getSimpleName() + " dependency cycle is detected.", pi);
+                        }
 
-                    if (!stateHelperArgs.get(mi.getQualifiedName()).contains(so)) {
-                        stateObjects.add(so);
-                        stateObjectDeps.put(pso, so);
-                        stateHelperArgs.put(mi.getQualifiedName(), so);
-                        bindState(method, so, ci);
-                        recursiveStateResolve(method, ci, so, seen);
+                        if (!stateHelperArgs.get(mi.getQualifiedName()).contains(so.toLocal())) {
+                            stateObjects.add(so);
+                            stateObjectDeps.put(pso, so);
+                            stateHelperArgs.put(mi.getQualifiedName(), so.toLocal());
+                            bindState(method, so, ci);
+                            recursiveStateResolve(method, ci, so, seen);
+                        }
                     }
                 }
             }
         }
     }
 
+
     public void bindImplicit(ClassInfo ci, String label, Scope scope) {
         State ann = BenchmarkGeneratorUtils.getAnnSuper(ci, State.class);
         StateObject so = new StateObject(identifiers, ci, (ann != null) ? ann.value() : scope);
@@ -438,7 +470,7 @@
     }
 
     public String getBenchmarkArgList(MethodInfo methodInfo) {
-        return getArgList(args.get(methodInfo.getName()));
+        return Utils.join(benchmarkArgs.get(methodInfo.getName()), ", ");
     }
 
     public String getArgList(MethodInfo methodInfo) {
@@ -517,8 +549,8 @@
             if (type == HelperType.SETUP) {
                 for (HelperMethodInvocation mi : so.getHelpers()) {
                     if (mi.helperLevel == helperLevel && mi.type == HelperType.SETUP) {
-                        Collection<StateObject> args = stateHelperArgs.get(mi.method.getQualifiedName());
-                        result.add(so.localIdentifier + "." + mi.method.getName() + "(" + getArgList(args) + ");");
+                        Collection<String> args = stateHelperArgs.get(mi.method.getQualifiedName());
+                        result.add(so.localIdentifier + "." + mi.method.getName() + "(" + Utils.join(args, ",") + ");");
                     }
                 }
             }
@@ -530,8 +562,8 @@
             if (type == HelperType.TEARDOWN) {
                 for (HelperMethodInvocation mi : so.getHelpers()) {
                     if (mi.helperLevel == helperLevel && mi.type == HelperType.TEARDOWN) {
-                        Collection<StateObject> args = stateHelperArgs.get(mi.method.getQualifiedName());
-                        result.add(so.localIdentifier + "." + mi.method.getName() + "(" + getArgList(args) + ");");
+                        Collection<String> args = stateHelperArgs.get(mi.method.getQualifiedName());
+                        result.add(so.localIdentifier + "." + mi.method.getName() + "(" + Utils.join(args, ",") + ");");
                     }
                 }
             }
@@ -547,8 +579,8 @@
                 result.add("        if (!" + so.localIdentifier + ".ready" + helperLevel + ") {");
                 for (HelperMethodInvocation mi : so.getHelpers()) {
                     if (mi.helperLevel == helperLevel && mi.type == HelperType.SETUP) {
-                        Collection<StateObject> args = stateHelperArgs.get(mi.method.getQualifiedName());
-                        result.add("            " + so.localIdentifier + "." + mi.method.getName() + "(" + getArgList(args) + ");");
+                        Collection<String> args = stateHelperArgs.get(mi.method.getQualifiedName());
+                        result.add("            " + so.localIdentifier + "." + mi.method.getName() + "(" + Utils.join(args, ",") + ");");
                     }
                 }
                 result.add("            " + so.localIdentifier + ".ready" + helperLevel + " = true;");
@@ -573,8 +605,8 @@
                 result.add("        if (" + so.localIdentifier + ".ready" + helperLevel + ") {");
                 for (HelperMethodInvocation mi : so.getHelpers()) {
                     if (mi.helperLevel == helperLevel && mi.type == HelperType.TEARDOWN) {
-                        Collection<StateObject> args = stateHelperArgs.get(mi.method.getQualifiedName());
-                        result.add("            " + so.localIdentifier + "." + mi.method.getName() + "(" + getArgList(args) + ");");
+                        Collection<String> args = stateHelperArgs.get(mi.method.getQualifiedName());
+                        result.add("            " + so.localIdentifier + "." + mi.method.getName() + "(" + Utils.join(args, ",") + ");");
                     }
                 }
                 result.add("            " + so.localIdentifier + ".ready" + helperLevel + " = false;");
@@ -646,7 +678,7 @@
             result.add("");
             result.add("static volatile " + so.type + " " + so.fieldIdentifier + ";");
             result.add("");
-            result.add(so.type + " _jmh_tryInit_" + so.fieldIdentifier + "(InfraControl control, ThreadParams threadParams" + soDependency_TypeArgs(so) + ") throws Throwable {");
+            result.add(so.type + " _jmh_tryInit_" + so.fieldIdentifier + "(InfraControl control" + soDependency_TypeArgs(so) + ") throws Throwable {");
             result.add("    " + so.type + " val = " + so.fieldIdentifier + ";");
             result.add("    if (val != null) {");
             result.add("        return val;");
@@ -670,8 +702,8 @@
             for (HelperMethodInvocation hmi : so.getHelpers()) {
                 if (hmi.helperLevel != Level.Trial) continue;
                 if (hmi.type != HelperType.SETUP) continue;
-                Collection<StateObject> args = stateHelperArgs.get(hmi.method.getQualifiedName());
-                result.add("        val." + hmi.method.getName() + "(" + getArgList(args) + ");");
+                Collection<String> args = stateHelperArgs.get(hmi.method.getQualifiedName());
+                result.add("        val." + hmi.method.getName() + "(" + Utils.join(args, ",") + ");");
             }
             result.add("        val.ready" + Level.Trial + " = true;");
             result.add("        " + so.fieldIdentifier + " = val;");
@@ -686,25 +718,7 @@
             result.add("");
             result.add(so.type + " " + so.fieldIdentifier + ";");
             result.add("");
-            result.add(so.type + " _jmh_tryInit_" + so.fieldIdentifier + "(InfraControl control, ThreadParams threadParams" + soDependency_TypeArgs(so) + ") throws Throwable {");
-
-            // These special classes are copying the external environment.
-            if (so.userType.equals(BenchmarkParams.class.getCanonicalName())) {
-                result.add("    " + so.fieldIdentifier + " = new " + so.type + "(control.benchmarkParams);");
-                result.add("    return " + so.fieldIdentifier + ";");
-                result.add("}");
-                continue;
-            } else if (so.userType.equals(IterationParams.class.getCanonicalName())) {
-                result.add("    " + so.fieldIdentifier + " = new " + so.type + "(control.iterationParams);");
-                result.add("    return " + so.fieldIdentifier + ";");
-                result.add("}");
-                continue;
-            } else if (so.userType.equals(ThreadParams.class.getCanonicalName())) {
-                result.add("    " + so.fieldIdentifier + " = new " + so.type + "(threadParams);");
-                result.add("    return " + so.fieldIdentifier + ";");
-                result.add("}");
-                continue;
-            }
+            result.add(so.type + " _jmh_tryInit_" + so.fieldIdentifier + "(InfraControl control" + soDependency_TypeArgs(so) + ") throws Throwable {");
 
             result.add("    " + so.type + " val = " + so.fieldIdentifier + ";");
             result.add("    if (val == null) {");
@@ -723,8 +737,8 @@
             for (HelperMethodInvocation hmi : so.getHelpers()) {
                 if (hmi.helperLevel != Level.Trial) continue;
                 if (hmi.type != HelperType.SETUP) continue;
-                Collection<StateObject> args = stateHelperArgs.get(hmi.method.getQualifiedName());
-                result.add("        val." + hmi.method.getName() + "(" + getArgList(args) + ");");
+                Collection<String> args = stateHelperArgs.get(hmi.method.getQualifiedName());
+                result.add("        val." + hmi.method.getName() + "(" + Utils.join(args, ",") + ");");
             }
             result.add("        " + so.fieldIdentifier + " = val;");
             result.add("    }");
@@ -738,13 +752,14 @@
             result.add("");
             result.add("static java.util.Map<Integer, " + so.type + "> " + so.fieldIdentifier + "_map = java.util.Collections.synchronizedMap(new java.util.HashMap<Integer, " + so.type + ">());");
             result.add("");
-            result.add(so.type + " _jmh_tryInit_" + so.fieldIdentifier + "(InfraControl control, ThreadParams threadParams" + soDependency_TypeArgs(so) + ") throws Throwable {");
-            result.add("    " + so.type + " val = " + so.fieldIdentifier + "_map.get(threadParams.getGroupIndex());");
+            result.add(so.type + " _jmh_tryInit_" + so.fieldIdentifier + "(InfraControl control" + soDependency_TypeArgs(so) + ") throws Throwable {");
+            result.add("    int groupIdx = threadParams.getGroupIndex();");
+            result.add("    " + so.type + " val = " + so.fieldIdentifier + "_map.get(groupIdx);");
             result.add("    if (val != null) {");
             result.add("        return val;");
             result.add("    }");
             result.add("    synchronized(this.getClass()) {");
-            result.add("        val = " + so.fieldIdentifier + "_map.get(threadParams.getGroupIndex());");
+            result.add("        val = " + so.fieldIdentifier + "_map.get(groupIdx);");
             result.add("        if (val != null) {");
             result.add("            return val;");
             result.add("        }");
@@ -762,11 +777,11 @@
             for (HelperMethodInvocation hmi : so.getHelpers()) {
                 if (hmi.helperLevel != Level.Trial) continue;
                 if (hmi.type != HelperType.SETUP) continue;
-                Collection<StateObject> args = stateHelperArgs.get(hmi.method.getQualifiedName());
-                result.add("        val." + hmi.method.getName() + "(" + getArgList(args) + ");");
+                Collection<String> args = stateHelperArgs.get(hmi.method.getQualifiedName());
+                result.add("        val." + hmi.method.getName() + "(" + Utils.join(args, ",") + ");");
             }
             result.add("        " + "val.ready" + Level.Trial + " = true;");
-            result.add("        " + so.fieldIdentifier + "_map.put(threadParams.getGroupIndex(), val);");
+            result.add("        " + so.fieldIdentifier + "_map.put(groupIdx, val);");
             result.add("    }");
             result.add("    return val;");
             result.add("}");
@@ -810,7 +825,7 @@
     public List<String> getStateGetters(MethodInfo method) {
         List<String> result = new ArrayList<String>();
         for (StateObject so : stateOrder(method, true)) {
-            result.add(so.type + " " + so.localIdentifier + " = _jmh_tryInit_" + so.fieldIdentifier + "(control, threadParams" + soDependency_Args(so) + ");");
+            result.add(so.type + " " + so.localIdentifier + " = _jmh_tryInit_" + so.fieldIdentifier + "(control" + soDependency_Args(so) + ");");
         }
         return result;
     }
@@ -822,9 +837,8 @@
         List<StateObject> stratum = new ArrayList<StateObject>();
 
         // These are roots
-        stratum.addAll(args.get(method.getName()));
+        stratum.addAll(roots.get(method.getName()));
         stratum.addAll(implicits.values());
-        stratum.addAll(getControls());
 
         // Recursively walk the DAG
         while (!stratum.isEmpty()) {
@@ -843,17 +857,6 @@
         return new LinkedHashSet<StateObject>(linearOrder);
     }
 
-    public void addSuperCall(PrintWriter writer, StateObject so, String suffix) throws IOException {
-        // These classes have copying constructor:
-        if (so.userType.equals(BenchmarkParams.class.getCanonicalName()) ||
-            so.userType.equals(IterationParams.class.getCanonicalName()) ||
-            so.userType.equals(ThreadParams.class.getCanonicalName())) {
-            writer.println("    public " + so.type + suffix + "(" + so.userType + " other) {");
-            writer.println("        super(other);");
-            writer.println("    }");
-        }
-    }
-
     public void writeStateOverrides(BenchmarkGeneratorSession sess, GeneratorDestination dst) throws IOException {
 
         for (StateObject so : cons(stateObjects)) {
@@ -868,7 +871,6 @@
 
                 pw.println("public class " + so.type + "_B1 extends " + so.userType + " {");
                 Paddings.padding(pw);
-                addSuperCall(pw, so, "_B1");
                 pw.println("}");
 
                 pw.close();
@@ -907,8 +909,6 @@
                         throw new IllegalStateException("Unknown state scope: " + so.scope);
                 }
 
-                addSuperCall(pw, so, "_B2");
-
                 pw.println("}");
 
                 pw.close();
@@ -918,10 +918,8 @@
                 PrintWriter pw = new PrintWriter(dst.newClass(so.packageName + "." + so.type + "_B3"));
 
                 pw.println("package " + so.packageName + ";");
-
                 pw.println("public class " + so.type + "_B3 extends " + so.type + "_B2 {");
                 Paddings.padding(pw);
-                addSuperCall(pw, so, "_B3");
                 pw.println("}");
                 pw.println("");
 
@@ -932,9 +930,7 @@
                 PrintWriter pw = new PrintWriter(dst.newClass(so.packageName + "." + so.type));
 
                 pw.println("package " + so.packageName + ";");
-
                 pw.println("public class " + so.type + " extends " + so.type + "_B3 {");
-                addSuperCall(pw, so, "");
                 pw.println("}");
                 pw.println("");
 
@@ -951,16 +947,6 @@
         return implicits.get(label);
     }
 
-    public Collection<StateObject> getControls() {
-        Collection<StateObject> s = new ArrayList<StateObject>();
-        for (StateObject so : cons(args.values())) {
-            if (so.userType.equals(Control.class.getName())) {
-                s.add(so);
-            }
-        }
-        return s;
-    }
-
     public Collection<String> getAuxResultNames(MethodInfo method) {
         return auxNames.get(method.getName());
     }
@@ -974,4 +960,5 @@
             writer.println("import " + so.packageName + "." + so.type + ";");
         }
     }
+
 }
--- a/jmh-core/src/main/java/org/openjdk/jmh/infra/BenchmarkParams.java	Wed Jul 13 19:35:00 2016 +0300
+++ b/jmh-core/src/main/java/org/openjdk/jmh/infra/BenchmarkParams.java	Tue Jul 19 21:57:50 2016 +0300
@@ -49,7 +49,6 @@
  *     info about the benchmark</li>
  * </ol>
  */
-@State(Scope.Thread)
 public class BenchmarkParams extends BenchmarkParamsL4 {
     private static final long serialVersionUID = -1068219503090299117L;
 
@@ -66,10 +65,6 @@
         Utils.check(BenchmarkParams.class, "jvm", "jvmArgs");
     }
 
-    public BenchmarkParams(BenchmarkParams other) {
-        super(other);
-    }
-
     public BenchmarkParams(String benchmark, String generatedTarget, boolean synchIterations,
                              int threads, int[] threadGroups, Collection<String> threadGroupLabels,
                              int forks, int warmupForks,
@@ -109,10 +104,6 @@
                 jvm, jvmArgs,
                 timeout);
     }
-
-    public BenchmarkParamsL4(BenchmarkParams other) {
-        super(other);
-    }
 }
 
 abstract class BenchmarkParamsL3 extends BenchmarkParamsL2 {
@@ -152,10 +143,6 @@
                 jvm, jvmArgs,
                 timeout);
     }
-
-    public BenchmarkParamsL3(BenchmarkParams other) {
-        super(other);
-    }
 }
 
 abstract class BenchmarkParamsL1 extends BenchmarkParamsL0 {
@@ -229,26 +216,6 @@
         this.timeout = timeout;
     }
 
-    public BenchmarkParamsL2(BenchmarkParams other) {
-        this.benchmark = other.benchmark;
-        this.generatedTarget = other.generatedTarget;
-        this.synchIterations = other.synchIterations;
-        this.threads = other.threads;
-        this.threadGroups = other.threadGroups;
-        this.threadGroupLabels = other.threadGroupLabels;
-        this.forks = other.forks;
-        this.warmupForks = other.warmupForks;
-        this.warmup = other.warmup;
-        this.measurement = other.measurement;
-        this.mode = other.mode;
-        this.params = other.params;
-        this.timeUnit = other.timeUnit;
-        this.opsPerInvocation = other.opsPerInvocation;
-        this.jvm = other.jvm;
-        this.jvmArgs = other.jvmArgs;
-        this.timeout = other.timeout;
-    }
-
     /**
      * @return how long to wait for iteration to complete
      */
--- a/jmh-core/src/main/java/org/openjdk/jmh/infra/Blackhole.java	Wed Jul 13 19:35:00 2016 +0300
+++ b/jmh-core/src/main/java/org/openjdk/jmh/infra/Blackhole.java	Tue Jul 19 21:57:50 2016 +0300
@@ -24,7 +24,6 @@
  */
 package org.openjdk.jmh.infra;
 
-import org.openjdk.jmh.annotations.*;
 import org.openjdk.jmh.util.Utils;
 
 import java.util.Random;
@@ -152,8 +151,7 @@
  * value is actually used afterwards. This can save from the dead-code elimination
  * of the computations resulting in the given values.</p>
  */
-@State(Scope.Thread) // Blackholes are always acting like a thread-local state
-public class Blackhole extends BlackholeL4 {
+public final class Blackhole extends BlackholeL4 {
 
     /**
      * IMPLEMENTATION NOTES:
@@ -257,7 +255,7 @@
         Utils.check(Blackhole.class, "obj1", "objs1");
     }
 
-    public Blackhole() {
+    public Blackhole(String challengeResponse) {
         /*
          * Prevent instantiation by user code. Without additional countermeasures
          * to properly escape Blackhole, its magic is not working. The instances
@@ -277,34 +275,9 @@
          * directly though.
          */
 
-        IllegalStateException iae = new IllegalStateException("Blackholes should not be instantiated directly.");
-        StackTraceElement[] stackTrace = iae.getStackTrace();
-
-        // Somebody disabled the stack traces? Oh well.
-        if (stackTrace.length == 0) {
-            return;
+        if (!challengeResponse.equals("Today's password is swordfish. I understand instantiating Blackholes directly is dangerous.")) {
+            throw new IllegalStateException("Blackholes should not be instantiated directly.");
         }
-
-        for (StackTraceElement el : stackTrace) {
-            // Either we instantiate from the JMH generated code,
-            // or our user is a tricky bastard, and gets what's coming to him.
-            if (el.getMethodName().startsWith("_jmh_tryInit_") &&
-                    el.getClassName().contains("generated"))
-                return;
-        }
-        throw iae;
-    }
-
-    /*
-     * Need to clear the sinks to break the GC from keeping the
-     * consumed objects forever.
-     */
-
-    @Setup(Level.Iteration)
-    @TearDown(Level.Iteration)
-    public void clearSinks() {
-        obj1 = new Object();
-        objs1 = new Object[]{new Object()};
     }
 
     /**
--- a/jmh-core/src/main/java/org/openjdk/jmh/infra/Control.java	Wed Jul 13 19:35:00 2016 +0300
+++ b/jmh-core/src/main/java/org/openjdk/jmh/infra/Control.java	Tue Jul 19 21:57:50 2016 +0300
@@ -24,18 +24,13 @@
  */
 package org.openjdk.jmh.infra;
 
-import org.openjdk.jmh.annotations.Level;
-import org.openjdk.jmh.annotations.Scope;
-import org.openjdk.jmh.annotations.Setup;
-import org.openjdk.jmh.annotations.State;
 import org.openjdk.jmh.util.Utils;
 
 /**
  * Control object, used to communicate significant information from JMH to the benchmark.
  * WARNING: The API for this class is considered unstable, and can be changed without notice.
  */
-@State(Scope.Benchmark)
-public class Control extends ControlL4 {
+public final class Control extends ControlL4 {
 
     /**
      * Do the class hierarchy trick to evade false sharing, and check if it's working in runtime.
@@ -72,12 +67,6 @@
 
 abstract class ControlL2 extends ControlL1 {
 
-    @Setup(Level.Iteration)
-    public void setup() {
-        startMeasurement = false;
-        stopMeasurement = false;
-    }
-
     /**
      * Transitions to "true", once JMH had started the measurement for the current iteration.
      */
--- a/jmh-core/src/main/java/org/openjdk/jmh/infra/IterationParams.java	Wed Jul 13 19:35:00 2016 +0300
+++ b/jmh-core/src/main/java/org/openjdk/jmh/infra/IterationParams.java	Tue Jul 19 21:57:50 2016 +0300
@@ -24,8 +24,6 @@
  */
 package org.openjdk.jmh.infra;
 
-import org.openjdk.jmh.annotations.Scope;
-import org.openjdk.jmh.annotations.State;
 import org.openjdk.jmh.runner.IterationType;
 import org.openjdk.jmh.runner.options.TimeValue;
 import org.openjdk.jmh.util.Utils;
@@ -46,18 +44,13 @@
  *     info about the benchmark</li>
  * </ol>
  */
-@State(Scope.Thread)
-public class IterationParams extends IterationParamsL4 {
+public final class IterationParams extends IterationParamsL4 {
     private static final long serialVersionUID = -8111111319033802892L;
 
     static {
         Utils.check(IterationParams.class, "type", "count", "timeValue", "batchSize");
     }
 
-    public IterationParams(IterationParams other) {
-        super(other);
-    }
-
     public IterationParams(IterationType type, int count, TimeValue time, int batchSize) {
         super(type, count, time, batchSize);
     }
@@ -70,10 +63,6 @@
     public IterationParamsL4(IterationType type, int count, TimeValue time, int batchSize) {
         super(type, count, time, batchSize);
     }
-
-    public IterationParamsL4(IterationParams other) {
-        super(other);
-    }
 }
 
 abstract class IterationParamsL3 extends IterationParamsL2 {
@@ -99,10 +88,6 @@
     public IterationParamsL3(IterationType type, int count, TimeValue time, int batchSize) {
         super(type, count, time, batchSize);
     }
-
-    public IterationParamsL3(IterationParams other) {
-        super(other);
-    }
 }
 
 abstract class IterationParamsL1 extends IterationParamsL0 {
@@ -158,13 +143,6 @@
         this.batchSize = batchSize;
     }
 
-    public IterationParamsL2(IterationParams other) {
-        this.type = other.type;
-        this.count = other.count;
-        this.timeValue = other.timeValue;
-        this.batchSize = other.batchSize;
-    }
-
     /**
      * Iteration type: separates warmup iterations vs. measurement iterations.
      * @return iteration type.
--- a/jmh-core/src/main/java/org/openjdk/jmh/infra/ThreadParams.java	Wed Jul 13 19:35:00 2016 +0300
+++ b/jmh-core/src/main/java/org/openjdk/jmh/infra/ThreadParams.java	Tue Jul 19 21:57:50 2016 +0300
@@ -24,8 +24,6 @@
  */
 package org.openjdk.jmh.infra;
 
-import org.openjdk.jmh.annotations.Scope;
-import org.openjdk.jmh.annotations.State;
 import org.openjdk.jmh.util.Utils;
 
 /**
@@ -35,18 +33,13 @@
  * not limited to the number of threads, thread indicies, group information, etc. Some
  * of that info duplicates what is available in {@link org.openjdk.jmh.infra.BenchmarkParams}.</p>
  */
-@State(Scope.Thread)
-public class ThreadParams extends ThreadParamsL4 {
+public final class ThreadParams extends ThreadParamsL4 {
     public ThreadParams(int threadIdx, int threadCount, int groupIdx, int groupCount, int subgroupIdx, int subgroupCount,
                         int groupThreadIdx, int groupThreadCount, int subgroupThreadIdx, int subgroupThreadCount) {
         super(threadIdx, threadCount, groupIdx, groupCount, subgroupIdx, subgroupCount,
                 groupThreadIdx, groupThreadCount, subgroupThreadIdx, subgroupThreadCount);
     }
 
-    public ThreadParams(ThreadParams other) {
-        super(other);
-    }
-
     static {
         Utils.check(ThreadParams.class, "threadIdx", "threadCount");
         Utils.check(ThreadParams.class, "groupIdx", "groupCount");
@@ -250,20 +243,6 @@
         this.subgroupThreadIdx = subgroupThreadIdx;
         this.subgroupThreadCount = subgroupThreadCount;
     }
-
-    public ThreadParamsL2(ThreadParams other) {
-        this.threadIdx = other.threadIdx;
-        this.threadCount = other.threadCount;
-        this.groupIdx = other.groupIdx;
-        this.groupCount = other.groupCount;
-        this.subgroupIdx = other.subgroupIdx;
-        this.subgroupCount = other.subgroupCount;
-        this.groupThreadIdx = other.groupThreadIdx;
-        this.subgroupThreadIdx = other.subgroupThreadIdx;
-        this.subgroupThreadCount = other.subgroupThreadCount;
-        this.groupThreadCount = other.groupThreadCount;
-    }
-
 }
 
 abstract class ThreadParamsL3 extends ThreadParamsL2 {
@@ -289,10 +268,6 @@
         super(threadIdx, threadCount, groupIdx, groupCount, subgroupIdx, subgroupCount,
                 groupThreadIdx, groupThreadCount, subgroupThreadIdx, subgroupThreadCount);
     }
-
-    public ThreadParamsL3(ThreadParams other) {
-        super(other);
-    }
 }
 
 abstract class ThreadParamsL4 extends ThreadParamsL3 {
@@ -303,8 +278,4 @@
         super(threadIdx, threadCount, groupIdx, groupCount, subgroupIdx, subgroupCount,
                 groupThreadIdx, groupThreadCount, subgroupThreadIdx, subgroupThreadCount);
     }
-
-    public ThreadParamsL4(ThreadParams other) {
-        super(other);
-    }
 }
--- a/jmh-core/src/test/java/org/openjdk/jmh/BlackholeTest.java	Wed Jul 13 19:35:00 2016 +0300
+++ b/jmh-core/src/test/java/org/openjdk/jmh/BlackholeTest.java	Tue Jul 19 21:57:50 2016 +0300
@@ -47,11 +47,17 @@
     @Test
     public void testUserConstructor() {
         try {
-            new Blackhole();
+            new Blackhole("Boyaa");
             Assert.fail("Should have failed");
         } catch (IllegalStateException e) {
             // expected
         }
+
+        try {
+            new Blackhole("Today's password is swordfish. I understand instantiating Blackholes directly is dangerous.");
+        } catch (Throwable e) {
+            Assert.fail("Failed unexpectedly");
+        }
     }
 
 }