Package org.netbeans.modules.scala.debugger.projects

Source Code of org.netbeans.modules.scala.debugger.projects.AST2Bytecode$OperationCreationDelegate

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common
* Development and Distribution License("CDDL") (collectively, the
* "License"). You may not use this file except in compliance with the
* License. You can obtain a copy of the License at
* http://www.netbeans.org/cddl-gplv2.html
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
* specific language governing permissions and limitations under the
* License.  When distributing the software, include this License Header
* Notice in each file and include the License file at
* nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the
* License Header, with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* Contributor(s):
*
* The Original Software is NetBeans. The Initial Developer of the Original
* Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
* Microsystems, Inc. All Rights Reserved.
*
* If you wish your version of this file to be governed by only the CDDL
* or only the GPL Version 2, indicate your decision by adding
* "[Contributor] elects to include this software in this distribution
* under the [CDDL or GPL Version 2] license." If you do not indicate a
* single choice of license, a recipient has the option to distribute
* your version of this file under either the CDDL, the GPL Version 2 or
* to extend the choice of license to its licensees as provided above.
* However, if you add GPL Version 2 code and therefore, elected the GPL
* Version 2 license, then the option applies only if the new code is
* made subject to such option by the copyright holder.
*/

package org.netbeans.modules.scala.debugger.projects;

import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.IdentifierTree;
import com.sun.source.tree.LineMap;
import com.sun.source.tree.MemberSelectTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.NewClassTree;
import com.sun.source.tree.Tree;
import com.sun.source.util.SourcePositions;
import com.sun.source.util.TreePath;
import com.sun.source.util.Trees;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Types;
import org.netbeans.api.java.source.CompilationController;
import org.netbeans.api.java.source.ElementUtilities;

import org.netbeans.spi.debugger.jpda.EditorContext;
import org.openide.ErrorManager;

/**
* This class tries to match the AST expression to bytecode. The result
* of this match is provided as an
* {@link org.netbeans.spi.debugger.jpda.EditorContext.ExpressionTree} object.
*
* @author Martin Entlicher
*/
class AST2Bytecode {
   
    /** Creates a new instance of AST2Bytecode */
    private AST2Bytecode() {
    }
   
    static EditorContext.Operation[] matchSourceTree2Bytecode(
            CompilationUnitTree cu, CompilationController ci,
            List<Tree> treeNodes, ExpressionScanner.ExpressionsInfo info,
            byte[] bytecodes, int[] indexes, byte[] constantPool,
            OperationCreationDelegate opCreationDelegate,
            Map<Tree, EditorContext.Operation> nodeOperations) {
       
        Trees trees = ci.getTrees();
        Types types = ci.getTypes();
        SourcePositions sp = trees.getSourcePositions();
        //List<Tree> treeNodes = linearizeTree(expTrees);
        if (treeNodes == null) return null;
        if (indexes == null) return null;
        int length = treeNodes.size();
        List<EditorContext.Operation> operations = new ArrayList<EditorContext.Operation>(length);
        LineMap lineMap = cu.getLineMap();
        int indexesIndex = 0;
        int from = indexes[indexesIndex];
        int to = indexes[indexesIndex + 1];
        for (int treeIndex = 0; treeIndex < length; treeIndex++) {
            Tree node = treeNodes.get(treeIndex);
            Tree.Kind kind = node.getKind();
            EditorContext.Operation op = null;
            if (kind.equals(Tree.Kind.METHOD_INVOCATION) ||
                kind.equals(Tree.Kind.NEW_CLASS)) {
               
                int opcode;
                do {
                    do {
                        opcode = bytecodes[from] & 0xFF;
                        if (isMethodCall(opcode)) {
                            break;
                        }
                        from += getInstrSize(opcode, bytecodes, from);
                    } while (from < to);
                    if (from < to) {
                        break;
                    }
                    if ((indexesIndex + 2) < indexes.length) {
                        indexesIndex += 2;
                        from = indexes[indexesIndex];
                        to = indexes[indexesIndex + 1];
                    } else {
                        break;
                    }
                } while (true);
                if (from < to) { // We have the method call
                    if (!ci.getTreeUtilities().isSynthetic(ci.getTrees().getPath(cu, node))) {
                        int pos = (int) sp.getStartPosition(cu, node);
                        EditorContext.Position startPosition =
                                opCreationDelegate.createPosition(
                                        pos,
                                        (int) lineMap.getLineNumber(pos),
                                        (int) lineMap.getColumnNumber(pos)
                                );
                        pos = (int) sp.getEndPosition(cu, node);
                        EditorContext.Position endPosition =
                                opCreationDelegate.createPosition(
                                        pos,
                                        (int) lineMap.getLineNumber(pos),
                                        (int) lineMap.getColumnNumber(pos)
                                );
                        Tree identifier;
                        String methodName;
                        String methodClassType;
                        boolean getStartPosFromMethodLength = false;
                        if (kind.equals(Tree.Kind.NEW_CLASS)) {
                            identifier = ((NewClassTree) node).getIdentifier();
                            methodName = "<init>";
                            TreePath iPath = TreePath.getPath(cu, identifier);
                            TypeMirror type = trees.getTypeMirror(iPath);
                            if (type.getKind() == TypeKind.ERROR) {
                                // There are errors, give it up.
                                return null;
                            }
                            assert type.getKind() == TypeKind.DECLARED;
                            TypeElement te = (TypeElement) types.asElement(type);
                            methodClassType = ElementUtilities.getBinaryName(te);
                        } else {
                            //identifier = ((MemberSelectTree) ((MethodInvocationTree) node).getMethodSelect()).getIdentifier();
                            identifier = ((MethodInvocationTree) node).getMethodSelect();
                            if (identifier.getKind() == Tree.Kind.IDENTIFIER) {
                                methodName = ((IdentifierTree) identifier).getName().toString();
                                TreePath iPath = TreePath.getPath(cu, identifier);
                                TypeElement te = trees.getScope(iPath).getEnclosingClass();
                                if (te == null) {
                                    // No enclosing class? Some error, give it up.
                                    return null;
                                }
                                methodClassType = ElementUtilities.getBinaryName(te);
                            } else {
                                methodName = ((MemberSelectTree) identifier).getIdentifier().toString();
                                getStartPosFromMethodLength = true;
                                ExpressionTree exp = ((MemberSelectTree) identifier).getExpression();
                                TreePath expPath = TreePath.getPath(cu, exp);
                                TypeMirror type = trees.getTypeMirror(expPath);
                                if (type.getKind() == TypeKind.ERROR) {
                                    // There are errors, give it up.
                                    return null;
                                }
                                TypeElement te;
                                if (type.getKind() == TypeKind.DECLARED) {
                                    te = (TypeElement) types.asElement(type);
                                } else if (type.getKind() == TypeKind.TYPEVAR) {
                                    TypeParameterElement tpe = (TypeParameterElement) types.asElement(type);
                                    List<? extends TypeMirror> exts = tpe.getBounds();
                                    if (exts.size() == 1) {
                                        type = exts.get(0);
                                        if (type.getKind() == TypeKind.DECLARED) {
                                            te = (TypeElement) types.asElement(type);
                                        } else {
                                            return null; // Unsupported
                                        }
                                    } else {
                                        return null; // Unsupported
                                    }
                                } else {
                                    ErrorManager.getDefault().notify(new IllegalStateException("Unexpected type "+type+" in "+treeNodes));
                                    return null;
                                }
                                methodClassType = ElementUtilities.getBinaryName(te);
                            }
                        }
                        pos = (int) sp.getEndPosition(cu, identifier);
                        EditorContext.Position methodEndPosition =
                                opCreationDelegate.createPosition(
                                        pos,
                                        (int) lineMap.getLineNumber(pos),
                                        (int) lineMap.getColumnNumber(pos)
                                );
                        if (getStartPosFromMethodLength) {
                            pos = pos - methodName.length();
                        } else {
                            pos = (int) sp.getStartPosition(cu, identifier);
                        }
                        EditorContext.Position methodStartPosition =
                                opCreationDelegate.createPosition(
                                        pos,
                                        (int) lineMap.getLineNumber(pos),
                                        (int) lineMap.getColumnNumber(pos)
                                );
                        /*
                        EditorContext.Operation op =
                                opCreationDelegate.createOperation(
                                        startPosition,
                                        endPosition,
                                        from
                                );
                         */
                        op = opCreationDelegate.createMethodOperation(
                                        startPosition,
                                        endPosition,
                                        methodStartPosition,
                                        methodEndPosition,
                                        methodName,
                                        methodClassType,
                                        from
                                );
                        //treeNodes.get(treeIndex).setCodeIndex(from);
                        operations.add(op);
                    }
                    from += getInstrSize(opcode, bytecodes, from);
                } else {
                    return null; // Mismatch
                }
            }
            if (op != null) {
                nodeOperations.put(node, op);
            }
        }
        // Check the rest of the bytecode for method calls:
        do {
            while (from < to) {
                int opcode = bytecodes[(int) from] & 0xFF;
                if (isMethodCall(opcode)) {
                    return null; // Mismatch
                }
                from += getInstrSize(opcode, bytecodes, from);
            }
            if ((indexesIndex + 2) < indexes.length) {
                indexesIndex += 2;
                from = indexes[indexesIndex];
                to = indexes[indexesIndex + 1];
            } else {
                break;
            }
        } while (true);
        /*
        // Assign next operations:
        for (int treeIndex = 0; treeIndex < length; treeIndex++) {
            Tree node = treeNodes.get(treeIndex);
            Set<Tree> nextNodes = info.getNextExpressions(node);
            if (nextNodes != null) {
                EditorContext.Operation op = nodeOperations.get(node);
                if (op == null) {
                    for (int backIndex = treeIndex - 1; backIndex >= 0; backIndex--) {
                        node = treeNodes.get(backIndex);
                        op = nodeOperations.get(node);
                        if (op != null) break;
                    }
                }
                if (op != null) {
                    assignNext(op, opCreationDelegate, info, nodeOperations,
                               nextNodes, treeNodes);
                }
            }
        }
         */
        return operations.toArray(new EditorContext.Operation[] {});
    }
   
    /*private static void assignNext(EditorContext.Operation op,
                                   OperationCreationDelegate opCreationDelegate,
                                   ExpressionScanner.ExpressionsInfo info,
                                   Map<Tree, EditorContext.Operation> nodeOperations,
                                   Set<Tree> nextNodes,
                                   List<Tree> allNodes) {
        for (Tree t : nextNodes) {
            EditorContext.Operation nextOp = nodeOperations.get(t);
            if (nextOp != null) {
                opCreationDelegate.addNextOperationTo(op, nextOp);
            } else {
                Set<Tree> nextNextNodes = info.getNextExpressions(t);
                if (nextNextNodes == null) {
                    boolean check = false;
                    for (int treeIndex = 0; treeIndex < allNodes.size(); treeIndex++) {
                        Tree node = allNodes.get(treeIndex);
                        if (check) {
                            nextNextNodes = info.getNextExpressions(node);
                            if (nextNextNodes != null) break;
                        } else {
                            if (t == node) {
                                check = true;
                            }
                        }
                    }
                } else {
                    assignNext(op, opCreationDelegate, info, nodeOperations, nextNextNodes, allNodes);
                }
            }
        }
    }*/
   
    private static boolean isMethodCall(int opcode) {
        return opcode >= 182 && opcode <= 185;
    }
   
    private static int getInstrSize(int opcode, byte[] bytecodes, long codeIndex) {
        if (opcode <= 15) return 1; // nop - dconst_1
        if (opcode == 16) return 2; // bipush <byte>
        if (opcode == 17) return 3; // sipush <byte1> <byte2>
        if (opcode == 18) return 2; // ldc <index>
        if (opcode <= 20) return 3; // ldc_w <byte1> <byte2>, ldc2_w <byte1> <byte2>
        if (opcode <= 25) return 2; // iload <index>, lload <index>, fload <index>, dload <index>, aload <index>
        if (opcode <= 53) return 1; // <x>load_<n>, <x>aload
        if (opcode <= 58) return 2; // <x>store <index>
        if (opcode <= 86) return 1; // <x>store_<n>, <x>astore
        if (opcode <= 94) return 1; // pop*, dup*
        if (opcode <= 131) return 1; // swap, <x>add, <x>sub, <x>mul, <x>div, <x>rem, <x>neg, *sh*, <x>and, <x>or, <x>xor
        if (opcode <= 132) return 3; // iinc <index> <const>
        if (opcode <= 147) return 1; // <x>2<x>
        if (opcode <= 152) return 1; // <x>cmp<x>
        if (opcode <= 168) return 3; // if<cond> <branchbyte1> <branchbyte2>, goto <branchbyte1> <branchbyte2>, jsr <branchbyte1> <branchbyte2>
        if (opcode <= 169) return 2; // ret <index>
        if (opcode == 170) return tableswitchSize(bytecodes, codeIndex);
        if (opcode == 171) return lookupswitchSize(bytecodes, codeIndex);
        if (opcode <= 177) return 1; // <x>return
        if (opcode <= 184) return 3; // <get/put><static/field> <byte1> <byte2>, invokevirtual, invokespecial, invokestatic
        if (opcode == 185) return 5; // invokeinterface
        // 186 not used
        if (opcode == 187) return 3; // new <byte1> <byte2>
        if (opcode == 188) return 2; // newarray <atype>
        if (opcode == 189) return 3; // anewarray <byte1> <byte2>
        if (opcode <= 191) return 1; // arraylength, athrow
        if (opcode <= 193) return 3; // checkcast <byte1> <byte2>, instanceof <byte1> <byte2>
        if (opcode <= 195) return 1; // monitorenter, monitorexit
        if (opcode == 196) return wideSize(bytecodes, codeIndex);
        if (opcode == 197) return 4; // multianewarray
        if (opcode <= 199) return 3; // ifnull/ifnonnull <byte1> <byte2>
        if (opcode <= 201) return 5; // goto_w/jsr_w 4x<byte>
        return 1; // reserved opcodes
    }
   
    private static int tableswitchSize(byte[] bytecodes, long codeIndex) {
        int padding = 4 - ((int) codeIndex % 4); // Following byte begins at an address that is a multiple of 4
        int pos = (int) codeIndex + padding;
        pos += 4; // default
        int low = readInt(bytecodes, pos);
        pos += 4; // low
        int high = readInt(bytecodes, pos);
        pos += 4; // high
        pos += (high - low + 1) << 2; // high - low + 1 32-bit offsets
        return pos - (int) codeIndex;
    }
   
    private static int lookupswitchSize(byte[] bytecodes, long codeIndex) {
        int padding = 4 - ((int) codeIndex % 4); // Following byte begins at an address that is a multiple of 4
        int pos = (int) codeIndex + padding;
        pos += 4; // default
        int npairs = readInt(bytecodes, pos);
        pos += 4; // npairs
        pos += npairs << 3; // npairs 2x32-bit numbers (pairs)
        return pos - (int) codeIndex;
    }
   
    private static int wideSize(byte[] bytecodes, long codeIndex) {
        int opcode = bytecodes[(int) codeIndex + 1] & 0xFF;
        if (opcode == 132) { // iinc
            return 6;
        } else {
            return 4;
        }
    }
   
    private static int readUnsignedShort(byte[] bytecodes, int pos) {
        return ((bytecodes[pos] & 0xFF) << 8) | (bytecodes[pos + 1] & 0xFF);
    }
   
    private static int readInt(byte[] bytecodes, int pos) {
        return  (bytecodes[pos    ] & 0xFF) << 24 |
                (bytecodes[pos + 1] & 0xFF) << 16 |
                (bytecodes[pos + 2] & 0xFF) << |
                (bytecodes[pos + 3] & 0xFF);
    }

   
    static interface OperationCreationDelegate {
       
        /*
            EditorContext.Operation createOperation(
                    EditorContext.Position startPosition,
                    EditorContext.Position endPosition,
                    int bytecodeIndex);
         */
           
            EditorContext.Operation createMethodOperation(
                    EditorContext.Position startPosition,
                    EditorContext.Position endPosition,
                    EditorContext.Position methodStartPosition,
                    EditorContext.Position methodEndPosition,
                    String methodName, String methodClassType,
                    int bytecodeIndex);
           
            EditorContext.Position createPosition(int offset, int line, int column);
           
            void addNextOperationTo(EditorContext.Operation operation,
                                    EditorContext.Operation next);

    }
}
TOP

Related Classes of org.netbeans.modules.scala.debugger.projects.AST2Bytecode$OperationCreationDelegate

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.