comparison graal/com.oracle.jvmci.hotspot/src/com/oracle/jvmci/hotspot/HotSpotVMConfigVerifier.java @ 21551:5324104ac4f3

moved com.oracle.graal.hotspot.jvmci classes to com.oracle.jvmci.hotspot module (JBS:GRAAL-53)
author Doug Simon <doug.simon@oracle.com>
date Tue, 26 May 2015 17:13:37 +0200
parents
children
comparison
equal deleted inserted replaced
21550:f48a6cea31eb 21551:5324104ac4f3
1 /*
2 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23 package com.oracle.jvmci.hotspot;
24
25 import static java.lang.String.*;
26
27 import java.io.*;
28 import java.lang.reflect.*;
29 import java.util.*;
30
31 import jdk.internal.org.objectweb.asm.*;
32 import jdk.internal.org.objectweb.asm.Type;
33 import sun.misc.*;
34
35 import com.oracle.jvmci.common.*;
36
37 /**
38 * A {@link ClassVisitor} that verifies {@link HotSpotVMConfig} does not access {@link Unsafe} from
39 * any of its non-static, non-constructor methods. This ensures that a deserialized
40 * {@link HotSpotVMConfig} object does not perform any unsafe reads on addresses that are only valid
41 * in the context in which the object was serialized. Note that this does not catch cases where a
42 * client uses an address stored in a {@link HotSpotVMConfig} field.
43 */
44 final class HotSpotVMConfigVerifier extends ClassVisitor {
45
46 public static boolean check() {
47 Class<?> cls = HotSpotVMConfig.class;
48 String classFilePath = "/" + cls.getName().replace('.', '/') + ".class";
49 try {
50 InputStream classfile = cls.getResourceAsStream(classFilePath);
51 ClassReader cr = new ClassReader(Objects.requireNonNull(classfile, "Could not find class file for " + cls.getName()));
52 ClassVisitor cv = new HotSpotVMConfigVerifier();
53 cr.accept(cv, 0);
54 return true;
55 } catch (IOException e) {
56 throw new JVMCIError(e);
57 }
58 }
59
60 /**
61 * Source file context for error reporting.
62 */
63 String sourceFile = null;
64
65 /**
66 * Line number for error reporting.
67 */
68 int lineNo = -1;
69
70 private static Class<?> resolve(String name) {
71 try {
72 return Class.forName(name.replace('/', '.'));
73 } catch (ClassNotFoundException e) {
74 throw new JVMCIError(e);
75 }
76 }
77
78 HotSpotVMConfigVerifier() {
79 super(Opcodes.ASM5);
80 }
81
82 @Override
83 public void visitSource(String source, String debug) {
84 this.sourceFile = source;
85 }
86
87 void verify(boolean condition, String message) {
88 if (!condition) {
89 error(message);
90 }
91 }
92
93 void error(String message) {
94 String errorMessage = format("%s:%d: %s is not allowed in the context of compilation replay. The unsafe access should be moved into the %s constructor and the result cached in a field",
95 sourceFile, lineNo, message, HotSpotVMConfig.class.getSimpleName());
96 throw new JVMCIError(errorMessage);
97
98 }
99
100 @Override
101 public MethodVisitor visitMethod(int access, String name, String d, String signature, String[] exceptions) {
102 if (!Modifier.isStatic(access) && Modifier.isPublic(access) && !name.equals("<init>")) {
103 return new MethodVisitor(Opcodes.ASM5) {
104
105 @Override
106 public void visitLineNumber(int line, Label start) {
107 lineNo = line;
108 }
109
110 private Executable resolveMethod(String owner, String methodName, String methodDesc) {
111 Class<?> declaringClass = resolve(owner);
112 while (declaringClass != null) {
113 if (methodName.equals("<init>")) {
114 for (Constructor<?> c : declaringClass.getDeclaredConstructors()) {
115 if (methodDesc.equals(Type.getConstructorDescriptor(c))) {
116 return c;
117 }
118 }
119 } else {
120 Type[] argumentTypes = Type.getArgumentTypes(methodDesc);
121 for (Method m : declaringClass.getDeclaredMethods()) {
122 if (m.getName().equals(methodName)) {
123 if (Arrays.equals(argumentTypes, Type.getArgumentTypes(m))) {
124 if (Type.getReturnType(methodDesc).equals(Type.getReturnType(m))) {
125 return m;
126 }
127 }
128 }
129 }
130 }
131 declaringClass = declaringClass.getSuperclass();
132 }
133 throw new NoSuchMethodError(owner + "." + methodName + methodDesc);
134 }
135
136 /**
137 * Checks whether a given method is allowed to be called.
138 */
139 private boolean checkInvokeTarget(Executable method) {
140 if (method.getDeclaringClass().equals(Unsafe.class)) {
141 return false;
142 }
143 return true;
144 }
145
146 @Override
147 public void visitMethodInsn(int opcode, String owner, String methodName, String methodDesc, boolean itf) {
148 Executable callee = resolveMethod(owner, methodName, methodDesc);
149 verify(checkInvokeTarget(callee), "invocation of " + callee);
150 }
151 };
152 } else {
153 return null;
154 }
155 }
156 }