001/* 002 * Copyright (c) 2012-2018 Institut National des Sciences Appliquées de Lyon (INSA Lyon) and others 003 * 004 * This program and the accompanying materials are made available under the 005 * terms of the Eclipse Public License 2.0 which is available at 006 * http://www.eclipse.org/legal/epl-2.0. 007 * 008 * SPDX-License-Identifier: EPL-2.0 009 */ 010 011package org.eclipse.golo.runtime; 012 013import java.lang.invoke.CallSite; 014import java.lang.invoke.ConstantCallSite; 015import java.lang.invoke.MethodHandles.Lookup; 016import java.lang.invoke.MethodType; 017 018import static gololang.Messages.message; 019import static java.lang.invoke.MethodHandles.constant; 020import static org.eclipse.golo.runtime.Module.imports; 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(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}