rewriter.hpp revision 3602:da91efe96a93
1121572Sume/*
262583Sitojun * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
355505Sshin * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
455505Sshin *
555505Sshin * This code is free software; you can redistribute it and/or modify it
655505Sshin * under the terms of the GNU General Public License version 2 only, as
755505Sshin * published by the Free Software Foundation.
855505Sshin *
955505Sshin * This code is distributed in the hope that it will be useful, but WITHOUT
1055505Sshin * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1155505Sshin * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1255505Sshin * version 2 for more details (a copy is included in the LICENSE file that
1355505Sshin * accompanied this code).
1455505Sshin *
1555505Sshin * You should have received a copy of the GNU General Public License version
1655505Sshin * 2 along with this work; if not, write to the Free Software Foundation,
1755505Sshin * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1855505Sshin *
1955505Sshin * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2055505Sshin * or visit www.oracle.com if you need additional information or have any
2155505Sshin * questions.
2255505Sshin *
2355505Sshin */
2455505Sshin
2555505Sshin#ifndef SHARE_VM_INTERPRETER_REWRITER_HPP
2655505Sshin#define SHARE_VM_INTERPRETER_REWRITER_HPP
2755505Sshin
2855505Sshin#include "memory/allocation.hpp"
2955505Sshin#include "runtime/handles.inline.hpp"
3055505Sshin#include "utilities/growableArray.hpp"
3155505Sshin
3284208Sdillon// The Rewriter adds caches to the constant pool and rewrites bytecode indices
3384208Sdillon// pointing into the constant pool for better interpreter performance.
3484208Sdillon
3555505Sshinclass Rewriter: public StackObj {
3655505Sshin private:
3755505Sshin  instanceKlassHandle _klass;
3855505Sshin  constantPoolHandle  _pool;
3955505Sshin  Array<Method*>*     _methods;
4057855Sshin  intArray            _cp_map;
41171135Sgnn  intStack            _cp_cache_map;        // for Methodref, Fieldref,
42171135Sgnn                                            // InterfaceMethodref and InvokeDynamic
4355505Sshin  intArray            _reference_map;       // maps from cp index to resolved_refs index (or -1)
4455505Sshin  intStack            _resolved_references_map;    // for strings, methodHandle, methodType
4555505Sshin  intStack            _invokedynamic_references_map; // for invokedynamic resolved refs
4655505Sshin  intArray            _method_handle_invokers;
4755505Sshin  int                 _resolved_reference_limit;
4862583Sitojun
4955505Sshin  void init_maps(int length) {
5055505Sshin    _cp_map.initialize(length, -1);
5178064Sume    // Choose an initial value large enough that we don't get frequent
5278064Sume    // calls to grow().
5362583Sitojun    _cp_cache_map.initialize(length / 2);
5462583Sitojun    // Also cache resolved objects, in another different cache.
5562583Sitojun    _reference_map.initialize(length, -1);
5662583Sitojun    _resolved_references_map.initialize(length / 2);
5762583Sitojun    _invokedynamic_references_map.initialize(length / 2);
5862583Sitojun    _resolved_reference_limit = -1;
5962583Sitojun    DEBUG_ONLY(_cp_cache_index_limit = -1);
6062583Sitojun  }
6162583Sitojun
6262583Sitojun  int _cp_cache_index_limit;
6362583Sitojun  void record_map_limits() {
6462583Sitojun#ifdef ASSERT
6562583Sitojun    // Record initial size of the two arrays generated for the CP cache:
6662583Sitojun    _cp_cache_index_limit = _cp_cache_map.length();
6762583Sitojun#endif //ASSERT
6862583Sitojun    _resolved_reference_limit = _resolved_references_map.length();
6962583Sitojun  }
7062583Sitojun
7162583Sitojun  int  cp_entry_to_cp_cache(int i) { assert(has_cp_cache(i), "oob"); return _cp_map[i]; }
7262583Sitojun  bool has_cp_cache(int i) { return (uint)i < (uint)_cp_map.length() && _cp_map[i] >= 0; }
7362583Sitojun
7462583Sitojun  int add_cp_cache_entry(int cp_index) {
7562583Sitojun    assert(_pool->tag_at(cp_index).value() != JVM_CONSTANT_InvokeDynamic, "use indy version");
7662583Sitojun    assert(_cp_map[cp_index] == -1, "not twice on same cp_index");
7762583Sitojun    assert(_cp_cache_index_limit == -1, "do not add cache entries after first iteration");
78248314Sglebius    int cache_index = _cp_cache_map.append(cp_index);
79248314Sglebius    _cp_map.at_put(cp_index, cache_index);
80248314Sglebius    assert(cp_entry_to_cp_cache(cp_index) == cache_index, "");
81248314Sglebius    assert(cp_cache_entry_pool_index(cache_index) == cp_index, "");
82248314Sglebius    return cache_index;
83248314Sglebius  }
84248314Sglebius
8562583Sitojun  // add a new CP cache entry beyond the normal cache (for invokedynamic only)
8655505Sshin  int add_invokedynamic_cp_cache_entry(int cp_index) {
8755505Sshin    assert(_pool->tag_at(cp_index).value() == JVM_CONSTANT_InvokeDynamic, "use non-indy version");
8892917Sobrien    assert(_cp_map[cp_index] == -1, "do not map from cp_index");
8992917Sobrien    assert(_cp_cache_index_limit >= 0, "add indy cache entries after first iteration");
9092917Sobrien    int cache_index = _cp_cache_map.append(cp_index);
9192917Sobrien    assert(cache_index >= _cp_cache_index_limit, "");
9292917Sobrien    // do not update _cp_map, since the mapping is one-to-many
9355505Sshin    assert(cp_cache_entry_pool_index(cache_index) == cp_index, "");
9455505Sshin    return cache_index;
9555505Sshin  }
9655505Sshin
9755505Sshin  // fix duplicated code later
9855505Sshin  int  cp_entry_to_resolved_references(int cp_index) const {
9962583Sitojun    assert(has_entry_in_resolved_references(cp_index), "oob");
10062583Sitojun    return _reference_map[cp_index];
10162583Sitojun  }
10262583Sitojun  bool has_entry_in_resolved_references(int cp_index) const {
10362583Sitojun    return (uint)cp_index < (uint)_reference_map.length() && _reference_map[cp_index] >= 0;
10462583Sitojun  }
10562583Sitojun
10662583Sitojun  // add a new entry to the resolved_references map
10762583Sitojun  int add_resolved_references_entry(int cp_index) {
10855505Sshin    assert(_reference_map[cp_index] == -1, "not twice on same cp_index");
10962583Sitojun    assert(_resolved_reference_limit == -1, "do not add CP refs after first iteration");
11055505Sshin    int ref_index = _resolved_references_map.append(cp_index);
11162583Sitojun    _reference_map.at_put(cp_index, ref_index);
11262583Sitojun    assert(cp_entry_to_resolved_references(cp_index) == ref_index, "");
11362583Sitojun    return ref_index;
11455505Sshin  }
11562583Sitojun
11662583Sitojun  // add a new entry to the resolved_references map (for invokedynamic only)
117121572Sume  int add_invokedynamic_resolved_references_entry(int cp_index, int cache_index) {
11862583Sitojun    assert(_resolved_reference_limit >= 0, "must add indy refs after first iteration");
119121572Sume    int ref_index = _resolved_references_map.append(cp_index);  // many-to-one
12055505Sshin    assert(ref_index >= _resolved_reference_limit, "");
12162583Sitojun    _invokedynamic_references_map.at_put_grow(ref_index, cache_index, -1);
12255505Sshin    return ref_index;
12362583Sitojun  }
12462583Sitojun
12555505Sshin  int resolved_references_entry_to_pool_index(int ref_index) {
12662583Sitojun    int cp_index = _resolved_references_map[ref_index];
12762583Sitojun    return cp_index;
12862583Sitojun  }
12962583Sitojun
13062583Sitojun  // invokedynamic support - append the cpCache entry (encoded) in object map.
13155505Sshin  // The resolved_references_map should still be in ascending order
13262583Sitojun  // The resolved_references has the invokedynamic call site objects appended after
13362583Sitojun  // the objects that are resolved in the constant pool.
13462583Sitojun  int add_callsite_entry(int main_cpc_entry) {
13562583Sitojun    int ref_index = _resolved_references_map.append(main_cpc_entry);
13662583Sitojun    return ref_index;
13762583Sitojun  }
13862583Sitojun
13962583Sitojun  // Access the contents of _cp_cache_map to determine CP cache layout.
14055505Sshin  int cp_cache_entry_pool_index(int cache_index) {
14162583Sitojun    int cp_index = _cp_cache_map[cache_index];
14255505Sshin      return cp_index;
14362583Sitojun  }
14462583Sitojun
14562583Sitojun  // All the work goes in here:
14655505Sshin  Rewriter(instanceKlassHandle klass, constantPoolHandle cpool, Array<Method*>* methods, TRAPS);
14762583Sitojun
14855505Sshin  void compute_index_maps();
14955505Sshin  void make_constant_pool_cache(TRAPS);
15055505Sshin  void scan_method(Method* m, bool reverse = false);
15155505Sshin  void rewrite_Object_init(methodHandle m, TRAPS);
15262583Sitojun  void rewrite_member_reference(address bcp, int offset, bool reverse = false);
15355505Sshin  void maybe_rewrite_invokehandle(address opc, int cp_index, int cache_index, bool reverse = false);
15455505Sshin  void rewrite_invokedynamic(address bcp, int offset, bool reverse = false);
15555505Sshin  void maybe_rewrite_ldc(address bcp, int offset, bool is_wide, bool reverse = false);
15662583Sitojun  // Revert bytecodes in case of an exception.
15762583Sitojun  void restore_bytecodes();
15855505Sshin
15955505Sshin  static methodHandle rewrite_jsrs(methodHandle m, TRAPS);
16055505Sshin public:
16155505Sshin  // Driver routine:
16255505Sshin  static void rewrite(instanceKlassHandle klass, TRAPS);
16355505Sshin  static void rewrite(instanceKlassHandle klass, constantPoolHandle cpool, Array<Method*>* methods, TRAPS);
16455505Sshin
16555505Sshin  // Second pass, not gated by is_rewritten flag
16655505Sshin  static void relocate_and_link(instanceKlassHandle klass, TRAPS);
16755505Sshin  // JSR292 version to call with it's own methods.
16855505Sshin  static void relocate_and_link(instanceKlassHandle klass,
16955505Sshin                                Array<Method*>* methods, TRAPS);
17055505Sshin
17155505Sshin};
17255505Sshin
17355505Sshin#endif // SHARE_VM_INTERPRETER_REWRITER_HPP
17455505Sshin