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; 21 import java.lang.invoke.WrongMethodTypeException; 22 23 import java.io.StreamTokenizer; 24 import java.io.StringReader; 25 import java.util.Stack; 26 27 class Main { 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. */ 35 private static String name = "default"; 36 unreachable()37 private static void unreachable() { 38 throw new Error("Unreachable"); 39 } 40 assertEquals(Object expected, Object actual)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 47 private static class LocalClass { LocalClass()48 public LocalClass() {} 49 50 private int field; 51 } 52 53 private static class TestTokenizer extends StreamTokenizer { TestTokenizer(String message)54 public TestTokenizer(String message) { 55 super(new StringReader(message)); 56 } 57 } 58 59 @ConstantMethodType( 60 returnType = String.class, 61 parameterTypes = {int.class, Integer.class, System.class}) methodType0()62 private static MethodType methodType0() { 63 unreachable(); 64 return null; 65 } 66 67 @ConstantMethodType( 68 returnType = void.class, 69 parameterTypes = {LocalClass.class}) methodType1()70 private static MethodType methodType1() { 71 unreachable(); 72 return null; 73 } 74 repeatConstMethodType0(MethodType expected)75 private static void repeatConstMethodType0(MethodType expected) { 76 System.out.print("repeatConstMethodType0("); 77 System.out.print(expected); 78 System.out.println(")"); 79 for (int i = 0; i < ITERATIONS_FOR_JIT; ++i) { 80 MethodType actual = methodType0(); 81 assertEquals(expected, actual); 82 } 83 } 84 repeatConstMethodType1(MethodType expected)85 private static void repeatConstMethodType1(MethodType expected) { 86 System.out.print("repeatConstMethodType1("); 87 System.out.print(expected); 88 System.out.println(")"); 89 for (int i = 0; i < ITERATIONS_FOR_JIT; ++i) { 90 MethodType actual = methodType1(); 91 assertEquals(expected, actual); 92 } 93 } 94 helloWorld(String who)95 static void helloWorld(String who) { 96 System.out.print("Hello World! And Hello "); 97 System.out.println(who); 98 } 99 100 @ConstantMethodHandle( 101 kind = ConstantMethodHandle.INVOKE_STATIC, 102 owner = "Main", 103 fieldOrMethodName = "helloWorld", 104 descriptor = "(Ljava/lang/String;)V") printHelloHandle()105 private static MethodHandle printHelloHandle() { 106 unreachable(); 107 return null; 108 } 109 110 @ConstantMethodHandle( 111 kind = ConstantMethodHandle.STATIC_PUT, 112 owner = "Main", 113 fieldOrMethodName = "name", 114 descriptor = "Ljava/lang/String;") setNameHandle()115 private static MethodHandle setNameHandle() { 116 unreachable(); 117 return null; 118 } 119 120 @ConstantMethodHandle( 121 kind = ConstantMethodHandle.STATIC_GET, 122 owner = "Main", 123 fieldOrMethodName = "name", 124 descriptor = "Ljava/lang/String;") getNameHandle()125 private static MethodHandle getNameHandle() { 126 unreachable(); 127 return null; 128 } 129 130 @ConstantMethodHandle( 131 kind = ConstantMethodHandle.STATIC_GET, 132 owner = "java/lang/Math", 133 fieldOrMethodName = "E", 134 descriptor = "D") getMathE()135 private static MethodHandle getMathE() { 136 unreachable(); 137 return null; 138 } 139 140 @ConstantMethodHandle( 141 kind = ConstantMethodHandle.STATIC_PUT, 142 owner = "java/lang/Math", 143 fieldOrMethodName = "E", 144 descriptor = "D") putMathE()145 private static MethodHandle putMathE() { 146 unreachable(); 147 return null; 148 } 149 150 @ConstantMethodHandle( 151 kind = ConstantMethodHandle.INSTANCE_GET, 152 owner = "java/io/StreamTokenizer", 153 fieldOrMethodName = "sval", 154 descriptor = "Ljava/lang/String;") getSval()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") putPeekc()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;") stackPop()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") stackTrim()187 private static MethodHandle stackTrim() { 188 unreachable(); 189 return null; 190 } 191 repeatConstMethodHandle()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 main(String[] args)204 public static void main(String[] args) throws Throwable { 205 System.out.println(methodType0()); 206 repeatConstMethodType0( 207 MethodType.methodType(String.class, int.class, Integer.class, System.class)); 208 repeatConstMethodType1(MethodType.methodType(void.class, LocalClass.class)); 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()); 215 repeatConstMethodHandle(); 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 } 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()); 246 } 247 } 248