001/* 002 * Copyright (c) 2012-2017 Institut National des Sciences Appliquées de Lyon (INSA-Lyon) 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the Eclipse Public License v1.0 006 * which accompanies this distribution, and is available at 007 * http://www.eclipse.org/legal/epl-v10.html 008 */ 009 010package org.eclipse.golo.runtime; 011 012import java.lang.invoke.CallSite; 013import java.lang.invoke.ConstantCallSite; 014import java.lang.invoke.MethodHandles; 015import java.lang.invoke.MethodType; 016 017import static org.eclipse.golo.runtime.Module.imports; 018import static java.lang.invoke.MethodHandles.constant; 019 020import static gololang.Messages.message; 021 022public final class ClassReferenceSupport { 023 024 private ClassReferenceSupport() { 025 throw new UnsupportedOperationException("Don't instantiate invokedynamic bootstrap class"); 026 } 027 028 public static CallSite bootstrap(MethodHandles.Lookup caller, String name, MethodType type) throws ClassNotFoundException { 029 String className = name.replaceAll("#", "\\."); 030 Class<?> callerClass = caller.lookupClass(); 031 ClassLoader classLoader = callerClass.getClassLoader(); 032 033 Class<?> classRef = tryLoadingFromPrimitiveType(className); 034 if (classRef != null) { 035 return createCallSite(classRef); 036 } 037 classRef = tryLoadingFromName(className, classLoader, callerClass.getName()); 038 if (classRef != null) { 039 return createCallSite(classRef); 040 } 041 classRef = tryLoadingFromImports(className, callerClass, classLoader); 042 if (classRef != null) { 043 return createCallSite(classRef); 044 } 045 throw new ClassNotFoundException(message("class_not_resolved", className)); 046 } 047 048 private static Class<?> tryLoadingFromName(String name, ClassLoader classLoader, String callerName) { 049 try { 050 return Class.forName(name, true, classLoader); 051 } catch (ClassNotFoundException e) { 052 Warnings.unavailableClass(name, callerName); 053 return null; 054 } 055 } 056 057 private static Class<?> tryLoadingFromImports(String className, Class<?> callerClass, ClassLoader classLoader) { 058 for (String importedClassName : imports(callerClass)) { 059 Class<?> classRef = tryLoadingFromName(importedClassName + "." + className, classLoader, callerClass.getName()); 060 if (classRef != null) { 061 return classRef; 062 } else { 063 if (importedClassName.endsWith(className)) { 064 classRef = tryLoadingFromName(importedClassName, classLoader, callerClass.getName()); 065 if (classRef != null) { 066 return classRef; 067 } 068 } 069 } 070 } 071 return null; 072 } 073 074 private static Class<?> tryLoadingFromPrimitiveType(String name) { 075 switch (name) { 076 case "byte" : return byte.class; 077 case "char" : return char.class; 078 case "int" : return int.class; 079 case "long" : return long.class; 080 case "double" : return double.class; 081 case "short" : return short.class; 082 case "float" : return float.class; 083 case "boolean" : return boolean.class; 084 default: return null; 085 } 086 } 087 088 private static CallSite createCallSite(Class<?> classRef) { 089 return new ConstantCallSite(constant(Class.class, classRef)); 090 } 091 092}