Search in sources :

Example 1 with CodeConverter

use of javassist.CodeConverter in project compss by bsc-wdc.

the class ITAppModifier method modify.

/**
 * Modify method
 *
 * @param appName
 * @return
 * @throws NotFoundException
 * @throws CannotCompileException
 * @throws ClassNotFoundException
 */
public Class<?> modify(String appName) throws NotFoundException, CannotCompileException, ClassNotFoundException {
    Class<?> annotItf = Class.forName(appName + LoaderConstants.ITF_SUFFIX);
    // Methods declared in the annotated interface
    Method[] remoteMethods = annotItf.getMethods();
    /*
         * Use the application editor to include the COMPSs API calls on the application code
         */
    CLASS_POOL.importPackage(LoaderConstants.PACKAGE_COMPSS_ROOT);
    CLASS_POOL.importPackage(LoaderConstants.PACKAGE_COMPSS_API);
    CLASS_POOL.importPackage(LoaderConstants.PACKAGE_COMPSS_API_IMPL);
    CLASS_POOL.importPackage(LoaderConstants.PACKAGE_COMPSS_LOADER);
    CLASS_POOL.importPackage(LoaderConstants.PACKAGE_COMPSS_LOADER_TOTAL);
    CtClass appClass = CLASS_POOL.get(appName);
    CtClass itApiClass = CLASS_POOL.get(LoaderConstants.CLASS_COMPSSRUNTIME_API);
    CtClass itSRClass = CLASS_POOL.get(LoaderConstants.CLASS_STREAM_REGISTRY);
    CtClass itORClass = CLASS_POOL.get(LoaderConstants.CLASS_OBJECT_REGISTRY);
    CtClass appIdClass = CLASS_POOL.get(LoaderConstants.CLASS_APP_ID);
    String varName = LoaderUtils.randomName(5, LoaderConstants.STR_COMPSS_PREFIX);
    String itApiVar = varName + LoaderConstants.STR_COMPSS_API;
    String itSRVar = varName + LoaderConstants.STR_COMPSS_STREAM_REGISTRY;
    String itORVar = varName + LoaderConstants.STR_COMPSS_OBJECT_REGISTRY;
    String itAppIdVar = varName + LoaderConstants.STR_COMPSS_APP_ID;
    CtField itApiField = new CtField(itApiClass, itApiVar, appClass);
    CtField itSRField = new CtField(itSRClass, itSRVar, appClass);
    CtField itORField = new CtField(itORClass, itORVar, appClass);
    CtField appIdField = new CtField(appIdClass, itAppIdVar, appClass);
    itApiField.setModifiers(Modifier.PRIVATE | Modifier.STATIC);
    itSRField.setModifiers(Modifier.PRIVATE | Modifier.STATIC);
    itORField.setModifiers(Modifier.PRIVATE | Modifier.STATIC);
    appIdField.setModifiers(Modifier.PRIVATE | Modifier.STATIC);
    appClass.addField(itApiField);
    appClass.addField(itSRField);
    appClass.addField(itORField);
    appClass.addField(appIdField);
    /*
         * Create a static constructor to initialize the runtime Create a shutdown hook to stop the runtime before the
         * JVM ends
         */
    manageStartAndStop(appClass, itApiVar, itSRVar, itORVar);
    /*
         * Create IT App Editor
         */
    // Candidates to be instrumented if they are not
    CtMethod[] instrCandidates = appClass.getDeclaredMethods();
    // remote
    ITAppEditor itAppEditor = new ITAppEditor(remoteMethods, instrCandidates, itApiVar, itSRVar, itORVar, itAppIdVar, appClass);
    // itAppEditor.setAppId(itAppIdVar);
    // itAppEditor.setAppClass(appClass);
    /*
         * Create Code Converter
         */
    CodeConverter converter = new CodeConverter();
    CtClass arrayWatcher = CLASS_POOL.get(LoaderConstants.CLASS_ARRAY_ACCESS_WATCHER);
    CodeConverter.DefaultArrayAccessReplacementMethodNames names = new CodeConverter.DefaultArrayAccessReplacementMethodNames();
    converter.replaceArrayAccess(arrayWatcher, (CodeConverter.ArrayAccessReplacementMethodNames) names);
    /*
         * Find the methods declared in the application class that will be instrumented - Main - Constructors - Methods
         * that are not in the remote list
         */
    if (DEBUG) {
        LOGGER.debug("Flags: ToFile: " + WRITE_TO_FILE + " isWS: " + IS_WS_CLASS + " isMainClass: " + IS_MAIN_CLASS);
    }
    for (CtMethod m : instrCandidates) {
        if (LoaderUtils.checkRemote(m, remoteMethods) == null) {
            // Not a remote method, we must instrument it
            if (DEBUG) {
                LOGGER.debug("Instrumenting method " + m.getName());
            }
            StringBuilder toInsertBefore = new StringBuilder();
            StringBuilder toInsertAfter = new StringBuilder();
            /*
                 * Add local variable to method representing the execution id, which will be the current thread id. Used
                 * for Services, to handle multiple service executions simultaneously with a single runtime For normal
                 * applications, there will be only one execution id.
                 */
            m.addLocalVariable(itAppIdVar, appIdClass);
            toInsertBefore.append(itAppIdVar).append(" = new Long(Thread.currentThread().getId());");
            // TODO remove old code:
            // boolean isMainProgram = writeToFile ? LoaderUtils.isOrchestration(m) : LoaderUtils.isMainMethod(m);
            boolean isMainProgram = LoaderUtils.isMainMethod(m);
            boolean isOrchestration = LoaderUtils.isOrchestration(m);
            if (isMainProgram && IS_MAIN_CLASS) {
                LOGGER.debug("Inserting calls at the beginning and at the end of main");
                if (IS_WS_CLASS) {
                    // 
                    LOGGER.debug("Inserting calls noMoreTasks at the end of main");
                    toInsertAfter.insert(0, itApiVar + ".noMoreTasks(" + itAppIdVar + ", true);");
                    m.insertBefore(toInsertBefore.toString());
                    // executed only if Orchestration finishes properly
                    m.insertAfter(toInsertAfter.toString());
                } else {
                    // Main program
                    LOGGER.debug("Inserting calls noMoreTasks and stopIT at the end of main");
                    // Set global variable for main as well, will be used in code inserted after to be run no matter
                    // what
                    toInsertBefore.append(appName).append('.').append(itAppIdVar).append(" = new Long(Thread.currentThread().getId());");
                    // toInsertAfter.append("System.exit(0);");
                    toInsertAfter.insert(0, itApiVar + ".stopIT(true);");
                    toInsertAfter.insert(0, itApiVar + ".noMoreTasks(" + appName + '.' + itAppIdVar + ", true);");
                    m.insertBefore(toInsertBefore.toString());
                    // executed no matter what
                    m.insertAfter(toInsertAfter.toString(), true);
                }
                /*
                     * Instrumenting first the array accesses makes each array access become a call to a black box
                     * method of class ArrayAccessWatcher, whose parameters include the array. For the second round of
                     * instrumentation, the synchronization by transition to black box automatically synchronizes the
                     * arrays accessed. TODO: Change the order of instrumentation, so that we have more control about
                     * the synchronization, and we can distinguish between a write access and a read access (now it's
                     * read/write access by default, because it goes into the black box).
                     */
                m.instrument(converter);
                m.instrument(itAppEditor);
            } else if (isOrchestration) {
                if (IS_WS_CLASS) {
                    // 
                    LOGGER.debug("Inserting calls noMoreTasks and stopIT at the end of orchestration");
                    toInsertAfter.insert(0, itApiVar + ".noMoreTasks(" + itAppIdVar + ", true);");
                    m.insertBefore(toInsertBefore.toString());
                    // executed only if Orchestration finishes properly
                    m.insertAfter(toInsertAfter.toString());
                } else {
                    LOGGER.debug("Inserting only before at the beginning of an orchestration");
                    m.insertBefore(toInsertBefore.toString());
                // TODO remove old code m.insertAfter(toInsertAfter.toString());
                // executed only if Orchestration finishes properly
                }
                m.instrument(converter);
                m.instrument(itAppEditor);
            } else {
                LOGGER.debug("Inserting only before");
                m.insertBefore(toInsertBefore.toString());
                if (IS_WS_CLASS) {
                    // non-OE operations
                    if (Modifier.isPrivate(m.getModifiers())) {
                        m.instrument(converter);
                        m.instrument(itAppEditor);
                    }
                } else {
                    // For an application class, instrument all non-remote methods
                    m.instrument(converter);
                    m.instrument(itAppEditor);
                }
            }
        }
    }
    // Instrument constructors
    for (CtConstructor c : appClass.getDeclaredConstructors()) {
        if (DEBUG) {
            LOGGER.debug("Instrumenting constructor " + c.getLongName());
        }
        c.instrument(converter);
        c.instrument(itAppEditor);
    }
    if (WRITE_TO_FILE) {
        // Write the modified class to disk
        try {
            appClass.writeFile();
        } catch (Exception e) {
            ErrorManager.fatal("Error writing the instrumented class file");
        }
        return null;
    } else {
        /*
             * Load the modified class into memory and return it. Generally, once a class is loaded into memory no
             * further modifications can be performed on it.
             */
        return appClass.toClass();
    }
}
Also used : CodeConverter(javassist.CodeConverter) CtMethod(javassist.CtMethod) Method(java.lang.reflect.Method) CannotCompileException(javassist.CannotCompileException) NotFoundException(javassist.NotFoundException) CtConstructor(javassist.CtConstructor) CtClass(javassist.CtClass) CtField(javassist.CtField) CtMethod(javassist.CtMethod)

Aggregations

Method (java.lang.reflect.Method)1 CannotCompileException (javassist.CannotCompileException)1 CodeConverter (javassist.CodeConverter)1 CtClass (javassist.CtClass)1 CtConstructor (javassist.CtConstructor)1 CtField (javassist.CtField)1 CtMethod (javassist.CtMethod)1 NotFoundException (javassist.NotFoundException)1