1 /*
   2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package org.graalvm.compiler.salver.dumper;
  24 
  25 import java.io.IOException;
  26 import java.lang.reflect.Modifier;
  27 import java.util.ArrayDeque;
  28 import java.util.Collections;
  29 import java.util.Deque;
  30 import java.util.Iterator;
  31 
  32 import org.graalvm.compiler.bytecode.BytecodeDisassembler;
  33 import org.graalvm.compiler.salver.data.DataDict;
  34 import org.graalvm.compiler.salver.data.DataList;
  35 import org.graalvm.compiler.salver.util.MethodContext;
  36 
  37 import jdk.vm.ci.meta.JavaMethod;
  38 import jdk.vm.ci.meta.ResolvedJavaMethod;
  39 
  40 public abstract class AbstractMethodScopeDumper extends AbstractGraalDumper {
  41 
  42     protected MethodContext previousMethodContext;
  43 
  44     protected final Deque<Integer> pathStack = new ArrayDeque<>();
  45     protected int pathCounter;
  46     protected final Deque<Integer> itemIdStack = new ArrayDeque<>();
  47     protected int itemIdCounter;
  48 
  49     protected void resolveMethodContext() throws IOException {
  50         // Get all current JavaMethod instances in the context.
  51         MethodContext methodContext = new MethodContext();
  52         // Reverse list such that inner method comes after outer method.
  53         Collections.reverse(methodContext);
  54 
  55         int size = methodContext.size();
  56         int previousSize = previousMethodContext != null ? previousMethodContext.size() : 0;
  57         // Check for method scopes that must be closed since the previous dump.
  58         for (int i = 0; i < previousSize; ++i) {
  59             if (i >= size || !methodContext.itemEquals(i, previousMethodContext)) {
  60                 for (int inlineDepth = previousSize - 1; inlineDepth >= i; --inlineDepth) {
  61                     closeScope();
  62                 }
  63                 break;
  64             }
  65         }
  66         // Check for method scopes that must be opened since the previous dump.
  67         for (int i = 0; i < size; ++i) {
  68             if (i >= previousSize || !methodContext.itemEquals(i, previousMethodContext)) {
  69                 for (int inlineDepth = i; inlineDepth < size; ++inlineDepth) {
  70                     openScope(methodContext.get(inlineDepth));
  71                 }
  72                 break;
  73             }
  74         }
  75         // Save inline context for next dump.
  76         previousMethodContext = methodContext;
  77     }
  78 
  79     protected void openScope(MethodContext.Item item) throws IOException {
  80         int debugId = item.getDebugId();
  81         int id = debugId != -1 ? debugId : pathCounter;
  82 
  83         pathStack.push(id);
  84         itemIdStack.push(itemIdCounter);
  85         pathCounter = 0;
  86         itemIdCounter = 0;
  87 
  88         processMethod(item.getMethod(), id, item.getName());
  89     }
  90 
  91     @SuppressWarnings("unused")
  92     protected void closeScope() throws IOException {
  93         if (!pathStack.isEmpty()) {
  94             pathCounter = pathStack.pop();
  95             pathCounter++;
  96         }
  97         if (!itemIdStack.isEmpty()) {
  98             itemIdCounter = itemIdStack.pop();
  99         }
 100     }
 101 
 102     protected void processMethod(JavaMethod method, int id, String name) throws IOException {
 103         DataDict dataDict = new DataDict();
 104         dataDict.put("id", id);
 105         dataDict.put("name", name);
 106 
 107         if (method instanceof ResolvedJavaMethod) {
 108             DataDict methodDict = new DataDict();
 109             dataDict.put("method", methodDict);
 110 
 111             ResolvedJavaMethod resolvedMethod = (ResolvedJavaMethod) method;
 112 
 113             methodDict.put("modifiers", Modifier.toString(resolvedMethod.getModifiers()));
 114             methodDict.put("code", new BytecodeDisassembler(false).disassemble(resolvedMethod));
 115         }
 116         serializeAndFlush(createEventDictWithId("method", dataDict, false));
 117     }
 118 
 119     protected int nextItemId() {
 120         return itemIdCounter++;
 121     }
 122 
 123     protected DataDict createEventDictWithId(String name, boolean isItem) {
 124         DataDict eventDict = createEventDict(name);
 125 
 126         DataDict idDict = new DataDict();
 127         eventDict.put("@id", idDict);
 128 
 129         DataList pathList = new DataList();
 130         idDict.put("path", pathList);
 131 
 132         Iterator<Integer> i = pathStack.descendingIterator();
 133         while (i.hasNext()) {
 134             pathList.add(i.next());
 135         }
 136         if (isItem) {
 137             pathList.add(pathCounter++);
 138         }
 139         return eventDict;
 140     }
 141 
 142     protected DataDict createEventDictWithId(String name, DataDict dataDict, boolean isItem) {
 143         DataDict eventDict = createEventDictWithId(name, isItem);
 144         eventDict.put("@data", dataDict);
 145         return eventDict;
 146     }
 147 
 148     protected DataDict createEventDictWithId(String name) {
 149         return createEventDictWithId(name, true);
 150     }
 151 
 152     protected DataDict createEventDictWithId(String name, DataDict dataDict) {
 153         return createEventDictWithId(name, dataDict, true);
 154     }
 155 }