1 | /* |
2 | * Copyright (c) 2003, 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 | #include "precompiled.hpp" |
26 | #include "interpreter/interpreter.hpp" |
27 | #include "memory/heapInspection.hpp" |
28 | #include "memory/metadataFactory.hpp" |
29 | #include "memory/metaspaceClosure.hpp" |
30 | #include "memory/resourceArea.hpp" |
31 | #include "oops/constMethod.hpp" |
32 | #include "oops/method.hpp" |
33 | #include "runtime/safepointVerifiers.hpp" |
34 | #include "utilities/align.hpp" |
35 | |
36 | // Static initialization |
37 | const u2 ConstMethod::MAX_IDNUM = 0xFFFE; |
38 | const u2 ConstMethod::UNSET_IDNUM = 0xFFFF; |
39 | |
40 | ConstMethod* ConstMethod::allocate(ClassLoaderData* loader_data, |
41 | int byte_code_size, |
42 | InlineTableSizes* sizes, |
43 | MethodType method_type, |
44 | TRAPS) { |
45 | int size = ConstMethod::size(byte_code_size, sizes); |
46 | return new (loader_data, size, MetaspaceObj::ConstMethodType, THREAD) ConstMethod( |
47 | byte_code_size, sizes, method_type, size); |
48 | } |
49 | |
50 | ConstMethod::ConstMethod(int byte_code_size, |
51 | InlineTableSizes* sizes, |
52 | MethodType method_type, |
53 | int size) { |
54 | |
55 | NoSafepointVerifier no_safepoint; |
56 | init_fingerprint(); |
57 | set_constants(NULL); |
58 | set_stackmap_data(NULL); |
59 | set_code_size(byte_code_size); |
60 | set_constMethod_size(size); |
61 | set_inlined_tables_length(sizes); // sets _flags |
62 | set_method_type(method_type); |
63 | assert(this->size() == size, "wrong size for object" ); |
64 | set_name_index(0); |
65 | set_signature_index(0); |
66 | set_constants(NULL); |
67 | set_max_stack(0); |
68 | set_max_locals(0); |
69 | set_method_idnum(0); |
70 | set_size_of_parameters(0); |
71 | set_result_type(T_VOID); |
72 | } |
73 | |
74 | // Accessor that copies to metadata. |
75 | void ConstMethod::copy_stackmap_data(ClassLoaderData* loader_data, |
76 | u1* sd, int length, TRAPS) { |
77 | _stackmap_data = MetadataFactory::new_array<u1>(loader_data, length, CHECK); |
78 | memcpy((void*)_stackmap_data->adr_at(0), (void*)sd, length); |
79 | } |
80 | |
81 | // Deallocate metadata fields associated with ConstMethod* |
82 | void ConstMethod::deallocate_contents(ClassLoaderData* loader_data) { |
83 | if (stackmap_data() != NULL) { |
84 | MetadataFactory::free_array<u1>(loader_data, stackmap_data()); |
85 | } |
86 | set_stackmap_data(NULL); |
87 | |
88 | // deallocate annotation arrays |
89 | if (has_method_annotations()) |
90 | MetadataFactory::free_array<u1>(loader_data, method_annotations()); |
91 | if (has_parameter_annotations()) |
92 | MetadataFactory::free_array<u1>(loader_data, parameter_annotations()); |
93 | if (has_type_annotations()) |
94 | MetadataFactory::free_array<u1>(loader_data, type_annotations()); |
95 | if (has_default_annotations()) |
96 | MetadataFactory::free_array<u1>(loader_data, default_annotations()); |
97 | } |
98 | |
99 | // How big must this constMethodObject be? |
100 | |
101 | int ConstMethod::size(int code_size, |
102 | InlineTableSizes* sizes) { |
103 | int = code_size; |
104 | if (sizes->compressed_linenumber_size() > 0) { |
105 | extra_bytes += sizes->compressed_linenumber_size(); |
106 | } |
107 | if (sizes->checked_exceptions_length() > 0) { |
108 | extra_bytes += sizeof(u2); |
109 | extra_bytes += sizes->checked_exceptions_length() * sizeof(CheckedExceptionElement); |
110 | } |
111 | if (sizes->localvariable_table_length() > 0) { |
112 | extra_bytes += sizeof(u2); |
113 | extra_bytes += |
114 | sizes->localvariable_table_length() * sizeof(LocalVariableTableElement); |
115 | } |
116 | if (sizes->exception_table_length() > 0) { |
117 | extra_bytes += sizeof(u2); |
118 | extra_bytes += sizes->exception_table_length() * sizeof(ExceptionTableElement); |
119 | } |
120 | if (sizes->generic_signature_index() != 0) { |
121 | extra_bytes += sizeof(u2); |
122 | } |
123 | // This has to be a less-than-or-equal check, because we might be |
124 | // storing information from a zero-length MethodParameters |
125 | // attribute. We have to store these, because in some cases, they |
126 | // cause the reflection API to throw a MalformedParametersException. |
127 | if (sizes->method_parameters_length() >= 0) { |
128 | extra_bytes += sizeof(u2); |
129 | extra_bytes += sizes->method_parameters_length() * sizeof(MethodParametersElement); |
130 | } |
131 | |
132 | // Align sizes up to a word. |
133 | extra_bytes = align_up(extra_bytes, BytesPerWord); |
134 | |
135 | // One pointer per annotation array |
136 | if (sizes->method_annotations_length() > 0) { |
137 | extra_bytes += sizeof(AnnotationArray*); |
138 | } |
139 | if (sizes->parameter_annotations_length() > 0) { |
140 | extra_bytes += sizeof(AnnotationArray*); |
141 | } |
142 | if (sizes->type_annotations_length() > 0) { |
143 | extra_bytes += sizeof(AnnotationArray*); |
144 | } |
145 | if (sizes->default_annotations_length() > 0) { |
146 | extra_bytes += sizeof(AnnotationArray*); |
147 | } |
148 | |
149 | int = align_up(extra_bytes, BytesPerWord) / BytesPerWord; |
150 | assert(extra_words == extra_bytes/BytesPerWord, "should already be aligned" ); |
151 | return align_metadata_size(header_size() + extra_words); |
152 | } |
153 | |
154 | Method* ConstMethod::method() const { |
155 | return _constants->pool_holder()->method_with_idnum(_method_idnum); |
156 | } |
157 | |
158 | // linenumber table - note that length is unknown until decompression, |
159 | // see class CompressedLineNumberReadStream. |
160 | |
161 | u_char* ConstMethod::compressed_linenumber_table() const { |
162 | // Located immediately following the bytecodes. |
163 | assert(has_linenumber_table(), "called only if table is present" ); |
164 | return code_end(); |
165 | } |
166 | |
167 | // Last short in ConstMethod* before annotations |
168 | u2* ConstMethod::last_u2_element() const { |
169 | int offset = 0; |
170 | if (has_method_annotations()) offset++; |
171 | if (has_parameter_annotations()) offset++; |
172 | if (has_type_annotations()) offset++; |
173 | if (has_default_annotations()) offset++; |
174 | return (u2*)((AnnotationArray**)constMethod_end() - offset) - 1; |
175 | } |
176 | |
177 | u2* ConstMethod::generic_signature_index_addr() const { |
178 | // Located at the end of the constMethod. |
179 | assert(has_generic_signature(), "called only if generic signature exists" ); |
180 | return last_u2_element(); |
181 | } |
182 | |
183 | u2* ConstMethod::method_parameters_length_addr() const { |
184 | assert(has_method_parameters(), "called only if table is present" ); |
185 | return has_generic_signature() ? (last_u2_element() - 1) : |
186 | last_u2_element(); |
187 | } |
188 | |
189 | u2* ConstMethod::checked_exceptions_length_addr() const { |
190 | // Located immediately before the generic signature index. |
191 | assert(has_checked_exceptions(), "called only if table is present" ); |
192 | if(has_method_parameters()) { |
193 | // If method parameters present, locate immediately before them. |
194 | return (u2*)method_parameters_start() - 1; |
195 | } else { |
196 | // Else, the exception table is at the end of the constMethod. |
197 | return has_generic_signature() ? (last_u2_element() - 1) : |
198 | last_u2_element(); |
199 | } |
200 | } |
201 | |
202 | u2* ConstMethod::exception_table_length_addr() const { |
203 | assert(has_exception_handler(), "called only if table is present" ); |
204 | if (has_checked_exceptions()) { |
205 | // If checked_exception present, locate immediately before them. |
206 | return (u2*) checked_exceptions_start() - 1; |
207 | } else { |
208 | if(has_method_parameters()) { |
209 | // If method parameters present, locate immediately before them. |
210 | return (u2*)method_parameters_start() - 1; |
211 | } else { |
212 | // Else, the exception table is at the end of the constMethod. |
213 | return has_generic_signature() ? (last_u2_element() - 1) : |
214 | last_u2_element(); |
215 | } |
216 | } |
217 | } |
218 | |
219 | u2* ConstMethod::localvariable_table_length_addr() const { |
220 | assert(has_localvariable_table(), "called only if table is present" ); |
221 | if (has_exception_handler()) { |
222 | // If exception_table present, locate immediately before them. |
223 | return (u2*) exception_table_start() - 1; |
224 | } else { |
225 | if (has_checked_exceptions()) { |
226 | // If checked_exception present, locate immediately before them. |
227 | return (u2*) checked_exceptions_start() - 1; |
228 | } else { |
229 | if(has_method_parameters()) { |
230 | // If method parameters present, locate immediately before them. |
231 | return (u2*)method_parameters_start() - 1; |
232 | } else { |
233 | // Else, the exception table is at the end of the constMethod. |
234 | return has_generic_signature() ? (last_u2_element() - 1) : |
235 | last_u2_element(); |
236 | } |
237 | } |
238 | } |
239 | } |
240 | |
241 | // Update the flags to indicate the presence of these optional fields. |
242 | void ConstMethod::set_inlined_tables_length(InlineTableSizes* sizes) { |
243 | _flags = 0; |
244 | if (sizes->compressed_linenumber_size() > 0) |
245 | _flags |= _has_linenumber_table; |
246 | if (sizes->generic_signature_index() != 0) |
247 | _flags |= _has_generic_signature; |
248 | if (sizes->method_parameters_length() >= 0) |
249 | _flags |= _has_method_parameters; |
250 | if (sizes->checked_exceptions_length() > 0) |
251 | _flags |= _has_checked_exceptions; |
252 | if (sizes->exception_table_length() > 0) |
253 | _flags |= _has_exception_table; |
254 | if (sizes->localvariable_table_length() > 0) |
255 | _flags |= _has_localvariable_table; |
256 | |
257 | // annotations, they are all pointer sized embedded objects so don't have |
258 | // a length embedded also. |
259 | if (sizes->method_annotations_length() > 0) |
260 | _flags |= _has_method_annotations; |
261 | if (sizes->parameter_annotations_length() > 0) |
262 | _flags |= _has_parameter_annotations; |
263 | if (sizes->type_annotations_length() > 0) |
264 | _flags |= _has_type_annotations; |
265 | if (sizes->default_annotations_length() > 0) |
266 | _flags |= _has_default_annotations; |
267 | |
268 | // This code is extremely brittle and should possibly be revised. |
269 | // The *_length_addr functions walk backwards through the |
270 | // constMethod data, using each of the length indexes ahead of them, |
271 | // as well as the flags variable. Therefore, the indexes must be |
272 | // initialized in reverse order, or else they will compute the wrong |
273 | // offsets. Moving the initialization of _flags into a separate |
274 | // block solves *half* of the problem, but the following part will |
275 | // still break if the order is not exactly right. |
276 | // |
277 | // Also, the servicability agent needs to be informed anytime |
278 | // anything is added here. It might be advisable to have some sort |
279 | // of indication of this inline. |
280 | if (sizes->generic_signature_index() != 0) |
281 | *(generic_signature_index_addr()) = sizes->generic_signature_index(); |
282 | // New data should probably go here. |
283 | if (sizes->method_parameters_length() >= 0) |
284 | *(method_parameters_length_addr()) = sizes->method_parameters_length(); |
285 | if (sizes->checked_exceptions_length() > 0) |
286 | *(checked_exceptions_length_addr()) = sizes->checked_exceptions_length(); |
287 | if (sizes->exception_table_length() > 0) |
288 | *(exception_table_length_addr()) = sizes->exception_table_length(); |
289 | if (sizes->localvariable_table_length() > 0) |
290 | *(localvariable_table_length_addr()) = sizes->localvariable_table_length(); |
291 | } |
292 | |
293 | int ConstMethod::method_parameters_length() const { |
294 | return has_method_parameters() ? *(method_parameters_length_addr()) : -1; |
295 | } |
296 | |
297 | MethodParametersElement* ConstMethod::method_parameters_start() const { |
298 | u2* addr = method_parameters_length_addr(); |
299 | u2 length = *addr; |
300 | addr -= length * sizeof(MethodParametersElement) / sizeof(u2); |
301 | return (MethodParametersElement*) addr; |
302 | } |
303 | |
304 | |
305 | int ConstMethod::checked_exceptions_length() const { |
306 | return has_checked_exceptions() ? *(checked_exceptions_length_addr()) : 0; |
307 | } |
308 | |
309 | |
310 | CheckedExceptionElement* ConstMethod::checked_exceptions_start() const { |
311 | u2* addr = checked_exceptions_length_addr(); |
312 | u2 length = *addr; |
313 | assert(length > 0, "should only be called if table is present" ); |
314 | addr -= length * sizeof(CheckedExceptionElement) / sizeof(u2); |
315 | return (CheckedExceptionElement*) addr; |
316 | } |
317 | |
318 | |
319 | int ConstMethod::localvariable_table_length() const { |
320 | return has_localvariable_table() ? *(localvariable_table_length_addr()) : 0; |
321 | } |
322 | |
323 | |
324 | LocalVariableTableElement* ConstMethod::localvariable_table_start() const { |
325 | u2* addr = localvariable_table_length_addr(); |
326 | u2 length = *addr; |
327 | assert(length > 0, "should only be called if table is present" ); |
328 | addr -= length * sizeof(LocalVariableTableElement) / sizeof(u2); |
329 | return (LocalVariableTableElement*) addr; |
330 | } |
331 | |
332 | int ConstMethod::exception_table_length() const { |
333 | return has_exception_handler() ? *(exception_table_length_addr()) : 0; |
334 | } |
335 | |
336 | ExceptionTableElement* ConstMethod::exception_table_start() const { |
337 | u2* addr = exception_table_length_addr(); |
338 | u2 length = *addr; |
339 | assert(length > 0, "should only be called if table is present" ); |
340 | addr -= length * sizeof(ExceptionTableElement) / sizeof(u2); |
341 | return (ExceptionTableElement*)addr; |
342 | } |
343 | |
344 | AnnotationArray** ConstMethod::method_annotations_addr() const { |
345 | assert(has_method_annotations(), "should only be called if method annotations are present" ); |
346 | return (AnnotationArray**)constMethod_end() - 1; |
347 | } |
348 | |
349 | AnnotationArray** ConstMethod::parameter_annotations_addr() const { |
350 | assert(has_parameter_annotations(), "should only be called if method parameter annotations are present" ); |
351 | int offset = 1; |
352 | if (has_method_annotations()) offset++; |
353 | return (AnnotationArray**)constMethod_end() - offset; |
354 | } |
355 | |
356 | AnnotationArray** ConstMethod::type_annotations_addr() const { |
357 | assert(has_type_annotations(), "should only be called if method type annotations are present" ); |
358 | int offset = 1; |
359 | if (has_method_annotations()) offset++; |
360 | if (has_parameter_annotations()) offset++; |
361 | return (AnnotationArray**)constMethod_end() - offset; |
362 | } |
363 | |
364 | AnnotationArray** ConstMethod::default_annotations_addr() const { |
365 | assert(has_default_annotations(), "should only be called if method default annotations are present" ); |
366 | int offset = 1; |
367 | if (has_method_annotations()) offset++; |
368 | if (has_parameter_annotations()) offset++; |
369 | if (has_type_annotations()) offset++; |
370 | return (AnnotationArray**)constMethod_end() - offset; |
371 | } |
372 | |
373 | Array<u1>* copy_annotations(ClassLoaderData* loader_data, AnnotationArray* from, TRAPS) { |
374 | int length = from->length(); |
375 | Array<u1>* a = MetadataFactory::new_array<u1>(loader_data, length, 0, CHECK_NULL); |
376 | memcpy((void*)a->adr_at(0), (void*)from->adr_at(0), length); |
377 | return a; |
378 | } |
379 | |
380 | // copy annotations from 'cm' to 'this' |
381 | // Must make copy because these are deallocated with their constMethod, if redefined. |
382 | void ConstMethod::copy_annotations_from(ClassLoaderData* loader_data, ConstMethod* cm, TRAPS) { |
383 | Array<u1>* a; |
384 | if (cm->has_method_annotations()) { |
385 | assert(has_method_annotations(), "should be allocated already" ); |
386 | a = copy_annotations(loader_data, cm->method_annotations(), CHECK); |
387 | set_method_annotations(a); |
388 | } |
389 | if (cm->has_parameter_annotations()) { |
390 | assert(has_parameter_annotations(), "should be allocated already" ); |
391 | a = copy_annotations(loader_data, cm->parameter_annotations(), CHECK); |
392 | set_parameter_annotations(a); |
393 | } |
394 | if (cm->has_type_annotations()) { |
395 | assert(has_type_annotations(), "should be allocated already" ); |
396 | a = copy_annotations(loader_data, cm->type_annotations(), CHECK); |
397 | set_type_annotations(a); |
398 | } |
399 | if (cm->has_default_annotations()) { |
400 | assert(has_default_annotations(), "should be allocated already" ); |
401 | a = copy_annotations(loader_data, cm->default_annotations(), CHECK); |
402 | set_default_annotations(a); |
403 | } |
404 | } |
405 | |
406 | void ConstMethod::metaspace_pointers_do(MetaspaceClosure* it) { |
407 | log_trace(cds)("Iter(ConstMethod): %p" , this); |
408 | |
409 | it->push(&_constants); |
410 | it->push(&_stackmap_data); |
411 | if (has_method_annotations()) { |
412 | it->push(method_annotations_addr()); |
413 | } |
414 | if (has_parameter_annotations()) { |
415 | it->push(parameter_annotations_addr()); |
416 | } |
417 | if (has_type_annotations()) { |
418 | it->push(type_annotations_addr()); |
419 | } |
420 | if (has_default_annotations()) { |
421 | it->push(default_annotations_addr()); |
422 | } |
423 | } |
424 | |
425 | // Printing |
426 | |
427 | void ConstMethod::print_on(outputStream* st) const { |
428 | ResourceMark rm; |
429 | st->print_cr("%s" , internal_name()); |
430 | Method* m = method(); |
431 | st->print(" - method: " INTPTR_FORMAT " " , p2i((address)m)); |
432 | if (m != NULL) { |
433 | m->print_value_on(st); |
434 | } |
435 | st->cr(); |
436 | if (has_stackmap_table()) { |
437 | st->print(" - stackmap data: " ); |
438 | stackmap_data()->print_value_on(st); |
439 | st->cr(); |
440 | } |
441 | } |
442 | |
443 | // Short version of printing ConstMethod* - just print the name of the |
444 | // method it belongs to. |
445 | void ConstMethod::print_value_on(outputStream* st) const { |
446 | st->print(" const part of method " ); |
447 | Method* m = method(); |
448 | if (m != NULL) { |
449 | m->print_value_on(st); |
450 | } else { |
451 | st->print("NULL" ); |
452 | } |
453 | } |
454 | |
455 | #if INCLUDE_SERVICES |
456 | // Size Statistics |
457 | void ConstMethod::collect_statistics(KlassSizeStats *sz) const { |
458 | int n1, n2, n3; |
459 | sz->_const_method_bytes += (n1 = sz->count(this)); |
460 | sz->_bytecode_bytes += (n2 = code_size()); |
461 | sz->_stackmap_bytes += (n3 = sz->count_array(stackmap_data())); |
462 | |
463 | // Count method annotations |
464 | int a1 = 0, a2 = 0, a3 = 0, a4 = 0; |
465 | if (has_method_annotations()) { |
466 | sz->_methods_annotations_bytes += (a1 = sz->count_array(method_annotations())); |
467 | } |
468 | if (has_parameter_annotations()) { |
469 | sz->_methods_parameter_annotations_bytes += (a2 = sz->count_array(parameter_annotations())); |
470 | } |
471 | if (has_type_annotations()) { |
472 | sz->_methods_type_annotations_bytes += (a3 = sz->count_array(type_annotations())); |
473 | } |
474 | if (has_default_annotations()) { |
475 | sz->_methods_default_annotations_bytes += (a4 = sz->count_array(default_annotations())); |
476 | } |
477 | |
478 | int size_annotations = a1 + a2 + a3 + a4; |
479 | |
480 | sz->_method_all_bytes += n1 + n3 + size_annotations; // note: n2 is part of n3 |
481 | sz->_ro_bytes += n1 + n3 + size_annotations; |
482 | } |
483 | #endif // INCLUDE_SERVICES |
484 | |
485 | // Verification |
486 | |
487 | void ConstMethod::verify_on(outputStream* st) { |
488 | // Verification can occur during oop construction before the method or |
489 | // other fields have been initialized. |
490 | guarantee(method() != NULL && method()->is_method(), "should be method" ); |
491 | |
492 | address m_end = (address)((intptr_t) this + size()); |
493 | address compressed_table_start = code_end(); |
494 | guarantee(compressed_table_start <= m_end, "invalid method layout" ); |
495 | address compressed_table_end = compressed_table_start; |
496 | // Verify line number table |
497 | if (has_linenumber_table()) { |
498 | CompressedLineNumberReadStream stream(compressed_linenumber_table()); |
499 | while (stream.read_pair()) { |
500 | guarantee(stream.bci() >= 0 && stream.bci() <= code_size(), "invalid bci in line number table" ); |
501 | } |
502 | compressed_table_end += stream.position(); |
503 | } |
504 | guarantee(compressed_table_end <= m_end, "invalid method layout" ); |
505 | // Verify checked exceptions, exception table and local variable tables |
506 | if (has_method_parameters()) { |
507 | u2* addr = method_parameters_length_addr(); |
508 | guarantee(*addr > 0 && (address) addr >= compressed_table_end && (address) addr < m_end, "invalid method layout" ); |
509 | } |
510 | if (has_checked_exceptions()) { |
511 | u2* addr = checked_exceptions_length_addr(); |
512 | guarantee(*addr > 0 && (address) addr >= compressed_table_end && (address) addr < m_end, "invalid method layout" ); |
513 | } |
514 | if (has_exception_handler()) { |
515 | u2* addr = exception_table_length_addr(); |
516 | guarantee(*addr > 0 && (address) addr >= compressed_table_end && (address) addr < m_end, "invalid method layout" ); |
517 | } |
518 | if (has_localvariable_table()) { |
519 | u2* addr = localvariable_table_length_addr(); |
520 | guarantee(*addr > 0 && (address) addr >= compressed_table_end && (address) addr < m_end, "invalid method layout" ); |
521 | } |
522 | // Check compressed_table_end relative to uncompressed_table_start |
523 | u2* uncompressed_table_start; |
524 | if (has_localvariable_table()) { |
525 | uncompressed_table_start = (u2*) localvariable_table_start(); |
526 | } else if (has_exception_handler()) { |
527 | uncompressed_table_start = (u2*) exception_table_start(); |
528 | } else if (has_checked_exceptions()) { |
529 | uncompressed_table_start = (u2*) checked_exceptions_start(); |
530 | } else if (has_method_parameters()) { |
531 | uncompressed_table_start = (u2*) method_parameters_start(); |
532 | } else { |
533 | uncompressed_table_start = (u2*) m_end; |
534 | } |
535 | int gap = (intptr_t) uncompressed_table_start - (intptr_t) compressed_table_end; |
536 | int max_gap = align_metadata_size(1)*BytesPerWord; |
537 | guarantee(gap >= 0 && gap < max_gap, "invalid method layout" ); |
538 | } |
539 | |