/*
 * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
 *
 * This file is part of Resin(R) Open Source
 *
 * Each copy or derived work must preserve the copyright notice and this
 * notice unmodified.
 *
 * Resin Open Source is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Resin Open Source is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
 * of NON-INFRINGEMENT.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Resin Open Source; if not, write to the
 *
 *   Free Software Foundation, Inc.
 *   59 Temple Place, Suite 330
 *   Boston, MA 02111-1307  USA
 *
 * @author Scott Ferguson
 */

package com.caucho.loader.enhancer;

import java.io.InputStream;
import java.io.IOException;

import java.net.URL;

import java.security.Permission;

import java.util.ArrayList;
import java.util.Enumeration;

import java.util.logging.Logger;
import java.util.logging.Level;

import com.caucho.bytecode.Attribute;
import com.caucho.bytecode.ByteCodeParser;
import com.caucho.bytecode.JClass;
import com.caucho.bytecode.JavaClass;
import com.caucho.bytecode.JavaClassLoader;
import com.caucho.bytecode.JavaField;
import com.caucho.bytecode.JavaMethod;
import com.caucho.bytecode.ConstantPool;
import com.caucho.bytecode.ConstantPoolEntry;
import com.caucho.bytecode.FieldRefConstant;
import com.caucho.bytecode.MethodRefConstant;
import com.caucho.bytecode.Utf8Constant;
import com.caucho.bytecode.CodeVisitor;
import com.caucho.bytecode.CodeEnhancer;
import com.caucho.bytecode.Analyzer;
import com.caucho.bytecode.CodeAttribute;

import com.caucho.java.WorkDir;
import com.caucho.java.CompileClassNotFound;

import com.caucho.java.gen.JavaClassGenerator;

import com.caucho.loader.EnvironmentClassLoader;
import com.caucho.loader.DynamicClassLoader;
import com.caucho.loader.SimpleLoader;
import com.caucho.loader.ClassLoaderListener;
import com.caucho.loader.ClassEntry;
import com.caucho.loader.Loader;

import com.caucho.util.L10N;

import com.caucho.vfs.Vfs;
import com.caucho.vfs.Path;
import com.caucho.vfs.ReadStream;
import com.caucho.vfs.WriteStream;

/**
 * Class loader which checks for changes in class files and automatically
 * picks up new jars.
 *
 * <p>DynamicClassLoaders can be chained creating one virtual class loader.
 * From the perspective of the JDK, it's all one classloader.  Internally,
 * the class loader chain searches like a classpath.
 */
public class EnhancerFixup {
  private static final L10N L = new L10N(EnhancerFixup.class);
  private static final Logger log = Logger.getLogger(EnhancerFixup.class.getName());

  private static final int ACC_PUBLIC = 0x1;
  private static final int ACC_PRIVATE = 0x2;
  private static final int ACC_PROTECTED = 0x4;

  private JavaClassGenerator _javaGen = new JavaClassGenerator();

  private JavaClassLoader _jClassLoader;
  private DynamicClassLoader _loader;

  private Path _workPath;

  private String _baseSuffix = "";
  private String _extSuffix = "__ResinExt";

  private ArrayList<ClassEnhancer> _enhancerList =
    new ArrayList<ClassEnhancer>();

  private boolean _isParentStarted;

  /**
   * Sets the class loader.
   */
  public void setClassLoader(DynamicClassLoader loader)
  {
    _loader = loader;
  }

  /**
   * Returns the parsed class loader.
   */
  public void setJavaClassLoader(JavaClassLoader jClassLoader)
  {
    _jClassLoader = jClassLoader;
  }

  /**
   * Returns the parsed class loader.
   */
  public JavaClassLoader getJavaClassLoader()
  {
    return _jClassLoader;
  }
  
  /**
   * Gets the work path.
   */
  public Path getWorkPath()
  {
    if (_workPath != null)
      return _workPath;
    else
      return WorkDir.getLocalWorkDir();
  }

  /**
   * Sets the work path.
   */
  public void setWorkPath(Path workPath)
  {
    _workPath = workPath;
  }

  /**
   * Gets the work path.
   */
  public final Path getPreWorkPath()
  {
    return getWorkPath().lookup("pre-enhance");
  }

  /**
   * Gets the work path.
   */
  public final Path getPostWorkPath()
  {
    return getWorkPath().lookup("post-enhance");
  }

  /**
   * Adds a class enhancer.
   */
  public void addEnhancer(ClassEnhancer enhancer)
  {
    _enhancerList.add(enhancer);
  }

  protected void fixup(String className, String extClassName)
    throws Exception
  {
    Path prePath = getPreWorkPath();
    Path postPath = getPostWorkPath();

    Path source = getSource(className);

    if (source == null || ! source.canRead())
      return;
    
    Path ext = prePath.lookup(extClassName.replace('.', '/') + ".class");
    Path target = postPath.lookup(className.replace('.', '/') + ".class");

    try {
      target.getParent().mkdirs();
    } catch (Throwable e) {
    }

    if (source != null)
      mergeClasses(className, target, source, ext);
    else
      mergeClasses(className, target, ext);

    int p = className.lastIndexOf('.');
    
    Path preTargetDir;
    Path targetDir;
    String classSuffix;
    String prefix = "";

    if (p > 0) {
      prefix = className.substring(0, p).replace('.', '/');
      preTargetDir = prePath.lookup(prefix);
      targetDir = postPath.lookup(prefix);
      classSuffix = className.substring(p + 1);
    }
    else {
      preTargetDir = prePath;
      targetDir = postPath;
      classSuffix = className;
    }

    prefix = prefix.replace('/', '.');
    if (! prefix.equals(""))
      prefix = prefix + ".";

    String extSuffix;
    p = extClassName.lastIndexOf('.');
    if (p > 0)
      extSuffix = extClassName.substring(p + 1);
    else
      extSuffix = extClassName;

    fixupPreSubClasses(preTargetDir, targetDir,
		       extSuffix, classSuffix);
    
    fixupPostSubClasses(targetDir, prefix, classSuffix);
  }

  private void fixupPreSubClasses(Path preTargetDir, Path targetDir,
				  String extSuffix, String classSuffix)
    throws Exception
  {
    String []list = preTargetDir.list();

    for (int i = 0; i < list.length; i++) {
      String name = list[i];

      if (name.startsWith(extSuffix + '$') &&
	  name.endsWith(".class")) {
	int p = name.indexOf('$');
	String targetClass = (classSuffix + '$' +
			      name.substring(p + 1, name.length() - 6));
	  
	Path subTarget = targetDir.lookup(targetClass + ".class");

	Path extPath = preTargetDir.lookup(name);

	renameSubClass(classSuffix, subTarget, extPath);

	//if (_loader != null)
	//  _loader.addPathClass(prefix + targetClass, subTarget);
      }
      else if (name.startsWith(extSuffix + '-') &&
	       name.endsWith(".class")) {
	int p = name.indexOf('-');
	String targetClass = (classSuffix + '-' +
			      name.substring(p + 1, name.length() - 6));
	  
	Path subTarget = targetDir.lookup(targetClass + ".class");
	  
	Path extPath = preTargetDir.lookup(name);

	renameSubClass(classSuffix, subTarget, extPath);

	//if (_loader != null)
	//  _loader.addPathClass(prefix + targetClass, subTarget);
      }
    }
  }

  private void fixupPostSubClasses(Path targetDir,
				   String prefix,
				   String classSuffix)
    throws Exception
  {
    String []list = targetDir.list();

    for (int i = 0; i < list.length; i++) {
      String name = list[i];

      if (! name.endsWith(".class"))
	continue;

      String className = name.substring(0, name.length() - ".class".length());

      if (name.startsWith(classSuffix + '$')) {
	if (_loader != null)
	  _loader.addPathClass(prefix + className, targetDir.lookup(name));
      }
      else if (name.startsWith(classSuffix + '-')) {
	if (_loader != null)
	  _loader.addPathClass(prefix + className, targetDir.lookup(name));
      }
      else if (name.startsWith(classSuffix + '+')) {
	if (_loader != null)
	  _loader.addPathClass(prefix + className, targetDir.lookup(name));
      }
    }
  }

  /**
   * Merges the two classes.
   */
  protected void renameSubClass(String className,
				Path targetPath,
				Path extPath)
    throws Exception
  {
    JavaClass extClass = null;
    
    ByteCodeParser parser = new ByteCodeParser();
    
    parser = new ByteCodeParser();
    parser.setClassLoader(new JavaClassLoader());
    
    ReadStream is = extPath.openRead();
    try {
      extClass = parser.parse(is);
    } finally {
      if (is != null)
	is.close();
    }

    cleanExtConstantPool(className, extClass);

    WriteStream os = targetPath.openWrite();
    try {
      extClass.write(os);
    } finally {
      os.close();
    }
  }

  /**
   * Renamed the super() methods
   */
  protected void renameExtSuperMethods(String className,
				       JavaClass baseClass,
				       JavaClass extClass)
    throws Exception
  {
    ArrayList<ConstantPoolEntry> entries;
    entries = extClass.getConstantPool().getEntries();

    className = className.replace('.', '/');
    String baseName = className + _baseSuffix;
    String extName = className + "__ResinExt";

    for (int i = 0; i < entries.size(); i++) {
      ConstantPoolEntry entry = entries.get(i);

      if (entry instanceof MethodRefConstant) {
	MethodRefConstant methodRef = (MethodRefConstant) entry;

	if (! methodRef.getClassName().equals(baseName))
	  continue;

	String methodName = methodRef.getName();
	String type = methodRef.getType();

	if (findMethod(baseClass, methodName, type) == null)
	  continue;
	
	if (findMethod(extClass, methodName, type) == null)
	  continue;

	if (methodName.equals("<init>")) {
	  methodName = "__init__super";
	  // methodRef.setNameAndType(methodName, type);
	}
	else {
	  methodName = methodName + "__super";
	  methodRef.setNameAndType(methodName, type);
	}
      }
    }
  }


  /**
   * Moves all methods in the base to the __super methods
   */
  private void moveSuperMethods(String className,
				JavaClass baseClass,
				JavaClass extClass)
  {
    className = className.replace('.', '/');
    
    ArrayList<JavaMethod> methods = baseClass.getMethodList();
    
    // Move the __super methods
    ArrayList<JavaMethod> extMethods = extClass.getMethodList();
    for (int i = 0; i < extMethods.size(); i++) {
      JavaMethod extMethod = extMethods.get(i);

      String baseName = extMethod.getName();

      if (baseName.endsWith("__super"))
	continue;

      String superName = baseName + "__super";
      
      int j;
      for (j = 0; j < methods.size(); j++) {
	JavaMethod method = methods.get(j);

	String type = method.getDescriptor();
	
	if (! method.getName().equals(baseName) ||
	    ! method.getDescriptor().equals(extMethod.getDescriptor()))
	  continue;

	if (baseName.equals("<init>")) {
	  baseClass.getConstantPool().addUTF8("__init__super");
	  mergeInitMethods(baseClass, method, extClass, extMethod);
	  break;
	}
	
	if (baseName.equals("<clinit>")) {
	  concatenateMethods(baseClass, method, extClass, extMethod);
	  break;
	}
	
	baseClass.getConstantPool().addUTF8(superName);
	method.setName(superName);
	baseClass.getConstantPool().addUTF8(type);
	method.setDescriptor(type);

	// set the super methods private
	int flags = method.getAccessFlags();
	flags = (flags & ~ACC_PUBLIC & ~ACC_PROTECTED) | ACC_PRIVATE;
	method.setAccessFlags(flags);
	break;
      }
    }
  }

  /**
   * Concatenates methods
   */
  private void concatenateMethods(JavaClass baseClass, JavaMethod baseMethod,
				  JavaClass extClass, JavaMethod extMethod)
  {
    extMethod = extMethod.export(extClass, baseClass);

    baseMethod.concatenate(extMethod);
  }

  /**
   * Merges the init methods
   */
  private void mergeInitMethods(JavaClass baseClass, JavaMethod baseMethod,
				JavaClass extClass, JavaMethod extMethod)
  {
    extMethod = extMethod.export(extClass, baseClass);

    baseMethod.setName("__init__super");

    baseClass.getMethodList().add(extMethod);

    try {
      InitAnalyzer initAnalyzer = new InitAnalyzer();
      CodeEnhancer baseEnhancer = new CodeEnhancer(baseClass, baseMethod.getCode());
      baseEnhancer.analyze(initAnalyzer);

      int offset = initAnalyzer.getOffset();
      byte []code = new byte[offset];
      byte []oldCode = baseEnhancer.getCode();
      System.arraycopy(oldCode, 0, code, 0, offset);
      
      baseEnhancer.remove(0, offset);
      baseEnhancer.update();

      CodeEnhancer extEnhancer = new CodeEnhancer(baseClass, extMethod.getCode());

      extEnhancer.add(0, code, 0, code.length);
      
      ExtInitAnalyzer extInitAnalyzer = new ExtInitAnalyzer(offset);
      extEnhancer.analyze(extInitAnalyzer);
      extEnhancer.update();

      CodeAttribute baseCode = baseMethod.getCode();
      CodeAttribute extCode = extMethod.getCode();
      
      if (extCode.getMaxStack() < baseCode.getMaxStack())
	extCode.setMaxStack(baseCode.getMaxStack());
      
      /*
	baseMethod.concatenate(extMethod);
      */
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  /**
   * Adds the methods from the ext to the base
   */
  private void addExtInterfaces(JavaClass baseClass, JavaClass extClass)
  {
    for (String name : extClass.getInterfaceNames()) {
      baseClass.getConstantPool().addClass(name);

      baseClass.addInterface(name);
    }
  }

  /**
   * Adds the methods from the ext to the base
   */
  private void addExtMethods(JavaClass baseClass, JavaClass extClass)
  {
    ArrayList<JavaMethod> methods = baseClass.getMethodList();
    ArrayList<JavaMethod> extMethods = extClass.getMethodList();

    for (int i = 0; i < extMethods.size(); i++) {
      JavaMethod extMethod = extMethods.get(i);

      if (extMethod.getName().equals("<clinit>") &&
	  findMethod(baseClass, "<clinit>",
		     extMethod.getDescriptor()) != null) {
	continue;
      }
      else if (extMethod.getName().equals("<init>"))
	continue;
      else if (extMethod.getName().endsWith("__super"))
	continue;

      log.finest("adding extension method: " + extClass.getThisClass() + ":" + extMethod.getName());
      
      JavaMethod method = extMethod.export(extClass, baseClass);

      methods.add(method);
    }
  }

  /**
   * Adds the inner classes from the ext to the base
   */
  private void addExtClasses(JavaClass baseClass, JavaClass extClass)
  {
    /*
    ArrayList<JavaMethod> methods = baseClass.getMethodList();
    ArrayList<JavaMethod> extMethods = extClass.getMethodList();

    for (int i = 0; i < extMethods.size(); i++) {
      JavaMethod extMethod = extMethods.get(i);

      if (extMethod.getName().equals("<clinit>") &&
	  findMethod(baseClass, "<clinit>",
		     extMethod.getDescriptor()) != null) {
	continue;
      }
      else if (extMethod.getName().equals("<init>"))
	continue;
      else if (extMethod.getName().endsWith("__super"))
	continue;

      log.finest("adding extension method: " + extClass.getThisClass() + ":" + extMethod.getName());
      
      JavaMethod method = extMethod.export(extClass, baseClass);

      methods.add(method);
    }
    */
  }

  /**
   * Finds a matching method.
   */
  private JavaMethod findMethod(JavaClass cl, String name, String descriptor)
  {
    ArrayList<JavaMethod> methods = cl.getMethodList();
    
    int j;
    for (j = 0; j < methods.size(); j++) {
      JavaMethod method = methods.get(j);

      if (method.getName().equals(name) &&
	  method.getDescriptor().equals(descriptor))
	return method;
    }

    return null;
  }

  /**
   * Adds all fields from the ext to the base
   */
  private void moveSuperFields(JavaClass baseClass, JavaClass extClass)
  {
    ArrayList<JavaField> fields = baseClass.getFieldList();
    ArrayList<JavaField> extFields = extClass.getFieldList();

    for (int i = 0; i < extFields.size(); i++) {
    }
  }

  private Path getSource(String className)
  {
    ClassLoader loader = _loader;
    if (loader == null)
      loader = Thread.currentThread().getContextClassLoader();

    URL url = loader.getResource(className.replace('.', '/') + ".class");
    
    return Vfs.lookup(url.toString());
  }

  /**
   * Merges the two classes.
   */
  protected void mergeClasses(String className,
			      Path targetPath,
			      Path sourcePath,
			      Path extPath)
    throws Exception
  {
    JavaClass baseClass = null;
    JavaClass extClass = null;
    
    ByteCodeParser parser = new ByteCodeParser();
    parser.setClassLoader(getJavaClassLoader());

    ReadStream is = sourcePath.openRead();
    try {
      baseClass = parser.parse(is);
    } finally {
      if (is != null)
	is.close();
    }
    
    parser = new ByteCodeParser();
    parser.setClassLoader(getJavaClassLoader());
    
    is = extPath.openRead();
    try {
      extClass = parser.parse(is);
    } finally {
      if (is != null)
	is.close();
    }

    // The base class will have the modified class
    mergeClasses(className, baseClass, extClass);

    postEnhance(baseClass);

    WriteStream os = targetPath.openWrite();
    try {
      baseClass.write(os);
    } finally {
      os.close();
    }
  }

  /**
   * Merges the two classes.
   */
  protected void mergeClasses(String className,
			      Path targetPath,
			      Path extPath)
    throws Exception
  {
    JavaClass baseClass = null;
    JavaClass extClass = null;
    
    ByteCodeParser parser = new ByteCodeParser();
    parser.setClassLoader(getJavaClassLoader());
    
    ReadStream is = extPath.openRead();
    try {
      extClass = parser.parse(is);
    } finally {
      if (is != null)
	is.close();
    }

    cleanExtConstantPool(className, extClass);

    postEnhance(baseClass);

    WriteStream os = targetPath.openWrite();
    try {
      extClass.write(os);
    } finally {
      os.close();
    }
  }

  /**
   * After enhancement fixup.
   */
  protected void postEnhance(JavaClass baseClass)
    throws Exception
  {
    for (int i = 0; i < _enhancerList.size(); i++) {
      _enhancerList.get(i).postEnhance(baseClass);
    }
  }

  /**
   * Merges the two classes.
   */
  protected void mergeClasses(String className,
			      JavaClass baseClass,
			      JavaClass extClass)
    throws Exception
  {
    if (baseClass.getMajor() < extClass.getMajor()) {
      baseClass.setMajor(extClass.getMajor());
      baseClass.setMinor(extClass.getMinor());
    }
    
    cleanExtConstantPool(className, extClass);
    renameExtSuperMethods(className, baseClass, extClass);
    
    cleanExtConstantPool(className, baseClass);

    addExtInterfaces(baseClass, extClass);
    
    addExtFields(baseClass, extClass);
    
    moveSuperMethods(className, baseClass, extClass);

    addExtMethods(baseClass, extClass);

    copyExtAnnotations(baseClass);

    addExtClasses(baseClass, extClass);
  }

  /**
   * Cleans the ext constant pool, renaming
   */
  protected void cleanExtConstantPool(String className, JavaClass extClass)
    throws Exception
  {
    extClass.setThisClass(replaceString(className, extClass.getThisClass()));
    extClass.setSuperClass(replaceString(className, extClass.getSuperClassName()));
    
    ArrayList<ConstantPoolEntry> entries;
    entries = extClass.getConstantPool().getEntries();

    int t = className.lastIndexOf('.');
    if (t > 0)
      className = className.substring(t + 1);

    String baseName = className + _baseSuffix;
    String extName = className + "__ResinExt";

    for (int i = 0; i < entries.size(); i++) {
      ConstantPoolEntry entry = entries.get(i);

      if (entry instanceof Utf8Constant) {
	Utf8Constant utf8 = (Utf8Constant) entry;

	String string = utf8.getValue();

	string = replaceString(className, string);
	
	utf8.setValue(string);
      }
    }

    ArrayList<JavaField> fields = extClass.getFieldList();
    for (int i = 0; i < fields.size(); i++) {
      JavaField field = fields.get(i);

      field.setName(replaceString(className, field.getName()));
      field.setDescriptor(replaceString(className, field.getDescriptor()));
    }

    ArrayList<JavaMethod> methods = extClass.getMethodList();
    for (int i = 0; i < methods.size(); i++) {
      JavaMethod method = methods.get(i);

      method.setName(replaceString(className, method.getName()));
      method.setDescriptor(replaceString(className, method.getDescriptor()));
    }
  }

  /**
   * Adds the methods from the ext to the base
   */
  private void copyExtAnnotations(JavaClass baseClass)
  {
    for (JavaMethod method : baseClass.getMethodList()) {
      if (method.getName().endsWith("__super")) {
	Attribute ann = method.getAttribute("RuntimeVisibleAnnotations");

	if (ann != null) {
	  String name = method.getName();
	  name = name.substring(0, name.length() - "__super".length());
				
	  JavaMethod baseMethod;
	  baseMethod = findMethod(baseClass, name, method.getDescriptor());

	  if (baseMethod != null)
	    baseMethod.addAttribute(ann);
	}
      }
    }
  }

  /**
   * Adds the methods from the ext to the base
   */
  private void addExtFields(JavaClass baseClass, JavaClass extClass)
  {
    ArrayList<JavaField> fields = baseClass.getFieldList();

    for (JavaField extField : extClass.getFieldList()) {
      JavaField field = extField.export(extClass, baseClass);

      if (! fields.contains(field))
	fields.add(field);
    }
  }

  private String replaceString(String className, String string)
  {
    string = replaceStringInt(className.replace('.', '/'), string);
    string = replaceStringInt(className.replace('.', '$'), string);
    string = replaceStringInt(className.replace('.', '-'), string);

    return string;
  }

  private String replaceStringInt(String className, String string)
  {
    int t = className.lastIndexOf('.');
    if (t > 0)
      className = className.substring(t + 1);

    String baseName = className + _baseSuffix;
    // String extName = className + "__ResinExt";
    String extName = "__ResinExt";
    
    int p;
    if (! baseName.equals(className)) {
      while ((p = string.indexOf(baseName)) >= 0) {
	String prefix = string.substring(0, p);
	String suffix = string.substring(p + baseName.length());

	string = prefix + className + suffix;
      }
    }

    while ((p = string.indexOf(extName)) >= 0) {
      String prefix = string.substring(0, p);
      String suffix = string.substring(p + extName.length());

      // string = prefix + className + suffix;
      string = prefix + suffix;
    }

    return string;
  }

  private static class InitAnalyzer extends Analyzer {
    int _offset = -1;

    /**
     * Returns the analyzed offset.
     */
    public int getOffset()
    {
      return _offset;
    }
    
    /**
     * Analyzes the opcode.
     */
    public void analyze(CodeVisitor visitor)
      throws Exception
    {
      if (_offset >= 0)
	return;

      switch (visitor.getOpcode()) {
      case CodeVisitor.INVOKESPECIAL:
	JavaClass javaClass = visitor.getJavaClass();
	ConstantPool cp = javaClass.getConstantPool();
	MethodRefConstant ref = cp.getMethodRef(visitor.getShortArg());

	// ejb/0l00
	// handler "super()" and "this()"
	if (ref.getName().equals("<init>") &&
	    (ref.getClassName().equals(javaClass.getThisClass()) ||
	     ref.getClassName().equals(javaClass.getSuperClassName()))) {
	  _offset = visitor.getOffset() + 3;
	}
	break;
      }
    }
  }

  private static class ExtInitAnalyzer extends Analyzer {
    int _startOffset;
    boolean _isEnhanced;
    
    ExtInitAnalyzer(int length)
    {
      _startOffset = length;
    }
    
    /**
     * Analyzes the opcode.
     */
    public void analyze(CodeVisitor visitor)
      throws Exception
    {
      if (_isEnhanced)
	return;

      if (visitor.getOffset() < _startOffset)
	return;
      
      switch (visitor.getOpcode()) {
      case CodeVisitor.INVOKESPECIAL:
	int index = visitor.getShortArg();

	ConstantPool cp = visitor.getJavaClass().getConstantPool();
	MethodRefConstant ref;
	ref = cp.getMethodRef(index);

	if (! ref.getName().equals("<init>"))
	  return;
	
	MethodRefConstant newRef;
	newRef = cp.addMethodRef(ref.getClassName(),
				 "__init__super",
				 ref.getType());

	visitor.setShortArg(1, newRef.getIndex());

	_isEnhanced = true;
	break;
      }
    }
  }
}
