| Orion Hodson | 8430e77 | 2018-03-15 15:13:43 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2018 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | import annotations.ConstantMethodHandle; |
| 18 | import annotations.ConstantMethodType; |
| 19 | import java.lang.invoke.MethodHandle; |
| 20 | import java.lang.invoke.MethodType; |
| Orion Hodson | ecd5856 | 2018-09-24 11:27:33 +0100 | [diff] [blame] | 21 | import java.lang.invoke.WrongMethodTypeException; |
| 22 | |
| 23 | import java.io.StreamTokenizer; |
| 24 | import java.io.StringReader; |
| 25 | import java.util.Stack; |
| Orion Hodson | 8430e77 | 2018-03-15 15:13:43 +0000 | [diff] [blame] | 26 | |
| 27 | class Main { |
| Orion Hodson | dbaa5c7 | 2018-05-10 08:22:46 +0100 | [diff] [blame] | 28 | /** |
| 29 | * Number of iterations run to attempt to trigger JIT compilation. These tests run on ART and |
| 30 | * the RI so they iterate rather than using the ART only native method ensureJitCompiled(). |
| 31 | */ |
| 32 | private static final int ITERATIONS_FOR_JIT = 12000; |
| 33 | |
| 34 | /** A static field updated by method handle getters and setters. */ |
| Orion Hodson | 8430e77 | 2018-03-15 15:13:43 +0000 | [diff] [blame] | 35 | private static String name = "default"; |
| 36 | |
| 37 | private static void unreachable() { |
| 38 | throw new Error("Unreachable"); |
| 39 | } |
| 40 | |
| Orion Hodson | dbaa5c7 | 2018-05-10 08:22:46 +0100 | [diff] [blame] | 41 | private static void assertEquals(Object expected, Object actual) { |
| 42 | if (!expected.equals(actual)) { |
| 43 | throw new AssertionError("Assertion failure: " + expected + " != " + actual); |
| 44 | } |
| 45 | } |
| 46 | |
| Orion Hodson | 18259d7 | 2018-04-12 11:18:23 +0100 | [diff] [blame] | 47 | private static class LocalClass { |
| 48 | public LocalClass() {} |
| 49 | |
| 50 | private int field; |
| 51 | } |
| 52 | |
| Orion Hodson | ecd5856 | 2018-09-24 11:27:33 +0100 | [diff] [blame] | 53 | private static class TestTokenizer extends StreamTokenizer { |
| 54 | public TestTokenizer(String message) { |
| 55 | super(new StringReader(message)); |
| 56 | } |
| 57 | } |
| 58 | |
| Orion Hodson | 8430e77 | 2018-03-15 15:13:43 +0000 | [diff] [blame] | 59 | @ConstantMethodType( |
| Orion Hodson | 18259d7 | 2018-04-12 11:18:23 +0100 | [diff] [blame] | 60 | returnType = String.class, |
| 61 | parameterTypes = {int.class, Integer.class, System.class}) |
| Orion Hodson | 8430e77 | 2018-03-15 15:13:43 +0000 | [diff] [blame] | 62 | private static MethodType methodType0() { |
| 63 | unreachable(); |
| 64 | return null; |
| 65 | } |
| 66 | |
| Orion Hodson | 18259d7 | 2018-04-12 11:18:23 +0100 | [diff] [blame] | 67 | @ConstantMethodType( |
| 68 | returnType = void.class, |
| 69 | parameterTypes = {LocalClass.class}) |
| 70 | private static MethodType methodType1() { |
| 71 | unreachable(); |
| 72 | return null; |
| 73 | } |
| 74 | |
| 75 | private static void repeatConstMethodType0(MethodType expected) { |
| 76 | System.out.print("repeatConstMethodType0("); |
| 77 | System.out.print(expected); |
| 78 | System.out.println(")"); |
| Orion Hodson | dbaa5c7 | 2018-05-10 08:22:46 +0100 | [diff] [blame] | 79 | for (int i = 0; i < ITERATIONS_FOR_JIT; ++i) { |
| Orion Hodson | 18259d7 | 2018-04-12 11:18:23 +0100 | [diff] [blame] | 80 | MethodType actual = methodType0(); |
| Orion Hodson | dbaa5c7 | 2018-05-10 08:22:46 +0100 | [diff] [blame] | 81 | assertEquals(expected, actual); |
| Orion Hodson | 18259d7 | 2018-04-12 11:18:23 +0100 | [diff] [blame] | 82 | } |
| 83 | } |
| 84 | |
| 85 | private static void repeatConstMethodType1(MethodType expected) { |
| 86 | System.out.print("repeatConstMethodType1("); |
| 87 | System.out.print(expected); |
| 88 | System.out.println(")"); |
| Orion Hodson | dbaa5c7 | 2018-05-10 08:22:46 +0100 | [diff] [blame] | 89 | for (int i = 0; i < ITERATIONS_FOR_JIT; ++i) { |
| Orion Hodson | 18259d7 | 2018-04-12 11:18:23 +0100 | [diff] [blame] | 90 | MethodType actual = methodType1(); |
| Orion Hodson | dbaa5c7 | 2018-05-10 08:22:46 +0100 | [diff] [blame] | 91 | assertEquals(expected, actual); |
| Orion Hodson | 18259d7 | 2018-04-12 11:18:23 +0100 | [diff] [blame] | 92 | } |
| 93 | } |
| 94 | |
| Orion Hodson | 8430e77 | 2018-03-15 15:13:43 +0000 | [diff] [blame] | 95 | static void helloWorld(String who) { |
| 96 | System.out.print("Hello World! And Hello "); |
| 97 | System.out.println(who); |
| 98 | } |
| 99 | |
| 100 | @ConstantMethodHandle( |
| Orion Hodson | 18259d7 | 2018-04-12 11:18:23 +0100 | [diff] [blame] | 101 | kind = ConstantMethodHandle.INVOKE_STATIC, |
| 102 | owner = "Main", |
| 103 | fieldOrMethodName = "helloWorld", |
| 104 | descriptor = "(Ljava/lang/String;)V") |
| Orion Hodson | 8430e77 | 2018-03-15 15:13:43 +0000 | [diff] [blame] | 105 | private static MethodHandle printHelloHandle() { |
| 106 | unreachable(); |
| 107 | return null; |
| 108 | } |
| 109 | |
| 110 | @ConstantMethodHandle( |
| Orion Hodson | 18259d7 | 2018-04-12 11:18:23 +0100 | [diff] [blame] | 111 | kind = ConstantMethodHandle.STATIC_PUT, |
| 112 | owner = "Main", |
| 113 | fieldOrMethodName = "name", |
| 114 | descriptor = "Ljava/lang/String;") |
| Orion Hodson | 8430e77 | 2018-03-15 15:13:43 +0000 | [diff] [blame] | 115 | private static MethodHandle setNameHandle() { |
| 116 | unreachable(); |
| 117 | return null; |
| 118 | } |
| 119 | |
| 120 | @ConstantMethodHandle( |
| Orion Hodson | 18259d7 | 2018-04-12 11:18:23 +0100 | [diff] [blame] | 121 | kind = ConstantMethodHandle.STATIC_GET, |
| Orion Hodson | dbaa5c7 | 2018-05-10 08:22:46 +0100 | [diff] [blame] | 122 | owner = "Main", |
| 123 | fieldOrMethodName = "name", |
| 124 | descriptor = "Ljava/lang/String;") |
| 125 | private static MethodHandle getNameHandle() { |
| 126 | unreachable(); |
| 127 | return null; |
| 128 | } |
| 129 | |
| 130 | @ConstantMethodHandle( |
| 131 | kind = ConstantMethodHandle.STATIC_GET, |
| Orion Hodson | 18259d7 | 2018-04-12 11:18:23 +0100 | [diff] [blame] | 132 | owner = "java/lang/Math", |
| 133 | fieldOrMethodName = "E", |
| 134 | descriptor = "D") |
| Orion Hodson | 8430e77 | 2018-03-15 15:13:43 +0000 | [diff] [blame] | 135 | private static MethodHandle getMathE() { |
| 136 | unreachable(); |
| 137 | return null; |
| 138 | } |
| 139 | |
| Orion Hodson | fd7b2c2 | 2018-03-15 15:38:38 +0000 | [diff] [blame] | 140 | @ConstantMethodHandle( |
| Orion Hodson | 18259d7 | 2018-04-12 11:18:23 +0100 | [diff] [blame] | 141 | kind = ConstantMethodHandle.STATIC_PUT, |
| 142 | owner = "java/lang/Math", |
| 143 | fieldOrMethodName = "E", |
| 144 | descriptor = "D") |
| Orion Hodson | fd7b2c2 | 2018-03-15 15:38:38 +0000 | [diff] [blame] | 145 | private static MethodHandle putMathE() { |
| 146 | unreachable(); |
| 147 | return null; |
| 148 | } |
| 149 | |
| Orion Hodson | ecd5856 | 2018-09-24 11:27:33 +0100 | [diff] [blame] | 150 | @ConstantMethodHandle( |
| 151 | kind = ConstantMethodHandle.INSTANCE_GET, |
| 152 | owner = "java/io/StreamTokenizer", |
| 153 | fieldOrMethodName = "sval", |
| 154 | descriptor = "Ljava/lang/String;") |
| 155 | private static MethodHandle getSval() { |
| 156 | unreachable(); |
| 157 | return null; |
| 158 | } |
| 159 | |
| 160 | // This constant-method-handle references a private instance field. If |
| 161 | // referenced in bytecode it raises IAE at load time. |
| 162 | @ConstantMethodHandle( |
| 163 | kind = ConstantMethodHandle.INSTANCE_PUT, |
| 164 | owner = "java/io/StreamTokenizer", |
| 165 | fieldOrMethodName = "peekc", |
| 166 | descriptor = "I") |
| 167 | private static MethodHandle putPeekc() { |
| 168 | unreachable(); |
| 169 | return null; |
| 170 | } |
| 171 | |
| 172 | @ConstantMethodHandle( |
| 173 | kind = ConstantMethodHandle.INVOKE_VIRTUAL, |
| 174 | owner = "java/util/Stack", |
| 175 | fieldOrMethodName = "pop", |
| 176 | descriptor = "()Ljava/lang/Object;") |
| 177 | private static MethodHandle stackPop() { |
| 178 | unreachable(); |
| 179 | return null; |
| 180 | } |
| 181 | |
| 182 | @ConstantMethodHandle( |
| 183 | kind = ConstantMethodHandle.INVOKE_VIRTUAL, |
| 184 | owner = "java/util/Stack", |
| 185 | fieldOrMethodName = "trimToSize", |
| 186 | descriptor = "()V") |
| 187 | private static MethodHandle stackTrim() { |
| 188 | unreachable(); |
| 189 | return null; |
| 190 | } |
| 191 | |
| Orion Hodson | dbaa5c7 | 2018-05-10 08:22:46 +0100 | [diff] [blame] | 192 | private static void repeatConstMethodHandle() throws Throwable { |
| 193 | System.out.println("repeatConstMethodHandle()"); |
| 194 | String[] values = {"A", "B", "C"}; |
| 195 | for (int i = 0; i < ITERATIONS_FOR_JIT; ++i) { |
| 196 | String value = values[i % values.length]; |
| 197 | setNameHandle().invoke(value); |
| 198 | String actual = (String) getNameHandle().invokeExact(); |
| 199 | assertEquals(value, actual); |
| 200 | assertEquals(value, name); |
| 201 | } |
| 202 | } |
| 203 | |
| Orion Hodson | 8430e77 | 2018-03-15 15:13:43 +0000 | [diff] [blame] | 204 | public static void main(String[] args) throws Throwable { |
| 205 | System.out.println(methodType0()); |
| Orion Hodson | 18259d7 | 2018-04-12 11:18:23 +0100 | [diff] [blame] | 206 | repeatConstMethodType0( |
| 207 | MethodType.methodType(String.class, int.class, Integer.class, System.class)); |
| 208 | repeatConstMethodType1(MethodType.methodType(void.class, LocalClass.class)); |
| Orion Hodson | 8430e77 | 2018-03-15 15:13:43 +0000 | [diff] [blame] | 209 | printHelloHandle().invokeExact("Zog"); |
| 210 | printHelloHandle().invokeExact("Zorba"); |
| 211 | setNameHandle().invokeExact("HoverFly"); |
| 212 | System.out.print("name is "); |
| 213 | System.out.println(name); |
| 214 | System.out.println(getMathE().invoke()); |
| Orion Hodson | dbaa5c7 | 2018-05-10 08:22:46 +0100 | [diff] [blame] | 215 | repeatConstMethodHandle(); |
| Orion Hodson | fd7b2c2 | 2018-03-15 15:38:38 +0000 | [diff] [blame] | 216 | try { |
| 217 | putMathE().invokeExact(Math.PI); |
| 218 | unreachable(); |
| 219 | } catch (IllegalAccessError expected) { |
| 220 | System.out.println("Attempting to set Math.E raised IAE"); |
| 221 | } |
| Orion Hodson | ecd5856 | 2018-09-24 11:27:33 +0100 | [diff] [blame] | 222 | |
| 223 | StreamTokenizer st = new StreamTokenizer(new StringReader("Quack Moo Woof")); |
| 224 | while (st.nextToken() != StreamTokenizer.TT_EOF) { |
| 225 | System.out.println((String) getSval().invokeExact(st)); |
| 226 | } |
| 227 | |
| 228 | TestTokenizer tt = new TestTokenizer("Test message 123"); |
| 229 | tt.nextToken(); |
| 230 | System.out.println((String) getSval().invoke(tt)); |
| 231 | try { |
| 232 | System.out.println((String) getSval().invokeExact(tt)); |
| 233 | } catch (WrongMethodTypeException wmte) { |
| 234 | System.out.println("Getting field in TestTokenizer raised WMTE (woohoo!)"); |
| 235 | } |
| 236 | |
| 237 | Stack stack = new Stack(); |
| 238 | stack.push(Integer.valueOf(3)); |
| 239 | stack.push(Integer.valueOf(5)); |
| 240 | stack.push(Integer.valueOf(7)); |
| 241 | Object tos = stackPop().invokeExact(stack); |
| 242 | System.out.println("Stack: tos was " + tos); |
| 243 | System.out.println("Stack: capacity was " + stack.capacity()); |
| 244 | stackTrim().invokeExact(stack); |
| 245 | System.out.println("Stack: capacity is " + stack.capacity()); |
| Orion Hodson | 8430e77 | 2018-03-15 15:13:43 +0000 | [diff] [blame] | 246 | } |
| 247 | } |