Path: blob/master/src/hotspot/share/ci/bcEscapeAnalyzer.cpp
40930 views
/*1* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include "precompiled.hpp"25#include "classfile/vmIntrinsics.hpp"26#include "ci/bcEscapeAnalyzer.hpp"27#include "ci/ciConstant.hpp"28#include "ci/ciField.hpp"29#include "ci/ciMethodBlocks.hpp"30#include "ci/ciStreams.hpp"31#include "compiler/compiler_globals.hpp"32#include "interpreter/bytecode.hpp"33#include "oops/oop.inline.hpp"34#include "utilities/align.hpp"35#include "utilities/bitMap.inline.hpp"36#include "utilities/copy.hpp"3738#ifndef PRODUCT39#define TRACE_BCEA(level, code) \40if (EstimateArgEscape && BCEATraceLevel >= level) { \41code; \42}43#else44#define TRACE_BCEA(level, code)45#endif4647// Maintain a map of which arguments a local variable or48// stack slot may contain. In addition to tracking49// arguments, it tracks two special values, "allocated"50// which represents any object allocated in the current51// method, and "unknown" which is any other object.52// Up to 30 arguments are handled, with the last one53// representing summary information for any extra arguments54class BCEscapeAnalyzer::ArgumentMap {55uint _bits;56enum {MAXBIT = 29,57ALLOCATED = 1,58UNKNOWN = 2};5960uint int_to_bit(uint e) const {61if (e > MAXBIT)62e = MAXBIT;63return (1 << (e + 2));64}6566public:67ArgumentMap() { _bits = 0;}68void set_bits(uint bits) { _bits = bits;}69uint get_bits() const { return _bits;}70void clear() { _bits = 0;}71void set_all() { _bits = ~0u; }72bool is_empty() const { return _bits == 0; }73bool contains(uint var) const { return (_bits & int_to_bit(var)) != 0; }74bool is_singleton(uint var) const { return (_bits == int_to_bit(var)); }75bool contains_unknown() const { return (_bits & UNKNOWN) != 0; }76bool contains_allocated() const { return (_bits & ALLOCATED) != 0; }77bool contains_vars() const { return (_bits & (((1 << MAXBIT) -1) << 2)) != 0; }78void set(uint var) { _bits = int_to_bit(var); }79void add(uint var) { _bits |= int_to_bit(var); }80void add_unknown() { _bits = UNKNOWN; }81void add_allocated() { _bits = ALLOCATED; }82void set_union(const ArgumentMap &am) { _bits |= am._bits; }83void set_difference(const ArgumentMap &am) { _bits &= ~am._bits; }84bool operator==(const ArgumentMap &am) { return _bits == am._bits; }85bool operator!=(const ArgumentMap &am) { return _bits != am._bits; }86};8788class BCEscapeAnalyzer::StateInfo {89public:90ArgumentMap *_vars;91ArgumentMap *_stack;92int _stack_height;93int _max_stack;94bool _initialized;95ArgumentMap empty_map;9697StateInfo() {98empty_map.clear();99}100101ArgumentMap raw_pop() { guarantee(_stack_height > 0, "stack underflow"); return _stack[--_stack_height]; }102ArgumentMap apop() { return raw_pop(); }103void spop() { raw_pop(); }104void lpop() { spop(); spop(); }105void raw_push(ArgumentMap i) { guarantee(_stack_height < _max_stack, "stack overflow"); _stack[_stack_height++] = i; }106void apush(ArgumentMap i) { raw_push(i); }107void spush() { raw_push(empty_map); }108void lpush() { spush(); spush(); }109110};111112void BCEscapeAnalyzer::set_returned(ArgumentMap vars) {113for (int i = 0; i < _arg_size; i++) {114if (vars.contains(i))115_arg_returned.set(i);116}117_return_local = _return_local && !(vars.contains_unknown() || vars.contains_allocated());118_return_allocated = _return_allocated && vars.contains_allocated() && !(vars.contains_unknown() || vars.contains_vars());119}120121// return true if any element of vars is an argument122bool BCEscapeAnalyzer::is_argument(ArgumentMap vars) {123for (int i = 0; i < _arg_size; i++) {124if (vars.contains(i))125return true;126}127return false;128}129130// return true if any element of vars is an arg_stack argument131bool BCEscapeAnalyzer::is_arg_stack(ArgumentMap vars){132if (_conservative)133return true;134for (int i = 0; i < _arg_size; i++) {135if (vars.contains(i) && _arg_stack.test(i))136return true;137}138return false;139}140141// return true if all argument elements of vars are returned142bool BCEscapeAnalyzer::returns_all(ArgumentMap vars) {143for (int i = 0; i < _arg_size; i++) {144if (vars.contains(i) && !_arg_returned.test(i)) {145return false;146}147}148return true;149}150151void BCEscapeAnalyzer::clear_bits(ArgumentMap vars, VectorSet &bm) {152for (int i = 0; i < _arg_size; i++) {153if (vars.contains(i)) {154bm.remove(i);155}156}157}158159void BCEscapeAnalyzer::set_method_escape(ArgumentMap vars) {160clear_bits(vars, _arg_local);161if (vars.contains_allocated()) {162_allocated_escapes = true;163}164}165166void BCEscapeAnalyzer::set_global_escape(ArgumentMap vars, bool merge) {167clear_bits(vars, _arg_local);168clear_bits(vars, _arg_stack);169if (vars.contains_allocated())170_allocated_escapes = true;171172if (merge && !vars.is_empty()) {173// Merge new state into already processed block.174// New state is not taken into account and175// it may invalidate set_returned() result.176if (vars.contains_unknown() || vars.contains_allocated()) {177_return_local = false;178}179if (vars.contains_unknown() || vars.contains_vars()) {180_return_allocated = false;181}182if (_return_local && vars.contains_vars() && !returns_all(vars)) {183// Return result should be invalidated if args in new184// state are not recorded in return state.185_return_local = false;186}187}188}189190void BCEscapeAnalyzer::set_modified(ArgumentMap vars, int offs, int size) {191192for (int i = 0; i < _arg_size; i++) {193if (vars.contains(i)) {194set_arg_modified(i, offs, size);195}196}197if (vars.contains_unknown())198_unknown_modified = true;199}200201bool BCEscapeAnalyzer::is_recursive_call(ciMethod* callee) {202for (BCEscapeAnalyzer* scope = this; scope != NULL; scope = scope->_parent) {203if (scope->method() == callee) {204return true;205}206}207return false;208}209210bool BCEscapeAnalyzer::is_arg_modified(int arg, int offset, int size_in_bytes) {211if (offset == OFFSET_ANY)212return _arg_modified[arg] != 0;213assert(arg >= 0 && arg < _arg_size, "must be an argument.");214bool modified = false;215int l = offset / HeapWordSize;216int h = align_up(offset + size_in_bytes, HeapWordSize) / HeapWordSize;217if (l > ARG_OFFSET_MAX)218l = ARG_OFFSET_MAX;219if (h > ARG_OFFSET_MAX+1)220h = ARG_OFFSET_MAX + 1;221for (int i = l; i < h; i++) {222modified = modified || (_arg_modified[arg] & (1 << i)) != 0;223}224return modified;225}226227void BCEscapeAnalyzer::set_arg_modified(int arg, int offset, int size_in_bytes) {228if (offset == OFFSET_ANY) {229_arg_modified[arg] = (uint) -1;230return;231}232assert(arg >= 0 && arg < _arg_size, "must be an argument.");233int l = offset / HeapWordSize;234int h = align_up(offset + size_in_bytes, HeapWordSize) / HeapWordSize;235if (l > ARG_OFFSET_MAX)236l = ARG_OFFSET_MAX;237if (h > ARG_OFFSET_MAX+1)238h = ARG_OFFSET_MAX + 1;239for (int i = l; i < h; i++) {240_arg_modified[arg] |= (1 << i);241}242}243244void BCEscapeAnalyzer::invoke(StateInfo &state, Bytecodes::Code code, ciMethod* target, ciKlass* holder) {245int i;246247// retrieve information about the callee248ciInstanceKlass* klass = target->holder();249ciInstanceKlass* calling_klass = method()->holder();250ciInstanceKlass* callee_holder = ciEnv::get_instance_klass_for_declared_method_holder(holder);251ciInstanceKlass* actual_recv = callee_holder;252253// Some methods are obviously bindable without any type checks so254// convert them directly to an invokespecial or invokestatic.255if (target->is_loaded() && !target->is_abstract() && target->can_be_statically_bound()) {256switch (code) {257case Bytecodes::_invokevirtual:258code = Bytecodes::_invokespecial;259break;260case Bytecodes::_invokehandle:261code = target->is_static() ? Bytecodes::_invokestatic : Bytecodes::_invokespecial;262break;263default:264break;265}266}267268// compute size of arguments269int arg_size = target->invoke_arg_size(code);270int arg_base = MAX2(state._stack_height - arg_size, 0);271272// direct recursive calls are skipped if they can be bound statically without introducing273// dependencies and if parameters are passed at the same position as in the current method274// other calls are skipped if there are no non-escaped arguments passed to them275bool directly_recursive = (method() == target) &&276(code != Bytecodes::_invokevirtual || target->is_final_method() || state._stack[arg_base] .is_empty());277278// check if analysis of callee can safely be skipped279bool skip_callee = true;280for (i = state._stack_height - 1; i >= arg_base && skip_callee; i--) {281ArgumentMap arg = state._stack[i];282skip_callee = !is_argument(arg) || !is_arg_stack(arg) || (directly_recursive && arg.is_singleton(i - arg_base));283}284// For now we conservatively skip invokedynamic.285if (code == Bytecodes::_invokedynamic) {286skip_callee = true;287}288if (skip_callee) {289TRACE_BCEA(3, tty->print_cr("[EA] skipping method %s::%s", holder->name()->as_utf8(), target->name()->as_utf8()));290for (i = 0; i < arg_size; i++) {291set_method_escape(state.raw_pop());292}293_unknown_modified = true; // assume the worst since we don't analyze the called method294return;295}296297// determine actual method (use CHA if necessary)298ciMethod* inline_target = NULL;299if (target->is_loaded() && klass->is_loaded()300&& (klass->is_initialized() || (klass->is_interface() && target->holder()->is_initialized()))) {301if (code == Bytecodes::_invokestatic302|| code == Bytecodes::_invokespecial303|| (code == Bytecodes::_invokevirtual && target->is_final_method())) {304inline_target = target;305} else {306inline_target = target->find_monomorphic_target(calling_klass, callee_holder, actual_recv);307}308}309310if (inline_target != NULL && !is_recursive_call(inline_target)) {311// analyze callee312BCEscapeAnalyzer analyzer(inline_target, this);313314// adjust escape state of actual parameters315bool must_record_dependencies = false;316for (i = arg_size - 1; i >= 0; i--) {317ArgumentMap arg = state.raw_pop();318// Check if callee arg is a caller arg or an allocated object319bool allocated = arg.contains_allocated();320if (!(is_argument(arg) || allocated))321continue;322for (int j = 0; j < _arg_size; j++) {323if (arg.contains(j)) {324_arg_modified[j] |= analyzer._arg_modified[i];325}326}327if (!(is_arg_stack(arg) || allocated)) {328// arguments have already been recognized as escaping329} else if (analyzer.is_arg_stack(i) && !analyzer.is_arg_returned(i)) {330set_method_escape(arg);331must_record_dependencies = true;332} else {333set_global_escape(arg);334}335}336_unknown_modified = _unknown_modified || analyzer.has_non_arg_side_affects();337338// record dependencies if at least one parameter retained stack-allocatable339if (must_record_dependencies) {340if (code == Bytecodes::_invokeinterface ||341(code == Bytecodes::_invokevirtual && !target->is_final_method())) {342_dependencies.append(actual_recv);343_dependencies.append(inline_target);344_dependencies.append(callee_holder);345_dependencies.append(target);346assert(callee_holder->is_interface() == (code == Bytecodes::_invokeinterface), "sanity");347}348_dependencies.appendAll(analyzer.dependencies());349}350} else {351TRACE_BCEA(1, tty->print_cr("[EA] virtual method %s is not monomorphic.",352target->name()->as_utf8()));353// conservatively mark all actual parameters as escaping globally354for (i = 0; i < arg_size; i++) {355ArgumentMap arg = state.raw_pop();356if (!is_argument(arg))357continue;358set_modified(arg, OFFSET_ANY, type2size[T_INT]*HeapWordSize);359set_global_escape(arg);360}361_unknown_modified = true; // assume the worst since we don't know the called method362}363}364365bool BCEscapeAnalyzer::contains(uint arg_set1, uint arg_set2) {366return ((~arg_set1) | arg_set2) == 0;367}368369370void BCEscapeAnalyzer::iterate_one_block(ciBlock *blk, StateInfo &state, GrowableArray<ciBlock *> &successors) {371372blk->set_processed();373ciBytecodeStream s(method());374int limit_bci = blk->limit_bci();375bool fall_through = false;376ArgumentMap allocated_obj;377allocated_obj.add_allocated();378ArgumentMap unknown_obj;379unknown_obj.add_unknown();380ArgumentMap empty_map;381382s.reset_to_bci(blk->start_bci());383while (s.next() != ciBytecodeStream::EOBC() && s.cur_bci() < limit_bci) {384fall_through = true;385switch (s.cur_bc()) {386case Bytecodes::_nop:387break;388case Bytecodes::_aconst_null:389state.apush(unknown_obj);390break;391case Bytecodes::_iconst_m1:392case Bytecodes::_iconst_0:393case Bytecodes::_iconst_1:394case Bytecodes::_iconst_2:395case Bytecodes::_iconst_3:396case Bytecodes::_iconst_4:397case Bytecodes::_iconst_5:398case Bytecodes::_fconst_0:399case Bytecodes::_fconst_1:400case Bytecodes::_fconst_2:401case Bytecodes::_bipush:402case Bytecodes::_sipush:403state.spush();404break;405case Bytecodes::_lconst_0:406case Bytecodes::_lconst_1:407case Bytecodes::_dconst_0:408case Bytecodes::_dconst_1:409state.lpush();410break;411case Bytecodes::_ldc:412case Bytecodes::_ldc_w:413case Bytecodes::_ldc2_w:414{415// Avoid calling get_constant() which will try to allocate416// unloaded constant. We need only constant's type.417int index = s.get_constant_pool_index();418constantTag tag = s.get_constant_pool_tag(index);419if (tag.is_long() || tag.is_double()) {420// Only longs and doubles use 2 stack slots.421state.lpush();422} else if (tag.basic_type() == T_OBJECT) {423state.apush(unknown_obj);424} else {425state.spush();426}427break;428}429case Bytecodes::_aload:430state.apush(state._vars[s.get_index()]);431break;432case Bytecodes::_iload:433case Bytecodes::_fload:434case Bytecodes::_iload_0:435case Bytecodes::_iload_1:436case Bytecodes::_iload_2:437case Bytecodes::_iload_3:438case Bytecodes::_fload_0:439case Bytecodes::_fload_1:440case Bytecodes::_fload_2:441case Bytecodes::_fload_3:442state.spush();443break;444case Bytecodes::_lload:445case Bytecodes::_dload:446case Bytecodes::_lload_0:447case Bytecodes::_lload_1:448case Bytecodes::_lload_2:449case Bytecodes::_lload_3:450case Bytecodes::_dload_0:451case Bytecodes::_dload_1:452case Bytecodes::_dload_2:453case Bytecodes::_dload_3:454state.lpush();455break;456case Bytecodes::_aload_0:457state.apush(state._vars[0]);458break;459case Bytecodes::_aload_1:460state.apush(state._vars[1]);461break;462case Bytecodes::_aload_2:463state.apush(state._vars[2]);464break;465case Bytecodes::_aload_3:466state.apush(state._vars[3]);467break;468case Bytecodes::_iaload:469case Bytecodes::_faload:470case Bytecodes::_baload:471case Bytecodes::_caload:472case Bytecodes::_saload:473state.spop();474set_method_escape(state.apop());475state.spush();476break;477case Bytecodes::_laload:478case Bytecodes::_daload:479state.spop();480set_method_escape(state.apop());481state.lpush();482break;483case Bytecodes::_aaload:484{ state.spop();485ArgumentMap array = state.apop();486set_method_escape(array);487state.apush(unknown_obj);488}489break;490case Bytecodes::_istore:491case Bytecodes::_fstore:492case Bytecodes::_istore_0:493case Bytecodes::_istore_1:494case Bytecodes::_istore_2:495case Bytecodes::_istore_3:496case Bytecodes::_fstore_0:497case Bytecodes::_fstore_1:498case Bytecodes::_fstore_2:499case Bytecodes::_fstore_3:500state.spop();501break;502case Bytecodes::_lstore:503case Bytecodes::_dstore:504case Bytecodes::_lstore_0:505case Bytecodes::_lstore_1:506case Bytecodes::_lstore_2:507case Bytecodes::_lstore_3:508case Bytecodes::_dstore_0:509case Bytecodes::_dstore_1:510case Bytecodes::_dstore_2:511case Bytecodes::_dstore_3:512state.lpop();513break;514case Bytecodes::_astore:515state._vars[s.get_index()] = state.apop();516break;517case Bytecodes::_astore_0:518state._vars[0] = state.apop();519break;520case Bytecodes::_astore_1:521state._vars[1] = state.apop();522break;523case Bytecodes::_astore_2:524state._vars[2] = state.apop();525break;526case Bytecodes::_astore_3:527state._vars[3] = state.apop();528break;529case Bytecodes::_iastore:530case Bytecodes::_fastore:531case Bytecodes::_bastore:532case Bytecodes::_castore:533case Bytecodes::_sastore:534{535state.spop();536state.spop();537ArgumentMap arr = state.apop();538set_method_escape(arr);539set_modified(arr, OFFSET_ANY, type2size[T_INT]*HeapWordSize);540break;541}542case Bytecodes::_lastore:543case Bytecodes::_dastore:544{545state.lpop();546state.spop();547ArgumentMap arr = state.apop();548set_method_escape(arr);549set_modified(arr, OFFSET_ANY, type2size[T_LONG]*HeapWordSize);550break;551}552case Bytecodes::_aastore:553{554set_global_escape(state.apop());555state.spop();556ArgumentMap arr = state.apop();557set_modified(arr, OFFSET_ANY, type2size[T_OBJECT]*HeapWordSize);558break;559}560case Bytecodes::_pop:561state.raw_pop();562break;563case Bytecodes::_pop2:564state.raw_pop();565state.raw_pop();566break;567case Bytecodes::_dup:568{ ArgumentMap w1 = state.raw_pop();569state.raw_push(w1);570state.raw_push(w1);571}572break;573case Bytecodes::_dup_x1:574{ ArgumentMap w1 = state.raw_pop();575ArgumentMap w2 = state.raw_pop();576state.raw_push(w1);577state.raw_push(w2);578state.raw_push(w1);579}580break;581case Bytecodes::_dup_x2:582{ ArgumentMap w1 = state.raw_pop();583ArgumentMap w2 = state.raw_pop();584ArgumentMap w3 = state.raw_pop();585state.raw_push(w1);586state.raw_push(w3);587state.raw_push(w2);588state.raw_push(w1);589}590break;591case Bytecodes::_dup2:592{ ArgumentMap w1 = state.raw_pop();593ArgumentMap w2 = state.raw_pop();594state.raw_push(w2);595state.raw_push(w1);596state.raw_push(w2);597state.raw_push(w1);598}599break;600case Bytecodes::_dup2_x1:601{ ArgumentMap w1 = state.raw_pop();602ArgumentMap w2 = state.raw_pop();603ArgumentMap w3 = state.raw_pop();604state.raw_push(w2);605state.raw_push(w1);606state.raw_push(w3);607state.raw_push(w2);608state.raw_push(w1);609}610break;611case Bytecodes::_dup2_x2:612{ ArgumentMap w1 = state.raw_pop();613ArgumentMap w2 = state.raw_pop();614ArgumentMap w3 = state.raw_pop();615ArgumentMap w4 = state.raw_pop();616state.raw_push(w2);617state.raw_push(w1);618state.raw_push(w4);619state.raw_push(w3);620state.raw_push(w2);621state.raw_push(w1);622}623break;624case Bytecodes::_swap:625{ ArgumentMap w1 = state.raw_pop();626ArgumentMap w2 = state.raw_pop();627state.raw_push(w1);628state.raw_push(w2);629}630break;631case Bytecodes::_iadd:632case Bytecodes::_fadd:633case Bytecodes::_isub:634case Bytecodes::_fsub:635case Bytecodes::_imul:636case Bytecodes::_fmul:637case Bytecodes::_idiv:638case Bytecodes::_fdiv:639case Bytecodes::_irem:640case Bytecodes::_frem:641case Bytecodes::_iand:642case Bytecodes::_ior:643case Bytecodes::_ixor:644state.spop();645state.spop();646state.spush();647break;648case Bytecodes::_ladd:649case Bytecodes::_dadd:650case Bytecodes::_lsub:651case Bytecodes::_dsub:652case Bytecodes::_lmul:653case Bytecodes::_dmul:654case Bytecodes::_ldiv:655case Bytecodes::_ddiv:656case Bytecodes::_lrem:657case Bytecodes::_drem:658case Bytecodes::_land:659case Bytecodes::_lor:660case Bytecodes::_lxor:661state.lpop();662state.lpop();663state.lpush();664break;665case Bytecodes::_ishl:666case Bytecodes::_ishr:667case Bytecodes::_iushr:668state.spop();669state.spop();670state.spush();671break;672case Bytecodes::_lshl:673case Bytecodes::_lshr:674case Bytecodes::_lushr:675state.spop();676state.lpop();677state.lpush();678break;679case Bytecodes::_ineg:680case Bytecodes::_fneg:681state.spop();682state.spush();683break;684case Bytecodes::_lneg:685case Bytecodes::_dneg:686state.lpop();687state.lpush();688break;689case Bytecodes::_iinc:690break;691case Bytecodes::_i2l:692case Bytecodes::_i2d:693case Bytecodes::_f2l:694case Bytecodes::_f2d:695state.spop();696state.lpush();697break;698case Bytecodes::_i2f:699case Bytecodes::_f2i:700state.spop();701state.spush();702break;703case Bytecodes::_l2i:704case Bytecodes::_l2f:705case Bytecodes::_d2i:706case Bytecodes::_d2f:707state.lpop();708state.spush();709break;710case Bytecodes::_l2d:711case Bytecodes::_d2l:712state.lpop();713state.lpush();714break;715case Bytecodes::_i2b:716case Bytecodes::_i2c:717case Bytecodes::_i2s:718state.spop();719state.spush();720break;721case Bytecodes::_lcmp:722case Bytecodes::_dcmpl:723case Bytecodes::_dcmpg:724state.lpop();725state.lpop();726state.spush();727break;728case Bytecodes::_fcmpl:729case Bytecodes::_fcmpg:730state.spop();731state.spop();732state.spush();733break;734case Bytecodes::_ifeq:735case Bytecodes::_ifne:736case Bytecodes::_iflt:737case Bytecodes::_ifge:738case Bytecodes::_ifgt:739case Bytecodes::_ifle:740{741state.spop();742int dest_bci = s.get_dest();743assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block");744assert(s.next_bci() == limit_bci, "branch must end block");745successors.push(_methodBlocks->block_containing(dest_bci));746break;747}748case Bytecodes::_if_icmpeq:749case Bytecodes::_if_icmpne:750case Bytecodes::_if_icmplt:751case Bytecodes::_if_icmpge:752case Bytecodes::_if_icmpgt:753case Bytecodes::_if_icmple:754{755state.spop();756state.spop();757int dest_bci = s.get_dest();758assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block");759assert(s.next_bci() == limit_bci, "branch must end block");760successors.push(_methodBlocks->block_containing(dest_bci));761break;762}763case Bytecodes::_if_acmpeq:764case Bytecodes::_if_acmpne:765{766set_method_escape(state.apop());767set_method_escape(state.apop());768int dest_bci = s.get_dest();769assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block");770assert(s.next_bci() == limit_bci, "branch must end block");771successors.push(_methodBlocks->block_containing(dest_bci));772break;773}774case Bytecodes::_goto:775{776int dest_bci = s.get_dest();777assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block");778assert(s.next_bci() == limit_bci, "branch must end block");779successors.push(_methodBlocks->block_containing(dest_bci));780fall_through = false;781break;782}783case Bytecodes::_jsr:784{785int dest_bci = s.get_dest();786assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block");787assert(s.next_bci() == limit_bci, "branch must end block");788state.apush(empty_map);789successors.push(_methodBlocks->block_containing(dest_bci));790fall_through = false;791break;792}793case Bytecodes::_ret:794// we don't track the destination of a "ret" instruction795assert(s.next_bci() == limit_bci, "branch must end block");796fall_through = false;797break;798case Bytecodes::_return:799assert(s.next_bci() == limit_bci, "return must end block");800fall_through = false;801break;802case Bytecodes::_tableswitch:803{804state.spop();805Bytecode_tableswitch sw(&s);806int len = sw.length();807int dest_bci;808for (int i = 0; i < len; i++) {809dest_bci = s.cur_bci() + sw.dest_offset_at(i);810assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block");811successors.push(_methodBlocks->block_containing(dest_bci));812}813dest_bci = s.cur_bci() + sw.default_offset();814assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block");815successors.push(_methodBlocks->block_containing(dest_bci));816assert(s.next_bci() == limit_bci, "branch must end block");817fall_through = false;818break;819}820case Bytecodes::_lookupswitch:821{822state.spop();823Bytecode_lookupswitch sw(&s);824int len = sw.number_of_pairs();825int dest_bci;826for (int i = 0; i < len; i++) {827dest_bci = s.cur_bci() + sw.pair_at(i).offset();828assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block");829successors.push(_methodBlocks->block_containing(dest_bci));830}831dest_bci = s.cur_bci() + sw.default_offset();832assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block");833successors.push(_methodBlocks->block_containing(dest_bci));834fall_through = false;835break;836}837case Bytecodes::_ireturn:838case Bytecodes::_freturn:839state.spop();840fall_through = false;841break;842case Bytecodes::_lreturn:843case Bytecodes::_dreturn:844state.lpop();845fall_through = false;846break;847case Bytecodes::_areturn:848set_returned(state.apop());849fall_through = false;850break;851case Bytecodes::_getstatic:852case Bytecodes::_getfield:853{ bool ignored_will_link;854ciField* field = s.get_field(ignored_will_link);855BasicType field_type = field->type()->basic_type();856if (s.cur_bc() != Bytecodes::_getstatic) {857set_method_escape(state.apop());858}859if (is_reference_type(field_type)) {860state.apush(unknown_obj);861} else if (type2size[field_type] == 1) {862state.spush();863} else {864state.lpush();865}866}867break;868case Bytecodes::_putstatic:869case Bytecodes::_putfield:870{ bool will_link;871ciField* field = s.get_field(will_link);872BasicType field_type = field->type()->basic_type();873if (is_reference_type(field_type)) {874set_global_escape(state.apop());875} else if (type2size[field_type] == 1) {876state.spop();877} else {878state.lpop();879}880if (s.cur_bc() != Bytecodes::_putstatic) {881ArgumentMap p = state.apop();882set_method_escape(p);883set_modified(p, will_link ? field->offset() : OFFSET_ANY, type2size[field_type]*HeapWordSize);884}885}886break;887case Bytecodes::_invokevirtual:888case Bytecodes::_invokespecial:889case Bytecodes::_invokestatic:890case Bytecodes::_invokedynamic:891case Bytecodes::_invokeinterface:892{ bool ignored_will_link;893ciSignature* declared_signature = NULL;894ciMethod* target = s.get_method(ignored_will_link, &declared_signature);895ciKlass* holder = s.get_declared_method_holder();896assert(declared_signature != NULL, "cannot be null");897// If the current bytecode has an attached appendix argument,898// push an unknown object to represent that argument. (Analysis899// of dynamic call sites, especially invokehandle calls, needs900// the appendix argument on the stack, in addition to "regular" arguments901// pushed onto the stack by bytecode instructions preceding the call.)902//903// The escape analyzer does _not_ use the ciBytecodeStream::has_appendix(s)904// method to determine whether the current bytecode has an appendix argument.905// The has_appendix() method obtains the appendix from the906// ConstantPoolCacheEntry::_f1 field, which can happen concurrently with907// resolution of dynamic call sites. Callees in the908// ciBytecodeStream::get_method() call above also access the _f1 field;909// interleaving the get_method() and has_appendix() calls in the current910// method with call site resolution can lead to an inconsistent view of911// the current method's argument count. In particular, some interleaving(s)912// can cause the method's argument count to not include the appendix, which913// then leads to stack over-/underflow in the escape analyzer.914//915// Instead of pushing the argument if has_appendix() is true, the escape analyzer916// pushes an appendix for all call sites targeted by invokedynamic and invokehandle917// instructions, except if the call site is the _invokeBasic intrinsic918// (that intrinsic is always targeted by an invokehandle instruction but does919// not have an appendix argument).920if (target->is_loaded() &&921Bytecodes::has_optional_appendix(s.cur_bc_raw()) &&922target->intrinsic_id() != vmIntrinsics::_invokeBasic) {923state.apush(unknown_obj);924}925// Pass in raw bytecode because we need to see invokehandle instructions.926invoke(state, s.cur_bc_raw(), target, holder);927// We are using the return type of the declared signature here because928// it might be a more concrete type than the one from the target (for929// e.g. invokedynamic and invokehandle).930ciType* return_type = declared_signature->return_type();931if (!return_type->is_primitive_type()) {932state.apush(unknown_obj);933} else if (return_type->is_one_word()) {934state.spush();935} else if (return_type->is_two_word()) {936state.lpush();937}938}939break;940case Bytecodes::_new:941state.apush(allocated_obj);942break;943case Bytecodes::_newarray:944case Bytecodes::_anewarray:945state.spop();946state.apush(allocated_obj);947break;948case Bytecodes::_multianewarray:949{ int i = s.cur_bcp()[3];950while (i-- > 0) state.spop();951state.apush(allocated_obj);952}953break;954case Bytecodes::_arraylength:955set_method_escape(state.apop());956state.spush();957break;958case Bytecodes::_athrow:959set_global_escape(state.apop());960fall_through = false;961break;962case Bytecodes::_checkcast:963{ ArgumentMap obj = state.apop();964set_method_escape(obj);965state.apush(obj);966}967break;968case Bytecodes::_instanceof:969set_method_escape(state.apop());970state.spush();971break;972case Bytecodes::_monitorenter:973case Bytecodes::_monitorexit:974state.apop();975break;976case Bytecodes::_wide:977ShouldNotReachHere();978break;979case Bytecodes::_ifnull:980case Bytecodes::_ifnonnull:981{982set_method_escape(state.apop());983int dest_bci = s.get_dest();984assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block");985assert(s.next_bci() == limit_bci, "branch must end block");986successors.push(_methodBlocks->block_containing(dest_bci));987break;988}989case Bytecodes::_goto_w:990{991int dest_bci = s.get_far_dest();992assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block");993assert(s.next_bci() == limit_bci, "branch must end block");994successors.push(_methodBlocks->block_containing(dest_bci));995fall_through = false;996break;997}998case Bytecodes::_jsr_w:999{1000int dest_bci = s.get_far_dest();1001assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block");1002assert(s.next_bci() == limit_bci, "branch must end block");1003state.apush(empty_map);1004successors.push(_methodBlocks->block_containing(dest_bci));1005fall_through = false;1006break;1007}1008case Bytecodes::_breakpoint:1009break;1010default:1011ShouldNotReachHere();1012break;1013}10141015}1016if (fall_through) {1017int fall_through_bci = s.cur_bci();1018if (fall_through_bci < _method->code_size()) {1019assert(_methodBlocks->is_block_start(fall_through_bci), "must fall through to block start.");1020successors.push(_methodBlocks->block_containing(fall_through_bci));1021}1022}1023}10241025void BCEscapeAnalyzer::merge_block_states(StateInfo *blockstates, ciBlock *dest, StateInfo *s_state) {1026StateInfo *d_state = blockstates + dest->index();1027int nlocals = _method->max_locals();10281029// exceptions may cause transfer of control to handlers in the middle of a1030// block, so we don't merge the incoming state of exception handlers1031if (dest->is_handler())1032return;1033if (!d_state->_initialized ) {1034// destination not initialized, just copy1035for (int i = 0; i < nlocals; i++) {1036d_state->_vars[i] = s_state->_vars[i];1037}1038for (int i = 0; i < s_state->_stack_height; i++) {1039d_state->_stack[i] = s_state->_stack[i];1040}1041d_state->_stack_height = s_state->_stack_height;1042d_state->_max_stack = s_state->_max_stack;1043d_state->_initialized = true;1044} else if (!dest->processed()) {1045// we have not yet walked the bytecodes of dest, we can merge1046// the states1047assert(d_state->_stack_height == s_state->_stack_height, "computed stack heights must match");1048for (int i = 0; i < nlocals; i++) {1049d_state->_vars[i].set_union(s_state->_vars[i]);1050}1051for (int i = 0; i < s_state->_stack_height; i++) {1052d_state->_stack[i].set_union(s_state->_stack[i]);1053}1054} else {1055// the bytecodes of dest have already been processed, mark any1056// arguments in the source state which are not in the dest state1057// as global escape.1058// Future refinement: we only need to mark these variable to the1059// maximum escape of any variables in dest state1060assert(d_state->_stack_height == s_state->_stack_height, "computed stack heights must match");1061ArgumentMap extra_vars;1062for (int i = 0; i < nlocals; i++) {1063ArgumentMap t;1064t = s_state->_vars[i];1065t.set_difference(d_state->_vars[i]);1066extra_vars.set_union(t);1067}1068for (int i = 0; i < s_state->_stack_height; i++) {1069ArgumentMap t;1070//extra_vars |= !d_state->_vars[i] & s_state->_vars[i];1071t.clear();1072t = s_state->_stack[i];1073t.set_difference(d_state->_stack[i]);1074extra_vars.set_union(t);1075}1076set_global_escape(extra_vars, true);1077}1078}10791080void BCEscapeAnalyzer::iterate_blocks(Arena *arena) {1081int numblocks = _methodBlocks->num_blocks();1082int stkSize = _method->max_stack();1083int numLocals = _method->max_locals();1084StateInfo state;10851086int datacount = (numblocks + 1) * (stkSize + numLocals);1087int datasize = datacount * sizeof(ArgumentMap);1088StateInfo *blockstates = (StateInfo *) arena->Amalloc(numblocks * sizeof(StateInfo));1089ArgumentMap *statedata = (ArgumentMap *) arena->Amalloc(datasize);1090for (int i = 0; i < datacount; i++) ::new ((void*)&statedata[i]) ArgumentMap();1091ArgumentMap *dp = statedata;1092state._vars = dp;1093dp += numLocals;1094state._stack = dp;1095dp += stkSize;1096state._initialized = false;1097state._max_stack = stkSize;1098for (int i = 0; i < numblocks; i++) {1099blockstates[i]._vars = dp;1100dp += numLocals;1101blockstates[i]._stack = dp;1102dp += stkSize;1103blockstates[i]._initialized = false;1104blockstates[i]._stack_height = 0;1105blockstates[i]._max_stack = stkSize;1106}1107GrowableArray<ciBlock *> worklist(arena, numblocks / 4, 0, NULL);1108GrowableArray<ciBlock *> successors(arena, 4, 0, NULL);11091110_methodBlocks->clear_processed();11111112// initialize block 0 state from method signature1113ArgumentMap allVars; // all oop arguments to method1114ciSignature* sig = method()->signature();1115int j = 0;1116ciBlock* first_blk = _methodBlocks->block_containing(0);1117int fb_i = first_blk->index();1118if (!method()->is_static()) {1119// record information for "this"1120blockstates[fb_i]._vars[j].set(j);1121allVars.add(j);1122j++;1123}1124for (int i = 0; i < sig->count(); i++) {1125ciType* t = sig->type_at(i);1126if (!t->is_primitive_type()) {1127blockstates[fb_i]._vars[j].set(j);1128allVars.add(j);1129}1130j += t->size();1131}1132blockstates[fb_i]._initialized = true;1133assert(j == _arg_size, "just checking");11341135ArgumentMap unknown_map;1136unknown_map.add_unknown();11371138worklist.push(first_blk);1139while(worklist.length() > 0) {1140ciBlock *blk = worklist.pop();1141StateInfo *blkState = blockstates + blk->index();1142if (blk->is_handler() || blk->is_ret_target()) {1143// for an exception handler or a target of a ret instruction, we assume the worst case,1144// that any variable could contain any argument1145for (int i = 0; i < numLocals; i++) {1146state._vars[i] = allVars;1147}1148if (blk->is_handler()) {1149state._stack_height = 1;1150} else {1151state._stack_height = blkState->_stack_height;1152}1153for (int i = 0; i < state._stack_height; i++) {1154// ??? should this be unknown_map ???1155state._stack[i] = allVars;1156}1157} else {1158for (int i = 0; i < numLocals; i++) {1159state._vars[i] = blkState->_vars[i];1160}1161for (int i = 0; i < blkState->_stack_height; i++) {1162state._stack[i] = blkState->_stack[i];1163}1164state._stack_height = blkState->_stack_height;1165}1166iterate_one_block(blk, state, successors);1167// if this block has any exception handlers, push them1168// onto successor list1169if (blk->has_handler()) {1170DEBUG_ONLY(int handler_count = 0;)1171int blk_start = blk->start_bci();1172int blk_end = blk->limit_bci();1173for (int i = 0; i < numblocks; i++) {1174ciBlock *b = _methodBlocks->block(i);1175if (b->is_handler()) {1176int ex_start = b->ex_start_bci();1177int ex_end = b->ex_limit_bci();1178if ((ex_start >= blk_start && ex_start < blk_end) ||1179(ex_end > blk_start && ex_end <= blk_end)) {1180successors.push(b);1181}1182DEBUG_ONLY(handler_count++;)1183}1184}1185assert(handler_count > 0, "must find at least one handler");1186}1187// merge computed variable state with successors1188while(successors.length() > 0) {1189ciBlock *succ = successors.pop();1190merge_block_states(blockstates, succ, &state);1191if (!succ->processed())1192worklist.push(succ);1193}1194}1195}11961197void BCEscapeAnalyzer::do_analysis() {1198Arena* arena = CURRENT_ENV->arena();1199// identify basic blocks1200_methodBlocks = _method->get_method_blocks();12011202iterate_blocks(arena);1203}12041205vmIntrinsicID BCEscapeAnalyzer::known_intrinsic() {1206vmIntrinsicID iid = method()->intrinsic_id();1207if (iid == vmIntrinsics::_getClass ||1208iid == vmIntrinsics::_hashCode) {1209return iid;1210} else {1211return vmIntrinsics::_none;1212}1213}12141215void BCEscapeAnalyzer::compute_escape_for_intrinsic(vmIntrinsicID iid) {1216switch (iid) {1217case vmIntrinsics::_getClass:1218_return_local = false;1219_return_allocated = false;1220break;1221case vmIntrinsics::_hashCode:1222// initialized state is correct1223break;1224default:1225assert(false, "unexpected intrinsic");1226}1227}12281229void BCEscapeAnalyzer::initialize() {1230int i;12311232// clear escape information (method may have been deoptimized)1233methodData()->clear_escape_info();12341235// initialize escape state of object parameters1236ciSignature* sig = method()->signature();1237int j = 0;1238if (!method()->is_static()) {1239_arg_local.set(0);1240_arg_stack.set(0);1241j++;1242}1243for (i = 0; i < sig->count(); i++) {1244ciType* t = sig->type_at(i);1245if (!t->is_primitive_type()) {1246_arg_local.set(j);1247_arg_stack.set(j);1248}1249j += t->size();1250}1251assert(j == _arg_size, "just checking");12521253// start with optimistic assumption1254ciType *rt = _method->return_type();1255if (rt->is_primitive_type()) {1256_return_local = false;1257_return_allocated = false;1258} else {1259_return_local = true;1260_return_allocated = true;1261}1262_allocated_escapes = false;1263_unknown_modified = false;1264}12651266void BCEscapeAnalyzer::clear_escape_info() {1267ciSignature* sig = method()->signature();1268int arg_count = sig->count();1269ArgumentMap var;1270if (!method()->is_static()) {1271arg_count++; // allow for "this"1272}1273for (int i = 0; i < arg_count; i++) {1274set_arg_modified(i, OFFSET_ANY, 4);1275var.clear();1276var.set(i);1277set_modified(var, OFFSET_ANY, 4);1278set_global_escape(var);1279}1280_arg_local.clear();1281_arg_stack.clear();1282_arg_returned.clear();1283_return_local = false;1284_return_allocated = false;1285_allocated_escapes = true;1286_unknown_modified = true;1287}128812891290void BCEscapeAnalyzer::compute_escape_info() {1291int i;1292assert(!methodData()->has_escape_info(), "do not overwrite escape info");12931294vmIntrinsicID iid = known_intrinsic();12951296// check if method can be analyzed1297if (iid == vmIntrinsics::_none && (method()->is_abstract() || method()->is_native() || !method()->holder()->is_initialized()1298|| _level > MaxBCEAEstimateLevel1299|| method()->code_size() > MaxBCEAEstimateSize)) {1300if (BCEATraceLevel >= 1) {1301tty->print("Skipping method because: ");1302if (method()->is_abstract())1303tty->print_cr("method is abstract.");1304else if (method()->is_native())1305tty->print_cr("method is native.");1306else if (!method()->holder()->is_initialized())1307tty->print_cr("class of method is not initialized.");1308else if (_level > MaxBCEAEstimateLevel)1309tty->print_cr("level (%d) exceeds MaxBCEAEstimateLevel (%d).",1310_level, (int) MaxBCEAEstimateLevel);1311else if (method()->code_size() > MaxBCEAEstimateSize)1312tty->print_cr("code size (%d) exceeds MaxBCEAEstimateSize (%d).",1313method()->code_size(), (int) MaxBCEAEstimateSize);1314else1315ShouldNotReachHere();1316}1317clear_escape_info();13181319return;1320}13211322if (BCEATraceLevel >= 1) {1323tty->print("[EA] estimating escape information for");1324if (iid != vmIntrinsics::_none)1325tty->print(" intrinsic");1326method()->print_short_name();1327tty->print_cr(" (%d bytes)", method()->code_size());1328}13291330initialize();13311332// Do not scan method if it has no object parameters and1333// does not returns an object (_return_allocated is set in initialize()).1334if (_arg_local.is_empty() && !_return_allocated) {1335// Clear all info since method's bytecode was not analysed and1336// set pessimistic escape information.1337clear_escape_info();1338methodData()->set_eflag(MethodData::allocated_escapes);1339methodData()->set_eflag(MethodData::unknown_modified);1340methodData()->set_eflag(MethodData::estimated);1341return;1342}13431344if (iid != vmIntrinsics::_none)1345compute_escape_for_intrinsic(iid);1346else {1347do_analysis();1348}13491350// don't store interprocedural escape information if it introduces1351// dependencies or if method data is empty1352//1353if (!has_dependencies() && !methodData()->is_empty()) {1354for (i = 0; i < _arg_size; i++) {1355if (_arg_local.test(i)) {1356assert(_arg_stack.test(i), "inconsistent escape info");1357methodData()->set_arg_local(i);1358methodData()->set_arg_stack(i);1359} else if (_arg_stack.test(i)) {1360methodData()->set_arg_stack(i);1361}1362if (_arg_returned.test(i)) {1363methodData()->set_arg_returned(i);1364}1365methodData()->set_arg_modified(i, _arg_modified[i]);1366}1367if (_return_local) {1368methodData()->set_eflag(MethodData::return_local);1369}1370if (_return_allocated) {1371methodData()->set_eflag(MethodData::return_allocated);1372}1373if (_allocated_escapes) {1374methodData()->set_eflag(MethodData::allocated_escapes);1375}1376if (_unknown_modified) {1377methodData()->set_eflag(MethodData::unknown_modified);1378}1379methodData()->set_eflag(MethodData::estimated);1380}1381}13821383void BCEscapeAnalyzer::read_escape_info() {1384assert(methodData()->has_escape_info(), "no escape info available");13851386// read escape information from method descriptor1387for (int i = 0; i < _arg_size; i++) {1388if (methodData()->is_arg_local(i))1389_arg_local.set(i);1390if (methodData()->is_arg_stack(i))1391_arg_stack.set(i);1392if (methodData()->is_arg_returned(i))1393_arg_returned.set(i);1394_arg_modified[i] = methodData()->arg_modified(i);1395}1396_return_local = methodData()->eflag_set(MethodData::return_local);1397_return_allocated = methodData()->eflag_set(MethodData::return_allocated);1398_allocated_escapes = methodData()->eflag_set(MethodData::allocated_escapes);1399_unknown_modified = methodData()->eflag_set(MethodData::unknown_modified);14001401}14021403#ifndef PRODUCT1404void BCEscapeAnalyzer::dump() {1405tty->print("[EA] estimated escape information for");1406method()->print_short_name();1407tty->print_cr(has_dependencies() ? " (not stored)" : "");1408tty->print(" non-escaping args: ");1409_arg_local.print();1410tty->print(" stack-allocatable args: ");1411_arg_stack.print();1412if (_return_local) {1413tty->print(" returned args: ");1414_arg_returned.print();1415} else if (is_return_allocated()) {1416tty->print_cr(" return allocated value");1417} else {1418tty->print_cr(" return non-local value");1419}1420tty->print(" modified args: ");1421for (int i = 0; i < _arg_size; i++) {1422if (_arg_modified[i] == 0)1423tty->print(" 0");1424else1425tty->print(" 0x%x", _arg_modified[i]);1426}1427tty->cr();1428tty->print(" flags: ");1429if (_return_allocated)1430tty->print(" return_allocated");1431if (_allocated_escapes)1432tty->print(" allocated_escapes");1433if (_unknown_modified)1434tty->print(" unknown_modified");1435tty->cr();1436}1437#endif14381439BCEscapeAnalyzer::BCEscapeAnalyzer(ciMethod* method, BCEscapeAnalyzer* parent)1440: _arena(CURRENT_ENV->arena())1441, _conservative(method == NULL || !EstimateArgEscape)1442, _method(method)1443, _methodData(method ? method->method_data() : NULL)1444, _arg_size(method ? method->arg_size() : 0)1445, _arg_local(_arena)1446, _arg_stack(_arena)1447, _arg_returned(_arena)1448, _return_local(false)1449, _return_allocated(false)1450, _allocated_escapes(false)1451, _unknown_modified(false)1452, _dependencies(_arena, 4, 0, NULL)1453, _parent(parent)1454, _level(parent == NULL ? 0 : parent->level() + 1) {1455if (!_conservative) {1456_arg_local.clear();1457_arg_stack.clear();1458_arg_returned.clear();1459Arena* arena = CURRENT_ENV->arena();1460_arg_modified = (uint *) arena->Amalloc(_arg_size * sizeof(uint));1461Copy::zero_to_bytes(_arg_modified, _arg_size * sizeof(uint));14621463if (methodData() == NULL)1464return;1465if (methodData()->has_escape_info()) {1466TRACE_BCEA(2, tty->print_cr("[EA] Reading previous results for %s.%s",1467method->holder()->name()->as_utf8(),1468method->name()->as_utf8()));1469read_escape_info();1470} else {1471TRACE_BCEA(2, tty->print_cr("[EA] computing results for %s.%s",1472method->holder()->name()->as_utf8(),1473method->name()->as_utf8()));14741475compute_escape_info();1476methodData()->update_escape_info();1477}1478#ifndef PRODUCT1479if (BCEATraceLevel >= 3) {1480// dump escape information1481dump();1482}1483#endif1484}1485}14861487void BCEscapeAnalyzer::copy_dependencies(Dependencies *deps) {1488if (ciEnv::current()->jvmti_can_hotswap_or_post_breakpoint()) {1489// Also record evol dependencies so redefinition of the1490// callee will trigger recompilation.1491deps->assert_evol_method(method());1492}1493for (int i = 0; i < _dependencies.length(); i+=4) {1494ciKlass* recv_klass = _dependencies.at(i+0)->as_klass();1495ciMethod* target = _dependencies.at(i+1)->as_method();1496ciKlass* resolved_klass = _dependencies.at(i+2)->as_klass();1497ciMethod* resolved_method = _dependencies.at(i+3)->as_method();1498deps->assert_unique_concrete_method(recv_klass, target, resolved_klass, resolved_method);1499}1500}150115021503