1 | /* |
2 | * Copyright (c) 1997, 2019, 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 | */ |
24 | |
25 | #ifndef SHARE_INTERPRETER_BYTECODESTREAM_HPP |
26 | #define SHARE_INTERPRETER_BYTECODESTREAM_HPP |
27 | |
28 | #include "interpreter/bytecode.hpp" |
29 | #include "memory/allocation.hpp" |
30 | #include "oops/method.hpp" |
31 | #include "utilities/bytes.hpp" |
32 | |
33 | // A BytecodeStream is used for fast iteration over the bytecodes |
34 | // of a Method*. |
35 | // |
36 | // Usage: |
37 | // |
38 | // BytecodeStream s(method); |
39 | // Bytecodes::Code c; |
40 | // while ((c = s.next()) >= 0) { |
41 | // ... |
42 | // } |
43 | |
44 | // A RawBytecodeStream is a simple version of BytecodeStream. |
45 | // It is used ONLY when we know the bytecodes haven't been rewritten |
46 | // yet, such as in the rewriter or the verifier. |
47 | |
48 | // Here is the common base class for both RawBytecodeStream and BytecodeStream: |
49 | class BaseBytecodeStream: StackObj { |
50 | protected: |
51 | // stream buffer |
52 | methodHandle _method; // read from method directly |
53 | |
54 | // reading position |
55 | int _bci; // bci if current bytecode |
56 | int _next_bci; // bci of next bytecode |
57 | int _end_bci; // bci after the current iteration interval |
58 | |
59 | // last bytecode read |
60 | Bytecodes::Code _raw_code; |
61 | bool _is_wide; |
62 | bool _is_raw; // false in 'cooked' BytecodeStream |
63 | |
64 | // Construction |
65 | BaseBytecodeStream(const methodHandle& method); |
66 | |
67 | public: |
68 | // Iteration control |
69 | void set_interval(int beg_bci, int end_bci) { |
70 | // iterate over the interval [beg_bci, end_bci) |
71 | assert(0 <= beg_bci && beg_bci <= method()->code_size(), "illegal beg_bci" ); |
72 | assert(0 <= end_bci && end_bci <= method()->code_size(), "illegal end_bci" ); |
73 | // setup of iteration pointers |
74 | _bci = beg_bci; |
75 | _next_bci = beg_bci; |
76 | _end_bci = end_bci; |
77 | } |
78 | void set_start (int beg_bci) { |
79 | set_interval(beg_bci, _method->code_size()); |
80 | } |
81 | |
82 | bool is_raw() const { return _is_raw; } |
83 | |
84 | // Stream attributes |
85 | const methodHandle& method() const { return _method; } |
86 | |
87 | int bci() const { return _bci; } |
88 | int next_bci() const { return _next_bci; } |
89 | int end_bci() const { return _end_bci; } |
90 | |
91 | Bytecodes::Code raw_code() const { return _raw_code; } |
92 | bool is_wide() const { return _is_wide; } |
93 | int instruction_size() const { return (_next_bci - _bci); } |
94 | bool is_last_bytecode() const { return _next_bci >= _end_bci; } |
95 | |
96 | address bcp() const { return method()->code_base() + _bci; } |
97 | Bytecode bytecode() const { return Bytecode(_method(), bcp()); } |
98 | |
99 | // State changes |
100 | void set_next_bci(int bci) { assert(0 <= bci && bci <= method()->code_size(), "illegal bci" ); _next_bci = bci; } |
101 | |
102 | // Bytecode-specific attributes |
103 | int dest() const { return bci() + bytecode().get_offset_s2(raw_code()); } |
104 | int dest_w() const { return bci() + bytecode().get_offset_s4(raw_code()); } |
105 | |
106 | // One-byte indices. |
107 | int get_index_u1() const { assert_raw_index_size(1); return *(jubyte*)(bcp()+1); } |
108 | |
109 | protected: |
110 | void assert_raw_index_size(int size) const NOT_DEBUG_RETURN; |
111 | void assert_raw_stream(bool want_raw) const NOT_DEBUG_RETURN; |
112 | }; |
113 | |
114 | class RawBytecodeStream: public BaseBytecodeStream { |
115 | public: |
116 | // Construction |
117 | RawBytecodeStream(const methodHandle& method) : BaseBytecodeStream(method) { |
118 | _is_raw = true; |
119 | } |
120 | |
121 | public: |
122 | // Iteration |
123 | // Use raw_next() rather than next() for faster method reference |
124 | Bytecodes::Code raw_next() { |
125 | Bytecodes::Code code; |
126 | // set reading position |
127 | _bci = _next_bci; |
128 | assert(!is_last_bytecode(), "caller should check is_last_bytecode()" ); |
129 | |
130 | address bcp = this->bcp(); |
131 | code = Bytecodes::code_or_bp_at(bcp); |
132 | |
133 | // set next bytecode position |
134 | int len = Bytecodes::length_for(code); |
135 | if (len > 0 && (_bci <= _end_bci - len)) { |
136 | assert(code != Bytecodes::_wide && code != Bytecodes::_tableswitch |
137 | && code != Bytecodes::_lookupswitch, "can't be special bytecode" ); |
138 | _is_wide = false; |
139 | _next_bci += len; |
140 | if (_next_bci <= _bci) { // Check for integer overflow |
141 | code = Bytecodes::_illegal; |
142 | } |
143 | _raw_code = code; |
144 | return code; |
145 | } else { |
146 | return raw_next_special(code); |
147 | } |
148 | } |
149 | Bytecodes::Code raw_next_special(Bytecodes::Code code); |
150 | |
151 | // Unsigned indices, widening, with no swapping of bytes |
152 | int get_index() const { return (is_wide()) ? get_index_u2_raw(bcp() + 2) : get_index_u1(); } |
153 | // Get an unsigned 2-byte index, with no swapping of bytes. |
154 | int get_index_u2() const { assert(!is_wide(), "" ); return get_index_u2_raw(bcp() + 1); } |
155 | |
156 | private: |
157 | int get_index_u2_raw(address p) const { |
158 | assert_raw_index_size(2); assert_raw_stream(true); |
159 | return Bytes::get_Java_u2(p); |
160 | } |
161 | }; |
162 | |
163 | // In BytecodeStream, non-java bytecodes will be translated into the |
164 | // corresponding java bytecodes. |
165 | |
166 | class BytecodeStream: public BaseBytecodeStream { |
167 | Bytecodes::Code _code; |
168 | |
169 | public: |
170 | // Construction |
171 | BytecodeStream(const methodHandle& method) : BaseBytecodeStream(method) { } |
172 | |
173 | BytecodeStream(const methodHandle& method, int bci) : BaseBytecodeStream(method) { |
174 | set_start(bci); |
175 | } |
176 | |
177 | // Iteration |
178 | Bytecodes::Code next() { |
179 | Bytecodes::Code raw_code, code; |
180 | // set reading position |
181 | _bci = _next_bci; |
182 | if (is_last_bytecode()) { |
183 | // indicate end of bytecode stream |
184 | raw_code = code = Bytecodes::_illegal; |
185 | } else { |
186 | // get bytecode |
187 | address bcp = this->bcp(); |
188 | raw_code = Bytecodes::code_at(_method(), bcp); |
189 | code = Bytecodes::java_code(raw_code); |
190 | // set next bytecode position |
191 | // |
192 | // note that we cannot advance before having the |
193 | // tty bytecode otherwise the stepping is wrong! |
194 | // (carefull: length_for(...) must be used first!) |
195 | int len = Bytecodes::length_for(code); |
196 | if (len == 0) len = Bytecodes::length_at(_method(), bcp); |
197 | if (len <= 0 || (_bci > _end_bci - len) || (_bci - len >= _next_bci)) { |
198 | raw_code = code = Bytecodes::_illegal; |
199 | } else { |
200 | _next_bci += len; |
201 | assert(_bci < _next_bci, "length must be > 0" ); |
202 | // set attributes |
203 | _is_wide = false; |
204 | // check for special (uncommon) cases |
205 | if (code == Bytecodes::_wide) { |
206 | raw_code = (Bytecodes::Code)bcp[1]; |
207 | code = raw_code; // wide BCs are always Java-normal |
208 | _is_wide = true; |
209 | } |
210 | assert(Bytecodes::is_java_code(code), "sanity check" ); |
211 | } |
212 | } |
213 | _raw_code = raw_code; |
214 | _code = code; |
215 | return _code; |
216 | } |
217 | |
218 | Bytecodes::Code code() const { return _code; } |
219 | |
220 | // Unsigned indices, widening |
221 | int get_index() const { return is_wide() ? bytecode().get_index_u2(raw_code(), true) : get_index_u1(); } |
222 | // Get an unsigned 2-byte index, swapping the bytes if necessary. |
223 | int get_index_u2() const { assert_raw_stream(false); |
224 | return bytecode().get_index_u2(raw_code(), false); } |
225 | // Get an unsigned 2-byte index in native order. |
226 | int get_index_u2_cpcache() const { assert_raw_stream(false); |
227 | return bytecode().get_index_u2_cpcache(raw_code()); } |
228 | int get_index_u4() const { assert_raw_stream(false); |
229 | return bytecode().get_index_u4(raw_code()); } |
230 | bool has_index_u4() const { return bytecode().has_index_u4(raw_code()); } |
231 | }; |
232 | |
233 | #endif // SHARE_INTERPRETER_BYTECODESTREAM_HPP |
234 | |