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_CLASSFILE_VERIFIER_HPP
26 #define SHARE_CLASSFILE_VERIFIER_HPP
27
28 #include "classfile/verificationType.hpp"
29 #include "oops/klass.hpp"
30 #include "oops/method.hpp"
31 #include "runtime/handles.hpp"
32 #include "utilities/exceptions.hpp"
33 #include "utilities/growableArray.hpp"
34 #include "utilities/hashTable.hpp"
35
36 // The verifier class
37 class Verifier : AllStatic {
38 public:
39 enum {
40 STACKMAP_ATTRIBUTE_MAJOR_VERSION = 50,
41 INVOKEDYNAMIC_MAJOR_VERSION = 51,
42 NO_RELAX_ACCESS_CTRL_CHECK_VERSION = 52,
43 DYNAMICCONSTANT_MAJOR_VERSION = 55
44 };
45
46 // Verify the bytecodes for a class.
47 static bool verify(InstanceKlass* klass, bool should_verify_class, TRAPS);
48
49 static void log_end_verification(outputStream* st, const char* klassName, Symbol* exception_name,
50 oop pending_exception);
51
52 // Return false if the class is loaded by the bootstrap loader,
53 // or if defineClass was called requesting skipping verification
54 // -Xverify:all overrides this value
55 static bool should_verify_for(oop class_loader);
56
57 // Relax certain access checks to enable some broken 1.1 apps to run on 1.2.
58 static bool relax_access_for(oop class_loader);
59
60 // Print output for class+resolve
61 static void trace_class_resolution(Klass* resolve_class, InstanceKlass* verify_class);
62
63 private:
131 void reset_frame();
132 void details(outputStream* ss) const;
133 void print_frame(outputStream* ss) const;
134 const StackMapFrame* frame() const { return _frame; }
135 bool is_valid() const { return _origin != NONE; }
136 int index() const { return _index; }
137
138 #ifdef ASSERT
139 void print_on(outputStream* str) const;
140 #endif
141 };
142
143 class ErrorContext {
144 private:
145 typedef enum {
146 INVALID_BYTECODE, // There was a problem with the bytecode
147 WRONG_TYPE, // Type value was not as expected
148 FLAGS_MISMATCH, // Frame flags are not assignable
149 BAD_CP_INDEX, // Invalid constant pool index
150 BAD_LOCAL_INDEX, // Invalid local index
151 LOCALS_SIZE_MISMATCH, // Frames have differing local counts
152 STACK_SIZE_MISMATCH, // Frames have different stack sizes
153 STACK_OVERFLOW, // Attempt to push onto a full expression stack
154 STACK_UNDERFLOW, // Attempt to pop and empty expression stack
155 MISSING_STACKMAP, // No stackmap for this location and there should be
156 BAD_STACKMAP, // Format error in stackmap
157 NO_FAULT, // No error
158 UNKNOWN
159 } FaultType;
160
161 int _bci;
162 FaultType _fault;
163 TypeOrigin _type;
164 TypeOrigin _expected;
165
166 ErrorContext(int bci, FaultType fault) :
167 _bci(bci), _fault(fault) {}
168 ErrorContext(int bci, FaultType fault, TypeOrigin type) :
169 _bci(bci), _fault(fault), _type(type) {}
170 ErrorContext(int bci, FaultType fault, TypeOrigin type, TypeOrigin exp) :
171 _bci(bci), _fault(fault), _type(type), _expected(exp) {}
172
173 public:
174 ErrorContext() : _bci(-1), _fault(NO_FAULT) {}
175
176 static ErrorContext bad_code(int bci) {
178 }
179 static ErrorContext bad_type(int bci, TypeOrigin type) {
180 return ErrorContext(bci, WRONG_TYPE, type);
181 }
182 static ErrorContext bad_type(int bci, TypeOrigin type, TypeOrigin exp) {
183 return ErrorContext(bci, WRONG_TYPE, type, exp);
184 }
185 static ErrorContext bad_flags(int bci, StackMapFrame* frame) {
186 return ErrorContext(bci, FLAGS_MISMATCH, TypeOrigin::frame(frame));
187 }
188 static ErrorContext bad_flags(int bci, StackMapFrame* cur, StackMapFrame* sm) {
189 return ErrorContext(bci, FLAGS_MISMATCH,
190 TypeOrigin::frame(cur), TypeOrigin::frame(sm));
191 }
192 static ErrorContext bad_cp_index(int bci, int index) {
193 return ErrorContext(bci, BAD_CP_INDEX, TypeOrigin::bad_index(index));
194 }
195 static ErrorContext bad_local_index(int bci, int index) {
196 return ErrorContext(bci, BAD_LOCAL_INDEX, TypeOrigin::bad_index(index));
197 }
198 static ErrorContext locals_size_mismatch(
199 int bci, StackMapFrame* frame0, StackMapFrame* frame1) {
200 return ErrorContext(bci, LOCALS_SIZE_MISMATCH,
201 TypeOrigin::frame(frame0), TypeOrigin::frame(frame1));
202 }
203 static ErrorContext stack_size_mismatch(
204 int bci, StackMapFrame* frame0, StackMapFrame* frame1) {
205 return ErrorContext(bci, STACK_SIZE_MISMATCH,
206 TypeOrigin::frame(frame0), TypeOrigin::frame(frame1));
207 }
208 static ErrorContext stack_overflow(int bci, StackMapFrame* frame) {
209 return ErrorContext(bci, STACK_OVERFLOW, TypeOrigin::frame(frame));
210 }
211 static ErrorContext stack_underflow(int bci, StackMapFrame* frame) {
212 return ErrorContext(bci, STACK_UNDERFLOW, TypeOrigin::frame(frame));
213 }
214 static ErrorContext missing_stackmap(int bci) {
215 return ErrorContext(bci, MISSING_STACKMAP);
216 }
217 static ErrorContext bad_stackmap(int index, StackMapFrame* frame) {
218 return ErrorContext(0, BAD_STACKMAP, TypeOrigin::frame(frame));
219 }
220
221 bool is_valid() const { return _fault != NO_FAULT; }
222 int bci() const { return _bci; }
223
224 void reset_frames() {
225 _type.reset_frame();
226 _expected.reset_frame();
227 }
228
229 void details(outputStream* ss, const Method* method) const;
230
231 #ifdef ASSERT
232 void print_on(outputStream* str) const {
233 str->print("error_context(%d, %d,", _bci, _fault);
234 _type.print_on(str);
235 str->print(",");
236 _expected.print_on(str);
237 str->print(")");
238 }
239 #endif
319 void verify_ldc(
320 int opcode, u2 index, StackMapFrame *current_frame,
321 const constantPoolHandle& cp, int bci, TRAPS);
322
323 void verify_switch(
324 RawBytecodeStream* bcs, u4 code_length, char* code_data,
325 StackMapFrame* current_frame, StackMapTable* stackmap_table, TRAPS);
326
327 void verify_field_instructions(
328 RawBytecodeStream* bcs, StackMapFrame* current_frame,
329 const constantPoolHandle& cp, bool allow_arrays, TRAPS);
330
331 void verify_invoke_init(
332 RawBytecodeStream* bcs, u2 ref_index, VerificationType ref_class_type,
333 StackMapFrame* current_frame, u4 code_length, bool in_try_block,
334 bool* this_uninit, const constantPoolHandle& cp, StackMapTable* stackmap_table,
335 TRAPS);
336
337 void verify_invoke_instructions(
338 RawBytecodeStream* bcs, u4 code_length, StackMapFrame* current_frame,
339 bool in_try_block, bool* this_uninit, VerificationType return_type,
340 const constantPoolHandle& cp, StackMapTable* stackmap_table, TRAPS);
341
342 VerificationType get_newarray_type(u2 index, int bci, TRAPS);
343 void verify_anewarray(int bci, u2 index, const constantPoolHandle& cp,
344 StackMapFrame* current_frame, TRAPS);
345 void verify_return_value(
346 VerificationType return_type, VerificationType type, int bci,
347 StackMapFrame* current_frame, TRAPS);
348
349 void verify_iload (int index, StackMapFrame* current_frame, TRAPS);
350 void verify_lload (int index, StackMapFrame* current_frame, TRAPS);
351 void verify_fload (int index, StackMapFrame* current_frame, TRAPS);
352 void verify_dload (int index, StackMapFrame* current_frame, TRAPS);
353 void verify_aload (int index, StackMapFrame* current_frame, TRAPS);
354 void verify_istore(int index, StackMapFrame* current_frame, TRAPS);
355 void verify_lstore(int index, StackMapFrame* current_frame, TRAPS);
356 void verify_fstore(int index, StackMapFrame* current_frame, TRAPS);
357 void verify_dstore(int index, StackMapFrame* current_frame, TRAPS);
358 void verify_astore(int index, StackMapFrame* current_frame, TRAPS);
359 void verify_iinc (int index, StackMapFrame* current_frame, TRAPS);
416 ss.print("%s", _message);
417 _error_context.details(&ss, _method());
418 return ss.as_string();
419 }
420
421 // Called when verify or class format errors are encountered.
422 // May throw an exception based upon the mode.
423 void verify_error(ErrorContext ctx, const char* fmt, ...) ATTRIBUTE_PRINTF(3, 4);
424 void class_format_error(const char* fmt, ...) ATTRIBUTE_PRINTF(2, 3);
425
426 Klass* load_class(Symbol* name, TRAPS);
427
428 method_signatures_table_type* method_signatures_table() {
429 return &_method_signatures_table;
430 }
431
432 int change_sig_to_verificationType(
433 SignatureStream* sig_type, VerificationType* inference_type);
434
435 VerificationType cp_index_to_type(int index, const constantPoolHandle& cp, TRAPS) {
436 return VerificationType::reference_type(cp->klass_name_at(index));
437 }
438
439 // Keep a list of temporary symbols created during verification because
440 // their reference counts need to be decremented when the verifier object
441 // goes out of scope. Since these symbols escape the scope in which they're
442 // created, we can't use a TempNewSymbol.
443 Symbol* create_temporary_symbol(const char *s, int length);
444 Symbol* create_temporary_symbol(Symbol* s) {
445 if (s == _previous_symbol) {
446 return s;
447 }
448 if (!s->is_permanent()) {
449 s->increment_refcount();
450 if (_symbols == nullptr) {
451 _symbols = new GrowableArray<Symbol*>(50, 0, nullptr);
452 }
453 _symbols->push(s);
454 }
455 _previous_symbol = s;
456 return s;
457 }
458
459 TypeOrigin ref_ctx(const char* str);
460
461 };
462
463 inline int ClassVerifier::change_sig_to_verificationType(
464 SignatureStream* sig_type, VerificationType* inference_type) {
465 BasicType bt = sig_type->type();
466 switch (bt) {
467 case T_OBJECT:
468 case T_ARRAY:
469 {
470 Symbol* name = sig_type->as_symbol();
471 // Create another symbol to save as signature stream unreferences this symbol.
472 Symbol* name_copy = create_temporary_symbol(name);
473 assert(name_copy == name, "symbols don't match");
474 *inference_type =
475 VerificationType::reference_type(name_copy);
476 return 1;
477 }
478 case T_LONG:
479 *inference_type = VerificationType::long_type();
480 *++inference_type = VerificationType::long2_type();
481 return 2;
482 case T_DOUBLE:
483 *inference_type = VerificationType::double_type();
484 *++inference_type = VerificationType::double2_type();
485 return 2;
486 case T_INT:
487 case T_BOOLEAN:
488 case T_BYTE:
489 case T_CHAR:
490 case T_SHORT:
491 *inference_type = VerificationType::integer_type();
492 return 1;
493 case T_FLOAT:
494 *inference_type = VerificationType::float_type();
495 return 1;
|
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_CLASSFILE_VERIFIER_HPP
26 #define SHARE_CLASSFILE_VERIFIER_HPP
27
28 #include "classfile/verificationType.hpp"
29 #include "oops/klass.hpp"
30 #include "oops/method.hpp"
31 #include "runtime/handles.hpp"
32 #include "utilities/exceptions.hpp"
33 #include "utilities/growableArray.hpp"
34 #include "utilities/hashTable.hpp"
35
36 struct NameAndSig {
37 Symbol* _name;
38 Symbol* _signature;
39
40 NameAndSig(Symbol* n, Symbol* s) : _name(n), _signature(s) {}
41 };
42
43 // The verifier class
44 class Verifier : AllStatic {
45 public:
46 enum {
47 STACKMAP_ATTRIBUTE_MAJOR_VERSION = 50,
48 INVOKEDYNAMIC_MAJOR_VERSION = 51,
49 NO_RELAX_ACCESS_CTRL_CHECK_VERSION = 52,
50 DYNAMICCONSTANT_MAJOR_VERSION = 55,
51 VALUE_TYPES_MAJOR_VERSION = 70,
52 JAVA_PREVIEW_MINOR_VERSION = 65535,
53 };
54
55 // Verify the bytecodes for a class.
56 static bool verify(InstanceKlass* klass, bool should_verify_class, TRAPS);
57
58 static void log_end_verification(outputStream* st, const char* klassName, Symbol* exception_name,
59 oop pending_exception);
60
61 // Return false if the class is loaded by the bootstrap loader,
62 // or if defineClass was called requesting skipping verification
63 // -Xverify:all overrides this value
64 static bool should_verify_for(oop class_loader);
65
66 // Relax certain access checks to enable some broken 1.1 apps to run on 1.2.
67 static bool relax_access_for(oop class_loader);
68
69 // Print output for class+resolve
70 static void trace_class_resolution(Klass* resolve_class, InstanceKlass* verify_class);
71
72 private:
140 void reset_frame();
141 void details(outputStream* ss) const;
142 void print_frame(outputStream* ss) const;
143 const StackMapFrame* frame() const { return _frame; }
144 bool is_valid() const { return _origin != NONE; }
145 int index() const { return _index; }
146
147 #ifdef ASSERT
148 void print_on(outputStream* str) const;
149 #endif
150 };
151
152 class ErrorContext {
153 private:
154 typedef enum {
155 INVALID_BYTECODE, // There was a problem with the bytecode
156 WRONG_TYPE, // Type value was not as expected
157 FLAGS_MISMATCH, // Frame flags are not assignable
158 BAD_CP_INDEX, // Invalid constant pool index
159 BAD_LOCAL_INDEX, // Invalid local index
160 BAD_STRICT_FIELDS, // Strict instance fields must be initialized before super constructor
161 LOCALS_SIZE_MISMATCH, // Frames have differing local counts
162 STACK_SIZE_MISMATCH, // Frames have different stack sizes
163 STRICT_FIELDS_MISMATCH, // Frames have incompatible uninitialized strict instance fields
164 STACK_OVERFLOW, // Attempt to push onto a full expression stack
165 STACK_UNDERFLOW, // Attempt to pop and empty expression stack
166 MISSING_STACKMAP, // No stackmap for this location and there should be
167 BAD_STACKMAP, // Format error in stackmap
168 WRONG_INLINE_TYPE, // Mismatched inline type
169 NO_FAULT, // No error
170 UNKNOWN
171 } FaultType;
172
173 int _bci;
174 FaultType _fault;
175 TypeOrigin _type;
176 TypeOrigin _expected;
177
178 ErrorContext(int bci, FaultType fault) :
179 _bci(bci), _fault(fault) {}
180 ErrorContext(int bci, FaultType fault, TypeOrigin type) :
181 _bci(bci), _fault(fault), _type(type) {}
182 ErrorContext(int bci, FaultType fault, TypeOrigin type, TypeOrigin exp) :
183 _bci(bci), _fault(fault), _type(type), _expected(exp) {}
184
185 public:
186 ErrorContext() : _bci(-1), _fault(NO_FAULT) {}
187
188 static ErrorContext bad_code(int bci) {
190 }
191 static ErrorContext bad_type(int bci, TypeOrigin type) {
192 return ErrorContext(bci, WRONG_TYPE, type);
193 }
194 static ErrorContext bad_type(int bci, TypeOrigin type, TypeOrigin exp) {
195 return ErrorContext(bci, WRONG_TYPE, type, exp);
196 }
197 static ErrorContext bad_flags(int bci, StackMapFrame* frame) {
198 return ErrorContext(bci, FLAGS_MISMATCH, TypeOrigin::frame(frame));
199 }
200 static ErrorContext bad_flags(int bci, StackMapFrame* cur, StackMapFrame* sm) {
201 return ErrorContext(bci, FLAGS_MISMATCH,
202 TypeOrigin::frame(cur), TypeOrigin::frame(sm));
203 }
204 static ErrorContext bad_cp_index(int bci, int index) {
205 return ErrorContext(bci, BAD_CP_INDEX, TypeOrigin::bad_index(index));
206 }
207 static ErrorContext bad_local_index(int bci, int index) {
208 return ErrorContext(bci, BAD_LOCAL_INDEX, TypeOrigin::bad_index(index));
209 }
210 static ErrorContext bad_strict_fields(int bci, StackMapFrame* cur) {
211 return ErrorContext(bci, BAD_STRICT_FIELDS, TypeOrigin::frame(cur));
212 }
213 static ErrorContext locals_size_mismatch(
214 int bci, StackMapFrame* frame0, StackMapFrame* frame1) {
215 return ErrorContext(bci, LOCALS_SIZE_MISMATCH,
216 TypeOrigin::frame(frame0), TypeOrigin::frame(frame1));
217 }
218 static ErrorContext stack_size_mismatch(
219 int bci, StackMapFrame* frame0, StackMapFrame* frame1) {
220 return ErrorContext(bci, STACK_SIZE_MISMATCH,
221 TypeOrigin::frame(frame0), TypeOrigin::frame(frame1));
222 }
223 static ErrorContext strict_fields_mismatch(
224 int bci, StackMapFrame* frame0, StackMapFrame* frame1) {
225 return ErrorContext(bci, STRICT_FIELDS_MISMATCH,
226 TypeOrigin::frame(frame0), TypeOrigin::frame(frame1));
227 }
228 static ErrorContext stack_overflow(int bci, StackMapFrame* frame) {
229 return ErrorContext(bci, STACK_OVERFLOW, TypeOrigin::frame(frame));
230 }
231 static ErrorContext stack_underflow(int bci, StackMapFrame* frame) {
232 return ErrorContext(bci, STACK_UNDERFLOW, TypeOrigin::frame(frame));
233 }
234 static ErrorContext missing_stackmap(int bci) {
235 return ErrorContext(bci, MISSING_STACKMAP);
236 }
237 static ErrorContext bad_stackmap(int index, StackMapFrame* frame) {
238 return ErrorContext(0, BAD_STACKMAP, TypeOrigin::frame(frame));
239 }
240 static ErrorContext bad_inline_type(int bci, TypeOrigin type, TypeOrigin exp) {
241 return ErrorContext(bci, WRONG_INLINE_TYPE, type, exp);
242 }
243
244 bool is_valid() const { return _fault != NO_FAULT; }
245 int bci() const { return _bci; }
246
247 void reset_frames() {
248 _type.reset_frame();
249 _expected.reset_frame();
250 }
251
252 void details(outputStream* ss, const Method* method) const;
253
254 #ifdef ASSERT
255 void print_on(outputStream* str) const {
256 str->print("error_context(%d, %d,", _bci, _fault);
257 _type.print_on(str);
258 str->print(",");
259 _expected.print_on(str);
260 str->print(")");
261 }
262 #endif
342 void verify_ldc(
343 int opcode, u2 index, StackMapFrame *current_frame,
344 const constantPoolHandle& cp, int bci, TRAPS);
345
346 void verify_switch(
347 RawBytecodeStream* bcs, u4 code_length, char* code_data,
348 StackMapFrame* current_frame, StackMapTable* stackmap_table, TRAPS);
349
350 void verify_field_instructions(
351 RawBytecodeStream* bcs, StackMapFrame* current_frame,
352 const constantPoolHandle& cp, bool allow_arrays, TRAPS);
353
354 void verify_invoke_init(
355 RawBytecodeStream* bcs, u2 ref_index, VerificationType ref_class_type,
356 StackMapFrame* current_frame, u4 code_length, bool in_try_block,
357 bool* this_uninit, const constantPoolHandle& cp, StackMapTable* stackmap_table,
358 TRAPS);
359
360 void verify_invoke_instructions(
361 RawBytecodeStream* bcs, u4 code_length, StackMapFrame* current_frame,
362 bool in_try_block, bool* this_uninit,
363 const constantPoolHandle& cp, StackMapTable* stackmap_table, TRAPS);
364
365 VerificationType get_newarray_type(u2 index, int bci, TRAPS);
366 void verify_anewarray(int bci, u2 index, const constantPoolHandle& cp,
367 StackMapFrame* current_frame, TRAPS);
368 void verify_return_value(
369 VerificationType return_type, VerificationType type, int bci,
370 StackMapFrame* current_frame, TRAPS);
371
372 void verify_iload (int index, StackMapFrame* current_frame, TRAPS);
373 void verify_lload (int index, StackMapFrame* current_frame, TRAPS);
374 void verify_fload (int index, StackMapFrame* current_frame, TRAPS);
375 void verify_dload (int index, StackMapFrame* current_frame, TRAPS);
376 void verify_aload (int index, StackMapFrame* current_frame, TRAPS);
377 void verify_istore(int index, StackMapFrame* current_frame, TRAPS);
378 void verify_lstore(int index, StackMapFrame* current_frame, TRAPS);
379 void verify_fstore(int index, StackMapFrame* current_frame, TRAPS);
380 void verify_dstore(int index, StackMapFrame* current_frame, TRAPS);
381 void verify_astore(int index, StackMapFrame* current_frame, TRAPS);
382 void verify_iinc (int index, StackMapFrame* current_frame, TRAPS);
439 ss.print("%s", _message);
440 _error_context.details(&ss, _method());
441 return ss.as_string();
442 }
443
444 // Called when verify or class format errors are encountered.
445 // May throw an exception based upon the mode.
446 void verify_error(ErrorContext ctx, const char* fmt, ...) ATTRIBUTE_PRINTF(3, 4);
447 void class_format_error(const char* fmt, ...) ATTRIBUTE_PRINTF(2, 3);
448
449 Klass* load_class(Symbol* name, TRAPS);
450
451 method_signatures_table_type* method_signatures_table() {
452 return &_method_signatures_table;
453 }
454
455 int change_sig_to_verificationType(
456 SignatureStream* sig_type, VerificationType* inference_type);
457
458 VerificationType cp_index_to_type(int index, const constantPoolHandle& cp, TRAPS) {
459 Symbol* name = cp->klass_name_at(index);
460 return VerificationType::reference_type(name);
461 }
462
463 // Keep a list of temporary symbols created during verification because
464 // their reference counts need to be decremented when the verifier object
465 // goes out of scope. Since these symbols escape the scope in which they're
466 // created, we can't use a TempNewSymbol.
467 Symbol* create_temporary_symbol(const char *s, int length);
468 Symbol* create_temporary_symbol(Symbol* s) {
469 if (s == _previous_symbol) {
470 return s;
471 }
472 if (!s->is_permanent()) {
473 s->increment_refcount();
474 if (_symbols == nullptr) {
475 _symbols = new GrowableArray<Symbol*>(50, 0, nullptr);
476 }
477 _symbols->push(s);
478 }
479 _previous_symbol = s;
480 return s;
481 }
482
483 TypeOrigin ref_ctx(const char* str);
484
485 };
486
487 inline int ClassVerifier::change_sig_to_verificationType(
488 SignatureStream* sig_type, VerificationType* inference_type) {
489 BasicType bt = sig_type->type();
490 switch (bt) {
491 case T_OBJECT:
492 case T_ARRAY:
493 {
494 Symbol* name = sig_type->as_symbol();
495 // Create another symbol to save as signature stream unreferences this symbol.
496 Symbol* name_copy = create_temporary_symbol(name);
497 assert(name_copy == name, "symbols don't match");
498 *inference_type = VerificationType::reference_type(name_copy);
499 return 1;
500 }
501 case T_LONG:
502 *inference_type = VerificationType::long_type();
503 *++inference_type = VerificationType::long2_type();
504 return 2;
505 case T_DOUBLE:
506 *inference_type = VerificationType::double_type();
507 *++inference_type = VerificationType::double2_type();
508 return 2;
509 case T_INT:
510 case T_BOOLEAN:
511 case T_BYTE:
512 case T_CHAR:
513 case T_SHORT:
514 *inference_type = VerificationType::integer_type();
515 return 1;
516 case T_FLOAT:
517 *inference_type = VerificationType::float_type();
518 return 1;
|