Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2010-2012 VMware and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springsource.loaded;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
/**
* @author Andy Clement
* @since 0.5.0
*/
class ConstructorCopier extends MethodVisitor implements Constants {
private final static int preInvokeSpecial = 0;
private final static int postInvokeSpecial = 1;
// It is important to know when an INVOKESPECIAL is hit, whether it is our actual one that delegates to the super or just
// one being invoked due to some early object construction prior to the real INVOKESPECIAL running. By tracking
// how many unitialized objects there are (count the NEWs) and how many INVOKESPECIALs have occurred, it is possible
// to identify the right one.
private int state = preInvokeSpecial;
private int unitializedObjectsCount = 0;
private TypeDescriptor typeDescriptor;
private String suffix;
private String classname;
public ConstructorCopier(MethodVisitor mv, TypeDescriptor typeDescriptor, String suffix, String classname) {
super(ASM5,mv);
this.typeDescriptor = typeDescriptor;
this.suffix = suffix;
this.classname = classname;
}
@Override
public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
// Rename 'this' to 'thiz' in executor otherwise Eclipse debugger will fail (static method with 'this')
if (index == 0 && name.equals("this")) {
super.visitLocalVariable("thiz", desc, signature, start, end, index);
} else {
super.visitLocalVariable(name, desc, signature, start, end, index);
}
}
@Override
public void visitFieldInsn(final int opcode, final String owner, final String name, final String desc) {
super.visitFieldInsn(opcode, owner, name, desc);
}
@Override
public void visitTypeInsn(final int opcode, final String type) {
if (opcode == NEW) {
unitializedObjectsCount++;
}
super.visitTypeInsn(opcode, type);
}
// TODO may need to pay attention itf==true
@Override
public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc, boolean itf) {
// If this is an invokespecial, first determine if it is the one of interest (the one calling our super constructor)
if (opcode == INVOKESPECIAL && name.charAt(0) == '<') {
if (unitializedObjectsCount != 0) {
unitializedObjectsCount--;
} else {
// This looks like our INVOKESPECIAL
if (state == preInvokeSpecial) {
// special case for calling jlObject, do nothing!
if (owner.equals("java/lang/Object")) {
mv.visitInsn(POP);
} else {
// Need to replace this INVOKESPECIAL call.
String supertypename = typeDescriptor.getSupertypeName();
ReloadableType superRtype = typeDescriptor.getReloadableType().getTypeRegistry()
.getReloadableSuperType(supertypename);
if (superRtype == null) {
// supertype was not reloadable. This either means it really isn't (doesn't match what we consider reloadable)
// or it just hasn't been loaded yet.
// In a real scenario supertypes will get loaded first always and this can't happen (the latter case) - it happens in tests
// because they don't actively load all their bits and pieces in a hierarchical way. Given that on a reloadable boundary
// the magic ctors are setup to call a default ctor, we can assume that above the boundary the object has been initialized.
// this means we don't need to call a super __init__ or __execute...
if (typeDescriptor.getReloadableType().getTypeRegistry().isReloadableTypeName(supertypename)) {
superRtype = typeDescriptor.getReloadableType().getTypeRegistry()
.getReloadableSuperType(supertypename);
throw new IllegalStateException("The supertype " + supertypename.replace('/', '.')
+ " has not been loaded as a reloadabletype");
}
Utils.insertPopsForAllParameters(mv, desc);
mv.visitInsn(POP); // pop 'this'
} else {
// Check the original form of the supertype for a constructor to call
MethodMember existingCtor = (superRtype == null ? null : superRtype.getTypeDescriptor().getConstructor(
desc));
if (existingCtor == null) {
// It did not exist in the original supertype version, need to use dynamic dispatch method
// collapse the arguments on the stack
Utils.collapseStackToArray(mv, desc);
// now the stack is the instance then the params
mv.visitInsn(SWAP);
mv.visitInsn(DUP_X1);
// no stack is instance then params then instance
mv.visitLdcInsn("" + desc);
mv.visitMethodInsn(INVOKESPECIAL, typeDescriptor.getSupertypeName(), mDynamicDispatchName,
mDynamicDispatchDescriptor, false);
mv.visitInsn(POP);
} else {
// it did exist in the original, so there will be parallel constructor
mv.visitMethodInsn(INVOKESPECIAL, typeDescriptor.getSupertypeName(), mInitializerName, desc, false);
}
}
}
state = postInvokeSpecial;
return;
}
}
}
// Is it a private method call?
// TODO r$ check here because we use invokespecial to avoid virtual dispatch on field changes...
if (opcode == INVOKESPECIAL && name.charAt(0) != '<' && owner.equals(classname) && !name.startsWith("r$")) {
// leaving the invokespecial alone will cause a verify error
String descriptor = Utils.insertExtraParameter(owner, desc);
super.visitMethodInsn(INVOKESTATIC, Utils.getExecutorName(classname, suffix), name, descriptor, false);
} else {
boolean done = false;
// TODO dup of code in method copier - can we refactor?
if (opcode == INVOKESTATIC) {
MethodMember mm = typeDescriptor.getByDescriptor(name, desc);
if (mm != null && mm.isPrivate()) {
super.visitMethodInsn(INVOKESTATIC, Utils.getExecutorName(classname, suffix), name, desc, false);
done = true;
}
}
if (!done) {
super.visitMethodInsn(opcode, owner, name, desc, itf);
}
}
}
}