src/hotspot/share/interpreter/bytecodeUtils.hpp
author goetz
Wed, 10 Apr 2019 08:26:23 +0200
branchJEP-8220715-NPE_messages
changeset 57319 aa400d41ebd6
parent 57271 1735d39dbff9
permissions -rw-r--r--
Print methods in Java syntax. Simplify computing the message Summary: Cleanup test: arrange according to messages and topics. Add test cases.

/*
 * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
 * Copyright (c) 2019 SAP SE. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code 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.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 *
 */

#ifndef SHARE_INTERPRETER_BYTECODEUTILS_HPP
#define SHARE_INTERPRETER_BYTECODEUTILS_HPP

#include "memory/allocation.hpp"
#include "oops/method.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/globalDefinitions.hpp"

class TrackingStack;
class TrackingStackCreator;

// The entry of TrackingStack.
class TrackingStackEntry {
 private:

  friend class TrackingStack;
  friend class TrackingStackCreator;

  // The raw entry composed of the type and the bci.
  int _entry;

  enum {
    SCALE = 1024 * 1024
  };

  // Merges this entry with the given one and returns the result. If
  // the bcis of the entry are different, the bci of the result will be
  // undefined. If the types are different, the result type is T_CONFLICT.
  // (an exception is if one type is an array and the other is object, then
  // the result type will be T_OBJECT).
  TrackingStackEntry merge(TrackingStackEntry other);
public:
  // Creates a new entry with an invalid bci and the given type.
  TrackingStackEntry(BasicType type = T_CONFLICT);

  // Creates a new entry with the given bci and type.
  TrackingStackEntry(int bci, BasicType type);

 public:

  enum {
    INVALID = SCALE - 1
  };

  // Returns the bci. If the bci is invalid, INVALID is returned.
  int get_bci();

  // Returns true, if the bci is not invalid.
  bool has_bci() { return get_bci() != INVALID; }

  // Returns the type of the entry.
  BasicType get_type();
};

// A stack consisting of TrackingStackEntries.
class TrackingStack: CHeapObj<mtInternal> {

 private:

  friend class TrackingStackCreator;
  friend class TrackingStackEntry;

  // The stack.
  GrowableArray<TrackingStackEntry> _stack;

  TrackingStack() { };
  TrackingStack(const TrackingStack &copy);

  // Pushes the given entry.
  void push_raw(TrackingStackEntry entry);

  // Like push_raw, but if the entry is long or double, we push two.
  void push(TrackingStackEntry entry);

  // Like push(entry), but using bci/type instead of entry.
  void push(int bci, BasicType type);

  // Pops the given number of entries.
  void pop(int slots);

  // Merges this with the given stack by merging all entries. The
  // size of the stacks must be the same.
  void merge(TrackingStack const& other);

 public:

  // Returns the size of the stack.
  int get_size() const;

  // Returns the entry with the given index. Top of stack is at index 0.
  TrackingStackEntry get_entry(int slot);
};

// Analyses the bytecodes of a method and tries to create a tracking
// stack for each bci. The tracking stack holds the bci and type of
// the object on the stack. The bci (if valid) holds the bci of the
// instruction, which put the entry on the stack.
class TrackingStackCreator {

  // The stacks.
  GrowableArray<TrackingStack*>* _stacks;

  // The method.
  Method* _method;

  // The maximum number of entries we want to use. This is used to
  // limit the amount of memory we waste for insane methods (as they
  // appear in JCK tests).
  int _max_entries;

  // The number of entries used (the sum of all entries of all stacks).
  int _nr_of_entries;

  // If true, we have added at least one new stack.
  bool _added_one;

  // If true, we have processed all bytecodes.
  bool _all_processed;

  static const int _max_cause_detail;

  // Merges the stack the the given bci with the given stack. If there
  // is no stack at the bci, we just put the given stack there. This
  // method doesn't takes ownership of the stack.
  void merge(int bci, TrackingStack* stack);

  // Processes the instruction at the given bci in the method. Returns
  // the size of the instruction.
  int do_instruction(int bci);

  bool print_NPE_cause0(outputStream *os, int bci, int slot, int max_detail, const char *prefix = NULL);

 public:

  // Creates tracking stacks for the given method (the method must be
  // rewritten already). Note that you're not allowed to use this object
  // when crossing a safepoint! If the bci is != -1, we only create the
  // stacks as far as needed to get a stack for the bci.
  TrackingStackCreator(Method* method, int bci = -1);

  // Releases the resources.
  ~TrackingStackCreator();

  // Returns the number of stacks (this is the size of the method).
  int get_size() { return _stacks->length() - 1; }

  // Assuming that a NullPointerException was thrown at the given bci,
  // we return the nr of the slot holding the null reference. If this
  // NPE is created by hand, we return -2 as the slot. If there
  // cannot be a NullPointerException at the bci, -1 is returned.
  int get_NPE_null_slot(int bci);

  // Prints a java-like expression for the bytecode that pushed
  // the value to the given slot being live at the given bci.
  // It constructs the expression recuring backwards over the
  // bytecode.
  // The TOS has the slot number 0, that below 1 and so on.
  void print_NPE_cause(outputStream *os, int bci, int slot);

  // Prints a string describing the failed action.
  void print_NPE_failedAction(outputStream *os, int bci);
};

#endif // SHARE_INTERPRETER_BYTECODEUTILS_HPP