001/* 002 * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.hotspot.logging; 024 025import java.lang.reflect.*; 026import java.util.*; 027import java.util.concurrent.*; 028import java.util.concurrent.atomic.*; 029 030import com.oracle.graal.debug.*; 031 032/** 033 * A java.lang.reflect proxy that hierarchically logs all method invocations along with their 034 * parameters and return values. 035 */ 036public class CountingProxy<T> implements InvocationHandler { 037 038 public static final boolean ENABLED = Boolean.valueOf(System.getProperty("jvmci.countcalls")); 039 040 private T delegate; 041 042 private ConcurrentHashMap<Method, AtomicLong> calls = new ConcurrentHashMap<>(); 043 044 public CountingProxy(T delegate) { 045 assert ENABLED; 046 TTY.println("Counting proxy for " + delegate.getClass().getSimpleName() + " created"); 047 this.delegate = delegate; 048 proxies.add(this); 049 } 050 051 @Override 052 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 053 int argCount = args == null ? 0 : args.length; 054 if (method.getParameterTypes().length != argCount) { 055 throw new RuntimeException("wrong parameter count"); 056 } 057 final Object result; 058 if (!calls.containsKey(method)) { 059 calls.putIfAbsent(method, new AtomicLong(0)); 060 } 061 AtomicLong count = calls.get(method); 062 count.incrementAndGet(); 063 try { 064 if (args == null) { 065 result = method.invoke(delegate); 066 } else { 067 result = method.invoke(delegate, args); 068 } 069 } catch (InvocationTargetException e) { 070 throw e.getCause(); 071 } 072 return result; 073 } 074 075 public static <T> T getProxy(Class<T> interf, T delegate) { 076 Class<?>[] interfaces = ProxyUtil.getAllInterfaces(delegate.getClass()); 077 Object obj = Proxy.newProxyInstance(interf.getClassLoader(), interfaces, new CountingProxy<>(delegate)); 078 return interf.cast(obj); 079 } 080 081 private static ArrayList<CountingProxy<?>> proxies = new ArrayList<>(); 082 083 static { 084 if (ENABLED) { 085 Runtime.getRuntime().addShutdownHook(new Thread() { 086 087 @Override 088 public void run() { 089 for (CountingProxy<?> proxy : proxies) { 090 proxy.print(); 091 } 092 } 093 }); 094 } 095 } 096 097 protected void print() { 098 long sum = 0; 099 for (Map.Entry<Method, AtomicLong> entry : calls.entrySet()) { 100 Method method = entry.getKey(); 101 long count = entry.getValue().get(); 102 sum += count; 103 TTY.println(delegate.getClass().getSimpleName() + "." + method.getName() + ": " + count); 104 } 105 TTY.println(delegate.getClass().getSimpleName() + " calls: " + sum); 106 } 107}