Mon, 31 Aug 2015 14:49:47 -0700
Merge
aoqi@0 | 1 | /* |
aoqi@0 | 2 | * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. |
aoqi@0 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
aoqi@0 | 4 | * |
aoqi@0 | 5 | * This code is free software; you can redistribute it and/or modify it |
aoqi@0 | 6 | * under the terms of the GNU General Public License version 2 only, as |
aoqi@0 | 7 | * published by the Free Software Foundation. |
aoqi@0 | 8 | * |
aoqi@0 | 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
aoqi@0 | 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
aoqi@0 | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
aoqi@0 | 12 | * version 2 for more details (a copy is included in the LICENSE file that |
aoqi@0 | 13 | * accompanied this code). |
aoqi@0 | 14 | * |
aoqi@0 | 15 | * You should have received a copy of the GNU General Public License version |
aoqi@0 | 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
aoqi@0 | 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
aoqi@0 | 18 | * |
aoqi@0 | 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
aoqi@0 | 20 | * or visit www.oracle.com if you need additional information or have any |
aoqi@0 | 21 | * questions. |
aoqi@0 | 22 | */ |
aoqi@0 | 23 | |
aoqi@0 | 24 | /* |
aoqi@0 | 25 | * @test |
aoqi@0 | 26 | * @bug 8011738 |
aoqi@0 | 27 | * @author sogoel |
aoqi@0 | 28 | * @summary Code translation test for Lambda expressions, method references |
aoqi@0 | 29 | * @run main ByteCodeTest |
aoqi@0 | 30 | */ |
aoqi@0 | 31 | |
aoqi@0 | 32 | import com.sun.tools.classfile.Attribute; |
aoqi@0 | 33 | import com.sun.tools.classfile.BootstrapMethods_attribute; |
aoqi@0 | 34 | import com.sun.tools.classfile.ClassFile; |
aoqi@0 | 35 | import com.sun.tools.classfile.ConstantPool; |
aoqi@0 | 36 | import com.sun.tools.classfile.ConstantPoolException; |
aoqi@0 | 37 | import com.sun.tools.classfile.ConstantPool.*; |
aoqi@0 | 38 | |
aoqi@0 | 39 | import java.io.BufferedWriter; |
aoqi@0 | 40 | import java.io.File; |
aoqi@0 | 41 | import java.io.FileWriter; |
aoqi@0 | 42 | import java.io.IOException; |
aoqi@0 | 43 | import java.io.PrintWriter; |
aoqi@0 | 44 | import java.util.ArrayList; |
aoqi@0 | 45 | import java.util.Collections; |
aoqi@0 | 46 | import java.util.HashMap; |
aoqi@0 | 47 | import java.util.HashSet; |
aoqi@0 | 48 | import java.util.List; |
aoqi@0 | 49 | import java.util.Map; |
aoqi@0 | 50 | |
aoqi@0 | 51 | public class ByteCodeTest { |
aoqi@0 | 52 | |
aoqi@0 | 53 | static boolean IS_DEBUG = false; |
aoqi@0 | 54 | public static void main(String[] args) { |
aoqi@0 | 55 | File classFile = null; |
aoqi@0 | 56 | int err = 0; |
aoqi@0 | 57 | boolean verifyResult = false; |
aoqi@0 | 58 | for(TestCases tc : TestCases.values()) { |
aoqi@0 | 59 | classFile = getCompiledFile(tc.name(), tc.srcCode); |
aoqi@0 | 60 | if(classFile == null) { // either testFile or classFile was not created |
aoqi@0 | 61 | err++; |
aoqi@0 | 62 | } else { |
aoqi@0 | 63 | verifyResult = verifyClassFileAttributes(classFile, tc); |
aoqi@0 | 64 | if(!verifyResult) |
aoqi@0 | 65 | System.out.println("Bootstrap class file attributes did not match for " + tc.name()); |
aoqi@0 | 66 | } |
aoqi@0 | 67 | } |
aoqi@0 | 68 | if(err > 0) |
aoqi@0 | 69 | throw new RuntimeException("Found " + err + " found"); |
aoqi@0 | 70 | else |
aoqi@0 | 71 | System.out.println("Test passed"); |
aoqi@0 | 72 | } |
aoqi@0 | 73 | |
aoqi@0 | 74 | private static boolean verifyClassFileAttributes(File classFile, TestCases tc) { |
aoqi@0 | 75 | ClassFile c = null; |
aoqi@0 | 76 | try { |
aoqi@0 | 77 | c = ClassFile.read(classFile); |
aoqi@0 | 78 | } catch (IOException | ConstantPoolException e) { |
aoqi@0 | 79 | e.printStackTrace(); |
aoqi@0 | 80 | } |
aoqi@0 | 81 | ConstantPoolVisitor cpv = new ConstantPoolVisitor(c, c.constant_pool.size()); |
aoqi@0 | 82 | Map<Integer, String> hm = cpv.getBSMMap(); |
aoqi@0 | 83 | |
aoqi@0 | 84 | List<String> expectedValList = tc.getExpectedArgValues(); |
aoqi@0 | 85 | expectedValList.add(tc.bsmSpecifier.specifier); |
aoqi@0 | 86 | if(!(hm.values().containsAll(new HashSet<String>(expectedValList)))) { |
aoqi@0 | 87 | System.out.println("Values do not match"); |
aoqi@0 | 88 | return false; |
aoqi@0 | 89 | } |
aoqi@0 | 90 | return true; |
aoqi@0 | 91 | } |
aoqi@0 | 92 | |
aoqi@0 | 93 | private static File getCompiledFile(String fname, String srcString) { |
aoqi@0 | 94 | File testFile = null, classFile = null; |
aoqi@0 | 95 | boolean isTestFileCreated = true; |
aoqi@0 | 96 | |
aoqi@0 | 97 | try { |
aoqi@0 | 98 | testFile = writeTestFile(fname+".java", srcString); |
aoqi@0 | 99 | } catch(IOException ioe) { |
aoqi@0 | 100 | isTestFileCreated = false; |
aoqi@0 | 101 | System.err.println("fail to write" + ioe); |
aoqi@0 | 102 | } |
aoqi@0 | 103 | |
aoqi@0 | 104 | if(isTestFileCreated) { |
aoqi@0 | 105 | try { |
aoqi@0 | 106 | classFile = compile(testFile); |
aoqi@0 | 107 | } catch (Error err) { |
aoqi@0 | 108 | System.err.println("fail compile. Source:\n" + srcString); |
aoqi@0 | 109 | throw err; |
aoqi@0 | 110 | } |
aoqi@0 | 111 | } |
aoqi@0 | 112 | return classFile; |
aoqi@0 | 113 | } |
aoqi@0 | 114 | |
aoqi@0 | 115 | static File writeTestFile(String fname, String source) throws IOException { |
aoqi@0 | 116 | File f = new File(fname); |
aoqi@0 | 117 | PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(f))); |
aoqi@0 | 118 | out.println(source); |
aoqi@0 | 119 | out.close(); |
aoqi@0 | 120 | return f; |
aoqi@0 | 121 | } |
aoqi@0 | 122 | |
aoqi@0 | 123 | static File compile(File f) { |
aoqi@0 | 124 | int rc = com.sun.tools.javac.Main.compile(new String[] { |
aoqi@0 | 125 | "-source", "1.8", "-g", f.getPath() }); |
aoqi@0 | 126 | if (rc != 0) |
aoqi@0 | 127 | throw new Error("compilation failed. rc=" + rc); |
aoqi@0 | 128 | String path = f.getPath(); |
aoqi@0 | 129 | return new File(path.substring(0, path.length() - 5) + ".class"); |
aoqi@0 | 130 | } |
aoqi@0 | 131 | |
aoqi@0 | 132 | static void debugln(String str) { |
aoqi@0 | 133 | if(IS_DEBUG) |
aoqi@0 | 134 | System.out.println(str); |
aoqi@0 | 135 | } |
aoqi@0 | 136 | |
aoqi@0 | 137 | enum BSMSpecifier { |
aoqi@0 | 138 | SPECIFIER1("REF_invokeStatic java/lang/invoke/LambdaMetafactory metaFactory " + |
aoqi@0 | 139 | "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;" + |
aoqi@0 | 140 | "Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)" + |
aoqi@0 | 141 | "Ljava/lang/invoke/CallSite;"), |
aoqi@0 | 142 | SPECIFIER2("REF_invokeStatic java/lang/invoke/LambdaMetafactory altMetaFactory " + |
aoqi@0 | 143 | "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;" + |
aoqi@0 | 144 | "[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"); |
aoqi@0 | 145 | |
aoqi@0 | 146 | String specifier; |
aoqi@0 | 147 | private BSMSpecifier(String specifier) { |
aoqi@0 | 148 | this.specifier = specifier; |
aoqi@0 | 149 | } |
aoqi@0 | 150 | } |
aoqi@0 | 151 | |
aoqi@0 | 152 | enum TestCases { |
aoqi@0 | 153 | // Single line lambda expression |
aoqi@0 | 154 | TC1("class TC1 {\n" + |
aoqi@0 | 155 | " public static void main(String[] args) {\n" + |
aoqi@0 | 156 | " Object o = (Runnable) () -> { System.out.println(\"hi\");};\n" + |
aoqi@0 | 157 | " }\n"+ |
aoqi@0 | 158 | "}", BSMSpecifier.SPECIFIER1) { |
aoqi@0 | 159 | |
aoqi@0 | 160 | @Override |
aoqi@0 | 161 | List<String> getExpectedArgValues() { |
aoqi@0 | 162 | List<String> valList = new ArrayList<>(); |
aoqi@0 | 163 | valList.add("REF_invokeInterface java/lang/Runnable run ()V"); |
aoqi@0 | 164 | valList.add("REF_invokeStatic TC1 lambda$0 ()V"); |
aoqi@0 | 165 | valList.add("()V"); |
aoqi@0 | 166 | return valList; |
aoqi@0 | 167 | } |
aoqi@0 | 168 | }, |
aoqi@0 | 169 | |
aoqi@0 | 170 | // Lambda expression in a for loop |
aoqi@0 | 171 | TC2("import java.util.*;\n" + |
aoqi@0 | 172 | "public class TC2 {\n" + |
aoqi@0 | 173 | " void TC2_test() {\n" + |
aoqi@0 | 174 | " List<String> list = new ArrayList<>();\n" + |
aoqi@0 | 175 | " list.add(\"A\");\n" + |
aoqi@0 | 176 | " list.add(\"B\");\n" + |
aoqi@0 | 177 | " list.stream().forEach( s -> { System.out.println(s); } );\n" + |
aoqi@0 | 178 | " }\n" + |
aoqi@0 | 179 | " public static void main(String[] args) {\n" + |
aoqi@0 | 180 | " new TC2().TC2_test();\n" + |
aoqi@0 | 181 | " }\n" + |
aoqi@0 | 182 | "}", BSMSpecifier.SPECIFIER1) { |
aoqi@0 | 183 | |
aoqi@0 | 184 | @Override |
aoqi@0 | 185 | List<String> getExpectedArgValues() { |
aoqi@0 | 186 | List<String> valList = new ArrayList<>(); |
aoqi@0 | 187 | valList.add("REF_invokeInterface java/util/function/Consumer accept (Ljava/lang/Object;)V"); |
aoqi@0 | 188 | valList.add("REF_invokeStatic TC2 lambda$0 (Ljava/lang/String;)V"); |
aoqi@0 | 189 | valList.add("(Ljava/lang/String;)V"); |
aoqi@0 | 190 | return valList; |
aoqi@0 | 191 | } |
aoqi@0 | 192 | }, |
aoqi@0 | 193 | |
aoqi@0 | 194 | // Lambda initializer |
aoqi@0 | 195 | TC3("class TC3 {\n" + |
aoqi@0 | 196 | " interface SAM {\n" + |
aoqi@0 | 197 | " void m(int i);\n" + |
aoqi@0 | 198 | " }\n" + |
aoqi@0 | 199 | " SAM lambda_03 = (int pos) -> { };\n" + |
aoqi@0 | 200 | "}", BSMSpecifier.SPECIFIER1) { |
aoqi@0 | 201 | |
aoqi@0 | 202 | @Override |
aoqi@0 | 203 | List<String> getExpectedArgValues() { |
aoqi@0 | 204 | List<String> valList = new ArrayList<>(); |
aoqi@0 | 205 | valList.add("REF_invokeInterface TC3$SAM m (I)V"); |
aoqi@0 | 206 | valList.add("REF_invokeStatic TC3 lambda$0 (I)V"); |
aoqi@0 | 207 | valList.add("(I)V"); |
aoqi@0 | 208 | return valList; |
aoqi@0 | 209 | } |
aoqi@0 | 210 | }, |
aoqi@0 | 211 | |
aoqi@0 | 212 | // Array initializer |
aoqi@0 | 213 | TC4("class TC4 {\n" + |
aoqi@0 | 214 | " interface Block<T> {\n" + |
aoqi@0 | 215 | " void m(T t);\n" + |
aoqi@0 | 216 | " }\n" + |
aoqi@0 | 217 | " void test1() {\n" + |
aoqi@0 | 218 | " Block<?>[] arr1 = { t -> { }, t -> { } };\n" + |
aoqi@0 | 219 | " }\n" + |
aoqi@0 | 220 | "}", BSMSpecifier.SPECIFIER1) { |
aoqi@0 | 221 | |
aoqi@0 | 222 | @Override |
aoqi@0 | 223 | List<String> getExpectedArgValues() { |
aoqi@0 | 224 | List<String> valList = new ArrayList<>(); |
aoqi@0 | 225 | valList.add("REF_invokeInterface TC4$Block m (Ljava/lang/Object;)V"); |
aoqi@0 | 226 | valList.add("REF_invokeStatic TC4 lambda$0 (Ljava/lang/Object;)V"); |
aoqi@0 | 227 | valList.add("(Ljava/lang/Object;)V"); |
aoqi@0 | 228 | valList.add("REF_invokeStatic TC4 lambda$1 (Ljava/lang/Object;)V"); |
aoqi@0 | 229 | return valList; |
aoqi@0 | 230 | } |
aoqi@0 | 231 | }, |
aoqi@0 | 232 | |
aoqi@0 | 233 | //Lambda expression as a method arg |
aoqi@0 | 234 | TC5("class TC5 {\n"+ |
aoqi@0 | 235 | " interface MapFun<T,R> { R m( T n); }\n" + |
aoqi@0 | 236 | " void meth( MapFun<String,Integer> mf ) {\n" + |
aoqi@0 | 237 | " assert( mf.m(\"four\") == 4);\n" + |
aoqi@0 | 238 | " }\n"+ |
aoqi@0 | 239 | " void test(Integer i) {\n" + |
aoqi@0 | 240 | " meth(s -> { Integer len = s.length(); return len; } );\n" + |
aoqi@0 | 241 | " }\n"+ |
aoqi@0 | 242 | "}", BSMSpecifier.SPECIFIER1) { |
aoqi@0 | 243 | |
aoqi@0 | 244 | @Override |
aoqi@0 | 245 | List<String> getExpectedArgValues() { |
aoqi@0 | 246 | List<String> valList = new ArrayList<>(); |
aoqi@0 | 247 | valList.add("REF_invokeInterface TC5$MapFun m (Ljava/lang/Object;)Ljava/lang/Object;"); |
aoqi@0 | 248 | valList.add("REF_invokeStatic TC5 lambda$0 (Ljava/lang/String;)Ljava/lang/Integer;"); |
aoqi@0 | 249 | valList.add("(Ljava/lang/String;)Ljava/lang/Integer;"); |
aoqi@0 | 250 | return valList; |
aoqi@0 | 251 | } |
aoqi@0 | 252 | }, |
aoqi@0 | 253 | |
aoqi@0 | 254 | //Inner class of Lambda expression |
aoqi@0 | 255 | TC6("class TC6 {\n" + |
aoqi@0 | 256 | " interface MapFun<T, R> { R m( T n); }\n" + |
aoqi@0 | 257 | " MapFun<Class<?>,String> cs;\n" + |
aoqi@0 | 258 | " void test() {\n" + |
aoqi@0 | 259 | " cs = c -> {\n" + |
aoqi@0 | 260 | " class innerClass {\n" + |
aoqi@0 | 261 | " Class<?> icc;\n" + |
aoqi@0 | 262 | " innerClass(Class<?> _c) { icc = _c; }\n" + |
aoqi@0 | 263 | " String getString() { return icc.toString(); }\n" + |
aoqi@0 | 264 | " }\n" + |
aoqi@0 | 265 | " return new innerClass(c).getString();\n"+ |
aoqi@0 | 266 | " };\n" + |
aoqi@0 | 267 | " }\n" + |
aoqi@0 | 268 | "}\n", BSMSpecifier.SPECIFIER1) { |
aoqi@0 | 269 | |
aoqi@0 | 270 | @Override |
aoqi@0 | 271 | List<String> getExpectedArgValues() { |
aoqi@0 | 272 | List<String> valList = new ArrayList<>(); |
aoqi@0 | 273 | valList.add("REF_invokeInterface TC6$MapFun m (Ljava/lang/Object;)Ljava/lang/Object;"); |
aoqi@0 | 274 | valList.add("REF_invokeSpecial TC6 lambda$0 (Ljava/lang/Class;)Ljava/lang/String;"); |
aoqi@0 | 275 | valList.add("(Ljava/lang/Class;)Ljava/lang/String;"); |
aoqi@0 | 276 | return valList; |
aoqi@0 | 277 | } |
aoqi@0 | 278 | }, |
aoqi@0 | 279 | |
aoqi@0 | 280 | // Method reference |
aoqi@0 | 281 | TC7("class TC7 {\n" + |
aoqi@0 | 282 | " static interface SAM {\n" + |
aoqi@0 | 283 | " void m(Integer i);\n" + |
aoqi@0 | 284 | " }\n" + |
aoqi@0 | 285 | " void m(Integer i) {}\n" + |
aoqi@0 | 286 | " SAM s = this::m;\n" + |
aoqi@0 | 287 | "}\n", BSMSpecifier.SPECIFIER1) { |
aoqi@0 | 288 | |
aoqi@0 | 289 | @Override |
aoqi@0 | 290 | List<String> getExpectedArgValues() { |
aoqi@0 | 291 | List<String> valList = new ArrayList<>(); |
aoqi@0 | 292 | valList.add("REF_invokeInterface TC7$SAM m (Ljava/lang/Integer;)V"); |
aoqi@0 | 293 | valList.add("REF_invokeVirtual TC7 m (Ljava/lang/Integer;)V"); |
aoqi@0 | 294 | valList.add("(Ljava/lang/Integer;)V"); |
aoqi@0 | 295 | return valList; |
aoqi@0 | 296 | } |
aoqi@0 | 297 | }, |
aoqi@0 | 298 | |
aoqi@0 | 299 | // Constructor reference |
aoqi@0 | 300 | TC8("public class TC8 {\n" + |
aoqi@0 | 301 | " static interface A {Fee<String> m();}\n" + |
aoqi@0 | 302 | " static class Fee<T> {\n" + |
aoqi@0 | 303 | " private T t;\n" + |
aoqi@0 | 304 | " public Fee() {}\n" + |
aoqi@0 | 305 | " }\n" + |
aoqi@0 | 306 | " public static void main(String[] args) {\n" + |
aoqi@0 | 307 | " A a = Fee<String>::new; \n" + |
aoqi@0 | 308 | " }\n" + |
aoqi@0 | 309 | "}\n", BSMSpecifier.SPECIFIER1) { |
aoqi@0 | 310 | |
aoqi@0 | 311 | @Override |
aoqi@0 | 312 | List<String> getExpectedArgValues() { |
aoqi@0 | 313 | List<String> valList = new ArrayList<>(); |
aoqi@0 | 314 | valList.add("REF_invokeInterface TC8$A m ()LTC8$Fee;"); |
aoqi@0 | 315 | valList.add("REF_newInvokeSpecial TC8$Fee <init> ()V"); |
aoqi@0 | 316 | valList.add("()LTC8$Fee;"); |
aoqi@0 | 317 | return valList; |
aoqi@0 | 318 | } |
aoqi@0 | 319 | }, |
aoqi@0 | 320 | |
aoqi@0 | 321 | // Recursive lambda expression |
aoqi@0 | 322 | TC9("class TC9 {\n" + |
aoqi@0 | 323 | " interface Recursive<T, R> { T apply(R n); };\n" + |
aoqi@0 | 324 | " Recursive<Integer,Integer> factorial;\n" + |
aoqi@0 | 325 | " void test(Integer j) {\n" + |
aoqi@0 | 326 | " factorial = i -> { return i == 0 ? 1 : i * factorial.apply( i - 1 ); };\n" + |
aoqi@0 | 327 | " }\n" + |
aoqi@0 | 328 | "}\n", BSMSpecifier.SPECIFIER1) { |
aoqi@0 | 329 | |
aoqi@0 | 330 | @Override |
aoqi@0 | 331 | List<String> getExpectedArgValues() { |
aoqi@0 | 332 | List<String> valList = new ArrayList<>(); |
aoqi@0 | 333 | valList.add("REF_invokeInterface TC9$Recursive apply (Ljava/lang/Object;)Ljava/lang/Object;"); |
aoqi@0 | 334 | valList.add("REF_invokeSpecial TC9 lambda$0 (Ljava/lang/Integer;)Ljava/lang/Integer;"); |
aoqi@0 | 335 | valList.add("(Ljava/lang/Integer;)Ljava/lang/Integer;"); |
aoqi@0 | 336 | return valList; |
aoqi@0 | 337 | } |
aoqi@0 | 338 | }, |
aoqi@0 | 339 | |
aoqi@0 | 340 | //Serializable Lambda |
aoqi@0 | 341 | TC10("import java.io.Serializable;\n" + |
aoqi@0 | 342 | "class TC10 {\n" + |
aoqi@0 | 343 | " interface Foo { int m(); }\n" + |
aoqi@0 | 344 | " public static void main(String[] args) {\n" + |
aoqi@0 | 345 | " Foo f1 = (Foo & Serializable)() -> 3;\n" + |
aoqi@0 | 346 | " }\n" + |
aoqi@0 | 347 | "}\n", BSMSpecifier.SPECIFIER2) { |
aoqi@0 | 348 | |
aoqi@0 | 349 | @Override |
aoqi@0 | 350 | List<String> getExpectedArgValues() { |
aoqi@0 | 351 | List<String> valList = new ArrayList<>(); |
aoqi@0 | 352 | valList.add("REF_invokeStatic java/lang/invoke/LambdaMetafactory altMetaFactory (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"); |
aoqi@0 | 353 | valList.add("REF_invokeInterface TC10$Foo m ()I"); |
aoqi@0 | 354 | valList.add("REF_invokeStatic TC10 lambda$main$3231c38a$0 ()I"); |
aoqi@0 | 355 | valList.add("()I"); |
aoqi@0 | 356 | valList.add("1"); |
aoqi@0 | 357 | return valList; |
aoqi@0 | 358 | } |
aoqi@0 | 359 | }; |
aoqi@0 | 360 | |
aoqi@0 | 361 | String srcCode; |
aoqi@0 | 362 | BSMSpecifier bsmSpecifier; |
aoqi@0 | 363 | |
aoqi@0 | 364 | TestCases(String src, BSMSpecifier bsmSpecifier) { |
aoqi@0 | 365 | this.srcCode = src; |
aoqi@0 | 366 | // By default, all test cases will have bootstrap method specifier as Lambda.MetaFactory |
aoqi@0 | 367 | // For serializable lambda test cases, bootstrap method specifier changed to altMetaFactory |
aoqi@0 | 368 | this.bsmSpecifier = bsmSpecifier; |
aoqi@0 | 369 | } |
aoqi@0 | 370 | |
aoqi@0 | 371 | List<String> getExpectedArgValues() { |
aoqi@0 | 372 | return null; |
aoqi@0 | 373 | } |
aoqi@0 | 374 | |
aoqi@0 | 375 | void setSrcCode(String src) { |
aoqi@0 | 376 | srcCode = src; |
aoqi@0 | 377 | } |
aoqi@0 | 378 | } |
aoqi@0 | 379 | |
aoqi@0 | 380 | static class ConstantPoolVisitor implements ConstantPool.Visitor<String, Integer> { |
aoqi@0 | 381 | final List<String> slist; |
aoqi@0 | 382 | final ClassFile cf; |
aoqi@0 | 383 | final ConstantPool cfpool; |
aoqi@0 | 384 | final Map<Integer, String> bsmMap; |
aoqi@0 | 385 | |
aoqi@0 | 386 | |
aoqi@0 | 387 | public ConstantPoolVisitor(ClassFile cf, int size) { |
aoqi@0 | 388 | slist = new ArrayList<>(size); |
aoqi@0 | 389 | for (int i = 0 ; i < size; i++) { |
aoqi@0 | 390 | slist.add(null); |
aoqi@0 | 391 | } |
aoqi@0 | 392 | this.cf = cf; |
aoqi@0 | 393 | this.cfpool = cf.constant_pool; |
aoqi@0 | 394 | bsmMap = readBSM(); |
aoqi@0 | 395 | } |
aoqi@0 | 396 | |
aoqi@0 | 397 | public Map<Integer, String> getBSMMap() { |
aoqi@0 | 398 | return Collections.unmodifiableMap(bsmMap); |
aoqi@0 | 399 | } |
aoqi@0 | 400 | |
aoqi@0 | 401 | public String visit(CPInfo c, int index) { |
aoqi@0 | 402 | return c.accept(this, index); |
aoqi@0 | 403 | } |
aoqi@0 | 404 | |
aoqi@0 | 405 | private Map<Integer, String> readBSM() { |
aoqi@0 | 406 | BootstrapMethods_attribute bsmAttr = |
aoqi@0 | 407 | (BootstrapMethods_attribute) cf.getAttribute(Attribute.BootstrapMethods); |
aoqi@0 | 408 | if (bsmAttr != null) { |
aoqi@0 | 409 | Map<Integer, String> out = |
aoqi@0 | 410 | new HashMap<>(bsmAttr.bootstrap_method_specifiers.length); |
aoqi@0 | 411 | for (BootstrapMethods_attribute.BootstrapMethodSpecifier bsms : |
aoqi@0 | 412 | bsmAttr.bootstrap_method_specifiers) { |
aoqi@0 | 413 | int index = bsms.bootstrap_method_ref; |
aoqi@0 | 414 | try { |
aoqi@0 | 415 | String value = slist.get(index); |
aoqi@0 | 416 | if (value == null) { |
aoqi@0 | 417 | value = visit(cfpool.get(index), index); |
aoqi@0 | 418 | debugln("[SG]: index " + index); |
aoqi@0 | 419 | debugln("[SG]: value " + value); |
aoqi@0 | 420 | slist.set(index, value); |
aoqi@0 | 421 | out.put(index, value); |
aoqi@0 | 422 | } |
aoqi@0 | 423 | for (int idx : bsms.bootstrap_arguments) { |
aoqi@0 | 424 | value = slist.get(idx); |
aoqi@0 | 425 | if (value == null) { |
aoqi@0 | 426 | value = visit(cfpool.get(idx), idx); |
aoqi@0 | 427 | debugln("[SG]: idx " + idx); |
aoqi@0 | 428 | debugln("[SG]: value " + value); |
aoqi@0 | 429 | slist.set(idx, value); |
aoqi@0 | 430 | out.put(idx, value); |
aoqi@0 | 431 | } |
aoqi@0 | 432 | } |
aoqi@0 | 433 | } catch (InvalidIndex ex) { |
aoqi@0 | 434 | ex.printStackTrace(); |
aoqi@0 | 435 | } |
aoqi@0 | 436 | } |
aoqi@0 | 437 | return out; |
aoqi@0 | 438 | } |
aoqi@0 | 439 | return new HashMap<>(0); |
aoqi@0 | 440 | } |
aoqi@0 | 441 | |
aoqi@0 | 442 | @Override |
aoqi@0 | 443 | public String visitClass(CONSTANT_Class_info c, Integer p) { |
aoqi@0 | 444 | |
aoqi@0 | 445 | String value = slist.get(p); |
aoqi@0 | 446 | if (value == null) { |
aoqi@0 | 447 | try { |
aoqi@0 | 448 | value = visit(cfpool.get(c.name_index), c.name_index); |
aoqi@0 | 449 | slist.set(p, value); |
aoqi@0 | 450 | } catch (ConstantPoolException ex) { |
aoqi@0 | 451 | ex.printStackTrace(); |
aoqi@0 | 452 | } |
aoqi@0 | 453 | } |
aoqi@0 | 454 | return value; |
aoqi@0 | 455 | } |
aoqi@0 | 456 | |
aoqi@0 | 457 | @Override |
aoqi@0 | 458 | public String visitDouble(CONSTANT_Double_info c, Integer p) { |
aoqi@0 | 459 | |
aoqi@0 | 460 | String value = slist.get(p); |
aoqi@0 | 461 | if (value == null) { |
aoqi@0 | 462 | value = Double.toString(c.value); |
aoqi@0 | 463 | slist.set(p, value); |
aoqi@0 | 464 | } |
aoqi@0 | 465 | return value; |
aoqi@0 | 466 | } |
aoqi@0 | 467 | |
aoqi@0 | 468 | @Override |
aoqi@0 | 469 | public String visitFieldref(CONSTANT_Fieldref_info c, Integer p) { |
aoqi@0 | 470 | |
aoqi@0 | 471 | String value = slist.get(p); |
aoqi@0 | 472 | if (value == null) { |
aoqi@0 | 473 | try { |
aoqi@0 | 474 | value = visit(cfpool.get(c.class_index), c.class_index); |
aoqi@0 | 475 | value = value.concat(" " + visit(cfpool.get(c.name_and_type_index), |
aoqi@0 | 476 | c.name_and_type_index)); |
aoqi@0 | 477 | slist.set(p, value); |
aoqi@0 | 478 | } catch (ConstantPoolException ex) { |
aoqi@0 | 479 | ex.printStackTrace(); |
aoqi@0 | 480 | } |
aoqi@0 | 481 | } |
aoqi@0 | 482 | return value; |
aoqi@0 | 483 | } |
aoqi@0 | 484 | |
aoqi@0 | 485 | @Override |
aoqi@0 | 486 | public String visitFloat(CONSTANT_Float_info c, Integer p) { |
aoqi@0 | 487 | |
aoqi@0 | 488 | String value = slist.get(p); |
aoqi@0 | 489 | if (value == null) { |
aoqi@0 | 490 | value = Float.toString(c.value); |
aoqi@0 | 491 | slist.set(p, value); |
aoqi@0 | 492 | } |
aoqi@0 | 493 | return value; |
aoqi@0 | 494 | } |
aoqi@0 | 495 | |
aoqi@0 | 496 | @Override |
aoqi@0 | 497 | public String visitInteger(CONSTANT_Integer_info cnstnt, Integer p) { |
aoqi@0 | 498 | |
aoqi@0 | 499 | String value = slist.get(p); |
aoqi@0 | 500 | if (value == null) { |
aoqi@0 | 501 | value = Integer.toString(cnstnt.value); |
aoqi@0 | 502 | slist.set(p, value); |
aoqi@0 | 503 | } |
aoqi@0 | 504 | return value; |
aoqi@0 | 505 | } |
aoqi@0 | 506 | |
aoqi@0 | 507 | @Override |
aoqi@0 | 508 | public String visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info c, |
aoqi@0 | 509 | Integer p) { |
aoqi@0 | 510 | |
aoqi@0 | 511 | String value = slist.get(p); |
aoqi@0 | 512 | if (value == null) { |
aoqi@0 | 513 | try { |
aoqi@0 | 514 | value = visit(cfpool.get(c.class_index), c.class_index); |
aoqi@0 | 515 | value = value.concat(" " + |
aoqi@0 | 516 | visit(cfpool.get(c.name_and_type_index), |
aoqi@0 | 517 | c.name_and_type_index)); |
aoqi@0 | 518 | slist.set(p, value); |
aoqi@0 | 519 | } catch (ConstantPoolException ex) { |
aoqi@0 | 520 | ex.printStackTrace(); |
aoqi@0 | 521 | } |
aoqi@0 | 522 | } |
aoqi@0 | 523 | return value; |
aoqi@0 | 524 | } |
aoqi@0 | 525 | |
aoqi@0 | 526 | @Override |
aoqi@0 | 527 | public String visitInvokeDynamic(CONSTANT_InvokeDynamic_info c, Integer p) { |
aoqi@0 | 528 | |
aoqi@0 | 529 | String value = slist.get(p); |
aoqi@0 | 530 | if (value == null) { |
aoqi@0 | 531 | try { |
aoqi@0 | 532 | value = bsmMap.get(c.bootstrap_method_attr_index) + " " |
aoqi@0 | 533 | + visit(cfpool.get(c.name_and_type_index), c.name_and_type_index); |
aoqi@0 | 534 | slist.set(p, value); |
aoqi@0 | 535 | } catch (ConstantPoolException ex) { |
aoqi@0 | 536 | ex.printStackTrace(); |
aoqi@0 | 537 | } |
aoqi@0 | 538 | } |
aoqi@0 | 539 | return value; |
aoqi@0 | 540 | } |
aoqi@0 | 541 | |
aoqi@0 | 542 | @Override |
aoqi@0 | 543 | public String visitLong(CONSTANT_Long_info c, Integer p) { |
aoqi@0 | 544 | |
aoqi@0 | 545 | String value = slist.get(p); |
aoqi@0 | 546 | if (value == null) { |
aoqi@0 | 547 | value = Long.toString(c.value); |
aoqi@0 | 548 | slist.set(p, value); |
aoqi@0 | 549 | } |
aoqi@0 | 550 | return value; |
aoqi@0 | 551 | } |
aoqi@0 | 552 | |
aoqi@0 | 553 | @Override |
aoqi@0 | 554 | public String visitNameAndType(CONSTANT_NameAndType_info c, Integer p) { |
aoqi@0 | 555 | |
aoqi@0 | 556 | String value = slist.get(p); |
aoqi@0 | 557 | if (value == null) { |
aoqi@0 | 558 | try { |
aoqi@0 | 559 | value = visit(cfpool.get(c.name_index), c.name_index); |
aoqi@0 | 560 | value = value.concat(" " + |
aoqi@0 | 561 | visit(cfpool.get(c.type_index), c.type_index)); |
aoqi@0 | 562 | slist.set(p, value); |
aoqi@0 | 563 | } catch (InvalidIndex ex) { |
aoqi@0 | 564 | ex.printStackTrace(); |
aoqi@0 | 565 | } |
aoqi@0 | 566 | } |
aoqi@0 | 567 | return value; |
aoqi@0 | 568 | } |
aoqi@0 | 569 | |
aoqi@0 | 570 | @Override |
aoqi@0 | 571 | public String visitMethodref(CONSTANT_Methodref_info c, Integer p) { |
aoqi@0 | 572 | |
aoqi@0 | 573 | String value = slist.get(p); |
aoqi@0 | 574 | if (value == null) { |
aoqi@0 | 575 | try { |
aoqi@0 | 576 | value = visit(cfpool.get(c.class_index), c.class_index); |
aoqi@0 | 577 | value = value.concat(" " + |
aoqi@0 | 578 | visit(cfpool.get(c.name_and_type_index), |
aoqi@0 | 579 | c.name_and_type_index)); |
aoqi@0 | 580 | slist.set(p, value); |
aoqi@0 | 581 | } catch (ConstantPoolException ex) { |
aoqi@0 | 582 | ex.printStackTrace(); |
aoqi@0 | 583 | } |
aoqi@0 | 584 | } |
aoqi@0 | 585 | return value; |
aoqi@0 | 586 | } |
aoqi@0 | 587 | |
aoqi@0 | 588 | @Override |
aoqi@0 | 589 | public String visitMethodHandle(CONSTANT_MethodHandle_info c, Integer p) { |
aoqi@0 | 590 | |
aoqi@0 | 591 | String value = slist.get(p); |
aoqi@0 | 592 | if (value == null) { |
aoqi@0 | 593 | try { |
aoqi@0 | 594 | value = c.reference_kind.name(); |
aoqi@0 | 595 | value = value.concat(" " |
aoqi@0 | 596 | + visit(cfpool.get(c.reference_index), c.reference_index)); |
aoqi@0 | 597 | slist.set(p, value); |
aoqi@0 | 598 | } catch (ConstantPoolException ex) { |
aoqi@0 | 599 | ex.printStackTrace(); |
aoqi@0 | 600 | } |
aoqi@0 | 601 | } |
aoqi@0 | 602 | return value; |
aoqi@0 | 603 | } |
aoqi@0 | 604 | |
aoqi@0 | 605 | @Override |
aoqi@0 | 606 | public String visitMethodType(CONSTANT_MethodType_info c, Integer p) { |
aoqi@0 | 607 | |
aoqi@0 | 608 | String value = slist.get(p); |
aoqi@0 | 609 | if (value == null) { |
aoqi@0 | 610 | try { |
aoqi@0 | 611 | value = visit(cfpool.get(c.descriptor_index), c.descriptor_index); |
aoqi@0 | 612 | slist.set(p, value); |
aoqi@0 | 613 | } catch (ConstantPoolException ex) { |
aoqi@0 | 614 | ex.printStackTrace(); |
aoqi@0 | 615 | } |
aoqi@0 | 616 | } |
aoqi@0 | 617 | return value; |
aoqi@0 | 618 | } |
aoqi@0 | 619 | |
aoqi@0 | 620 | @Override |
aoqi@0 | 621 | public String visitString(CONSTANT_String_info c, Integer p) { |
aoqi@0 | 622 | |
aoqi@0 | 623 | try { |
aoqi@0 | 624 | String value = slist.get(p); |
aoqi@0 | 625 | if (value == null) { |
aoqi@0 | 626 | value = c.getString(); |
aoqi@0 | 627 | slist.set(p, value); |
aoqi@0 | 628 | } |
aoqi@0 | 629 | return value; |
aoqi@0 | 630 | } catch (ConstantPoolException ex) { |
aoqi@0 | 631 | throw new RuntimeException("Fatal error", ex); |
aoqi@0 | 632 | } |
aoqi@0 | 633 | } |
aoqi@0 | 634 | |
aoqi@0 | 635 | @Override |
aoqi@0 | 636 | public String visitUtf8(CONSTANT_Utf8_info cnstnt, Integer p) { |
aoqi@0 | 637 | |
aoqi@0 | 638 | String value = slist.get(p); |
aoqi@0 | 639 | if (value == null) { |
aoqi@0 | 640 | value = cnstnt.value; |
aoqi@0 | 641 | slist.set(p, value); |
aoqi@0 | 642 | } |
aoqi@0 | 643 | return value; |
aoqi@0 | 644 | } |
aoqi@0 | 645 | } |
aoqi@0 | 646 | } |
aoqi@0 | 647 |