com.strobel.assembler.metadata.MetadataSystem Maven / Gradle / Ivy
/*
* MetadataSystem.java
*
* Copyright (c) 2013 Mike Strobel
*
* This source code is based on Mono.Cecil from Jb Evain, Copyright (c) Jb Evain;
* and ILSpy/ICSharpCode from SharpDevelop, Copyright (c) AlphaSierraPapa.
*
* This source code is subject to terms and conditions of the Apache License, Version 2.0.
* A copy of the license can be found in the License.html file at the root of this distribution.
* By using this source code in any fashion, you are agreeing to be bound by the terms of the
* Apache License, Version 2.0.
*
* You must not remove this notice, or any other, from this software.
*/
package com.strobel.assembler.metadata;
import com.strobel.compilerservices.RuntimeHelpers;
import com.strobel.core.Fences;
import com.strobel.core.VerifyArgument;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author Mike Strobel
*/
public class MetadataSystem extends MetadataResolver {
private static MetadataSystem _instance;
private final ConcurrentHashMap _types;
private final ITypeLoader _typeLoader;
private boolean _isEagerMethodLoadingEnabled;
public static MetadataSystem instance() {
if (_instance == null) {
synchronized (MetadataSystem.class) {
if (_instance == null) {
_instance = Fences.orderWrites(new MetadataSystem());
}
}
}
return _instance;
}
public MetadataSystem() {
this(new ClasspathTypeLoader());
}
public MetadataSystem(final String classPath) {
this(new ClasspathTypeLoader(VerifyArgument.notNull(classPath, "classPath")));
}
public MetadataSystem(final ITypeLoader typeLoader) {
_typeLoader = VerifyArgument.notNull(typeLoader, "typeLoader");
_types = new ConcurrentHashMap<>();
}
public final boolean isEagerMethodLoadingEnabled() {
return _isEagerMethodLoadingEnabled;
}
public final void setEagerMethodLoadingEnabled(final boolean value) {
_isEagerMethodLoadingEnabled = value;
}
public void addTypeDefinition(final TypeDefinition type) {
VerifyArgument.notNull(type, "type");
_types.putIfAbsent(type.getInternalName(), type);
}
@Override
protected TypeDefinition resolveCore(final TypeReference type) {
VerifyArgument.notNull(type, "type");
return resolveType(type.getInternalName(), false);
}
@Override
protected TypeReference lookupTypeCore(final String descriptor) {
return resolveType(descriptor, true);
}
protected TypeDefinition resolveType(final String descriptor, final boolean mightBePrimitive) {
VerifyArgument.notNull(descriptor, "descriptor");
if (mightBePrimitive) {
if (descriptor.length() == 1) {
final int primitiveHash = descriptor.charAt(0) - 'B';
if (primitiveHash >= 0 && primitiveHash < PRIMITIVE_TYPES_BY_DESCRIPTOR.length) {
final TypeDefinition primitiveType = PRIMITIVE_TYPES_BY_DESCRIPTOR[primitiveHash];
if (primitiveType != null) {
return primitiveType;
}
}
}
else {
final int primitiveHash = hashPrimitiveName(descriptor);
if (primitiveHash >= 0 && primitiveHash < PRIMITIVE_TYPES_BY_NAME.length) {
final TypeDefinition primitiveType = PRIMITIVE_TYPES_BY_NAME[primitiveHash];
if (primitiveType != null && descriptor.equals(primitiveType.getName())) {
return primitiveType;
}
}
}
}
TypeDefinition cachedDefinition = _types.get(descriptor);
if (cachedDefinition != null) {
return cachedDefinition;
}
final Buffer buffer = new Buffer(0);
if (!_typeLoader.tryLoadType(descriptor, buffer)) {
return null;
}
final TypeDefinition typeDefinition = ClassFileReader.readClass(
_isEagerMethodLoadingEnabled ? ClassFileReader.OPTIONS_DEFAULT | ClassFileReader.OPTION_PROCESS_CODE
: ClassFileReader.OPTIONS_DEFAULT,
this,
buffer
);
cachedDefinition = _types.putIfAbsent(descriptor, typeDefinition);
typeDefinition.setTypeLoader(_typeLoader);
if (cachedDefinition != null) {
return cachedDefinition;
}
return typeDefinition;
}
//
private final static TypeDefinition[] PRIMITIVE_TYPES_BY_NAME = new TypeDefinition['Z' - 'B' + 1];
private final static TypeDefinition[] PRIMITIVE_TYPES_BY_DESCRIPTOR = new TypeDefinition[16];
static {
RuntimeHelpers.ensureClassInitialized(BuiltinTypes.class);
final TypeDefinition[] allPrimitives = {
BuiltinTypes.Boolean,
BuiltinTypes.Byte,
BuiltinTypes.Character,
BuiltinTypes.Short,
BuiltinTypes.Integer,
BuiltinTypes.Long,
BuiltinTypes.Float,
BuiltinTypes.Double,
BuiltinTypes.Void
};
for (final TypeDefinition t : allPrimitives) {
PRIMITIVE_TYPES_BY_DESCRIPTOR[hashPrimitiveName(t.getName())] = t;
PRIMITIVE_TYPES_BY_NAME[t.getInternalName().charAt(0) - 'B'] = t;
}
}
private static int hashPrimitiveName(final String name) {
if (name.length() < 3) {
return 0;
}
return (name.charAt(0) + name.charAt(2)) % 16;
}
//
}