From d19a396e96cee4bb4facb268c723f23cbae83351 Mon Sep 17 00:00:00 2001 From: Lois Foltan Date: Thu, 6 Feb 2020 14:29:57 +0000 Subject: [PATCH] 8230199: consolidate signature parsing code in HotSpot sources Add a new Signature class to support basic signature queries and enhance SignatureStream class to parse field signatures in addition to methods. Co-authored-by: John Rose Reviewed-by: coleenp, dholmes, fparain, hseigel --- .../cpu/aarch64/sharedRuntime_aarch64.cpp | 24 +- src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp | 24 +- src/hotspot/cpu/s390/sharedRuntime_s390.cpp | 24 +- src/hotspot/cpu/sparc/sharedRuntime_sparc.cpp | 24 +- src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp | 24 +- src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp | 24 +- src/hotspot/share/c1/c1_ValueMap.cpp | 16 +- src/hotspot/share/ci/ciEnv.cpp | 19 +- src/hotspot/share/ci/ciField.cpp | 4 +- src/hotspot/share/ci/ciKlass.hpp | 3 +- src/hotspot/share/ci/ciObjArrayKlass.cpp | 42 +- src/hotspot/share/ci/ciObjectFactory.cpp | 18 +- src/hotspot/share/ci/ciSignature.cpp | 8 +- .../share/classfile/classFileParser.cpp | 32 +- .../share/classfile/classListParser.cpp | 5 +- .../share/classfile/defaultMethods.cpp | 5 +- src/hotspot/share/classfile/placeholders.cpp | 3 +- src/hotspot/share/classfile/stackMapTable.cpp | 3 +- .../share/classfile/systemDictionary.cpp | 126 ++-- .../share/classfile/systemDictionary.hpp | 6 +- .../share/classfile/verificationType.cpp | 46 +- src/hotspot/share/classfile/vmSymbols.cpp | 22 +- src/hotspot/share/classfile/vmSymbols.hpp | 4 +- src/hotspot/share/code/nmethod.cpp | 12 +- src/hotspot/share/compiler/methodMatcher.cpp | 5 +- src/hotspot/share/interpreter/bytecode.cpp | 3 +- .../share/interpreter/bytecodeUtils.cpp | 11 +- .../share/interpreter/interpreterRuntime.cpp | 4 +- src/hotspot/share/interpreter/oopMapCache.cpp | 4 +- src/hotspot/share/interpreter/rewriter.cpp | 4 +- src/hotspot/share/jvmci/compilerRuntime.cpp | 12 +- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 41 +- src/hotspot/share/jvmci/jvmciCompilerToVM.hpp | 46 +- src/hotspot/share/oops/constMethod.cpp | 2 +- src/hotspot/share/oops/constantPool.cpp | 7 +- src/hotspot/share/oops/generateOopMap.cpp | 91 ++- src/hotspot/share/oops/generateOopMap.hpp | 4 +- src/hotspot/share/oops/method.cpp | 28 +- src/hotspot/share/oops/method.hpp | 6 +- src/hotspot/share/oops/methodData.cpp | 41 +- src/hotspot/share/oops/symbol.cpp | 88 +-- src/hotspot/share/oops/symbol.hpp | 30 +- src/hotspot/share/prims/jni.cpp | 256 ++----- src/hotspot/share/prims/jvmtiImpl.cpp | 6 +- src/hotspot/share/prims/methodHandles.cpp | 116 +--- src/hotspot/share/prims/methodHandles.hpp | 4 +- src/hotspot/share/runtime/deoptimization.cpp | 35 +- src/hotspot/share/runtime/fieldDescriptor.hpp | 3 +- .../share/runtime/fieldDescriptor.inline.hpp | 4 +- src/hotspot/share/runtime/frame.cpp | 58 +- src/hotspot/share/runtime/javaCalls.cpp | 74 +- src/hotspot/share/runtime/reflection.cpp | 5 +- src/hotspot/share/runtime/sharedRuntime.cpp | 37 +- src/hotspot/share/runtime/signature.cpp | 606 ++++++++-------- src/hotspot/share/runtime/signature.hpp | 656 +++++++++++------- .../share/utilities/globalDefinitions.cpp | 20 +- .../share/utilities/globalDefinitions.hpp | 43 +- 57 files changed, 1382 insertions(+), 1486 deletions(-) diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp index d7668172751..e1ec57e16b4 100644 --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2019, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -1333,28 +1333,16 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Arrays are passed as int, elem* pair out_sig_bt[argc++] = T_INT; out_sig_bt[argc++] = T_ADDRESS; - Symbol* atype = ss.as_symbol(); - const char* at = atype->as_C_string(); - if (strlen(at) == 2) { - assert(at[0] == '[', "must be"); - switch (at[1]) { - case 'B': in_elem_bt[i] = T_BYTE; break; - case 'C': in_elem_bt[i] = T_CHAR; break; - case 'D': in_elem_bt[i] = T_DOUBLE; break; - case 'F': in_elem_bt[i] = T_FLOAT; break; - case 'I': in_elem_bt[i] = T_INT; break; - case 'J': in_elem_bt[i] = T_LONG; break; - case 'S': in_elem_bt[i] = T_SHORT; break; - case 'Z': in_elem_bt[i] = T_BOOLEAN; break; - default: ShouldNotReachHere(); - } - } + ss.skip_array_prefix(1); // skip one '[' + assert(ss.is_primitive(), "primitive type expected"); + in_elem_bt[i] = ss.type(); } else { out_sig_bt[argc++] = in_sig_bt[i]; in_elem_bt[i] = T_VOID; } if (in_sig_bt[i] != T_VOID) { - assert(in_sig_bt[i] == ss.type(), "must match"); + assert(in_sig_bt[i] == ss.type() || + in_sig_bt[i] == T_ARRAY, "must match"); ss.next(); } } diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp index a514173f3fa..5db8558fa72 100644 --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2019 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -1934,27 +1934,15 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, for (int i = 0; i < total_in_args ; i++, o++) { if (in_sig_bt[i] == T_ARRAY) { // Arrays are passed as int, elem* pair - Symbol* atype = ss.as_symbol(); - const char* at = atype->as_C_string(); - if (strlen(at) == 2) { - assert(at[0] == '[', "must be"); - switch (at[1]) { - case 'B': in_elem_bt[o] = T_BYTE; break; - case 'C': in_elem_bt[o] = T_CHAR; break; - case 'D': in_elem_bt[o] = T_DOUBLE; break; - case 'F': in_elem_bt[o] = T_FLOAT; break; - case 'I': in_elem_bt[o] = T_INT; break; - case 'J': in_elem_bt[o] = T_LONG; break; - case 'S': in_elem_bt[o] = T_SHORT; break; - case 'Z': in_elem_bt[o] = T_BOOLEAN; break; - default: ShouldNotReachHere(); - } - } + ss.skip_array_prefix(1); // skip one '[' + assert(ss.is_primitive(), "primitive type expected"); + in_elem_bt[o] = ss.type(); } else { in_elem_bt[o] = T_VOID; } if (in_sig_bt[i] != T_VOID) { - assert(in_sig_bt[i] == ss.type(), "must match"); + assert(in_sig_bt[i] == ss.type() || + in_sig_bt[i] == T_ARRAY, "must match"); ss.next(); } } diff --git a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp index 54beb8263ea..373c89055b4 100644 --- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp +++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2019, SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -1626,27 +1626,15 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, for (int i = 0; i < total_in_args; i++, o++) { if (in_sig_bt[i] == T_ARRAY) { // Arrays are passed as tuples (int, elem*). - Symbol* atype = ss.as_symbol(); - const char* at = atype->as_C_string(); - if (strlen(at) == 2) { - assert(at[0] == '[', "must be"); - switch (at[1]) { - case 'B': in_elem_bt[o] = T_BYTE; break; - case 'C': in_elem_bt[o] = T_CHAR; break; - case 'D': in_elem_bt[o] = T_DOUBLE; break; - case 'F': in_elem_bt[o] = T_FLOAT; break; - case 'I': in_elem_bt[o] = T_INT; break; - case 'J': in_elem_bt[o] = T_LONG; break; - case 'S': in_elem_bt[o] = T_SHORT; break; - case 'Z': in_elem_bt[o] = T_BOOLEAN; break; - default: ShouldNotReachHere(); - } - } + ss.skip_array_prefix(1); // skip one '[' + assert(ss.is_primitive(), "primitive type expected"); + in_elem_bt[o] = ss.type(); } else { in_elem_bt[o] = T_VOID; } if (in_sig_bt[i] != T_VOID) { - assert(in_sig_bt[i] == ss.type(), "must match"); + assert(in_sig_bt[i] == ss.type() || + in_sig_bt[i] == T_ARRAY, "must match"); ss.next(); } } diff --git a/src/hotspot/cpu/sparc/sharedRuntime_sparc.cpp b/src/hotspot/cpu/sparc/sharedRuntime_sparc.cpp index 38dd6d9cd34..7a1b9ce5ba7 100644 --- a/src/hotspot/cpu/sparc/sharedRuntime_sparc.cpp +++ b/src/hotspot/cpu/sparc/sharedRuntime_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1907,28 +1907,16 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Arrays are passed as int, elem* pair out_sig_bt[argc++] = T_INT; out_sig_bt[argc++] = T_ADDRESS; - Symbol* atype = ss.as_symbol(); - const char* at = atype->as_C_string(); - if (strlen(at) == 2) { - assert(at[0] == '[', "must be"); - switch (at[1]) { - case 'B': in_elem_bt[i] = T_BYTE; break; - case 'C': in_elem_bt[i] = T_CHAR; break; - case 'D': in_elem_bt[i] = T_DOUBLE; break; - case 'F': in_elem_bt[i] = T_FLOAT; break; - case 'I': in_elem_bt[i] = T_INT; break; - case 'J': in_elem_bt[i] = T_LONG; break; - case 'S': in_elem_bt[i] = T_SHORT; break; - case 'Z': in_elem_bt[i] = T_BOOLEAN; break; - default: ShouldNotReachHere(); - } - } + ss.skip_array_prefix(1); // skip one '[' + assert(ss.is_primitive(), "primitive type expected"); + in_elem_bt[i] = ss.type(); } else { out_sig_bt[argc++] = in_sig_bt[i]; in_elem_bt[i] = T_VOID; } if (in_sig_bt[i] != T_VOID) { - assert(in_sig_bt[i] == ss.type(), "must match"); + assert(in_sig_bt[i] == ss.type() || + in_sig_bt[i] == T_ARRAY, "must match"); ss.next(); } } diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp index 97609ef0e2a..7c57d3ad647 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1697,28 +1697,16 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Arrays are passed as int, elem* pair out_sig_bt[argc++] = T_INT; out_sig_bt[argc++] = T_ADDRESS; - Symbol* atype = ss.as_symbol(); - const char* at = atype->as_C_string(); - if (strlen(at) == 2) { - assert(at[0] == '[', "must be"); - switch (at[1]) { - case 'B': in_elem_bt[i] = T_BYTE; break; - case 'C': in_elem_bt[i] = T_CHAR; break; - case 'D': in_elem_bt[i] = T_DOUBLE; break; - case 'F': in_elem_bt[i] = T_FLOAT; break; - case 'I': in_elem_bt[i] = T_INT; break; - case 'J': in_elem_bt[i] = T_LONG; break; - case 'S': in_elem_bt[i] = T_SHORT; break; - case 'Z': in_elem_bt[i] = T_BOOLEAN; break; - default: ShouldNotReachHere(); - } - } + ss.skip_array_prefix(1); // skip one '[' + assert(ss.is_primitive(), "primitive type expected"); + in_elem_bt[i] = ss.type(); } else { out_sig_bt[argc++] = in_sig_bt[i]; in_elem_bt[i] = T_VOID; } if (in_sig_bt[i] != T_VOID) { - assert(in_sig_bt[i] == ss.type(), "must match"); + assert(in_sig_bt[i] == ss.type() || + in_sig_bt[i] == T_ARRAY, "must match"); ss.next(); } } diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp index 9a87d7796a6..eeba4269d90 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2002,28 +2002,16 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Arrays are passed as int, elem* pair out_sig_bt[argc++] = T_INT; out_sig_bt[argc++] = T_ADDRESS; - Symbol* atype = ss.as_symbol(); - const char* at = atype->as_C_string(); - if (strlen(at) == 2) { - assert(at[0] == '[', "must be"); - switch (at[1]) { - case 'B': in_elem_bt[i] = T_BYTE; break; - case 'C': in_elem_bt[i] = T_CHAR; break; - case 'D': in_elem_bt[i] = T_DOUBLE; break; - case 'F': in_elem_bt[i] = T_FLOAT; break; - case 'I': in_elem_bt[i] = T_INT; break; - case 'J': in_elem_bt[i] = T_LONG; break; - case 'S': in_elem_bt[i] = T_SHORT; break; - case 'Z': in_elem_bt[i] = T_BOOLEAN; break; - default: ShouldNotReachHere(); - } - } + ss.skip_array_prefix(1); // skip one '[' + assert(ss.is_primitive(), "primitive type expected"); + in_elem_bt[i] = ss.type(); } else { out_sig_bt[argc++] = in_sig_bt[i]; in_elem_bt[i] = T_VOID; } if (in_sig_bt[i] != T_VOID) { - assert(in_sig_bt[i] == ss.type(), "must match"); + assert(in_sig_bt[i] == ss.type() || + in_sig_bt[i] == T_ARRAY, "must match"); ss.next(); } } diff --git a/src/hotspot/share/c1/c1_ValueMap.cpp b/src/hotspot/share/c1/c1_ValueMap.cpp index 5c4685fc834..88ee5fe72b7 100644 --- a/src/hotspot/share/c1/c1_ValueMap.cpp +++ b/src/hotspot/share/c1/c1_ValueMap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -265,8 +265,8 @@ class ShortLoopOptimizer : public ValueNumberingVisitor { GlobalValueNumbering* _gvn; BlockList _loop_blocks; bool _too_complicated_loop; - bool _has_field_store[T_ARRAY + 1]; - bool _has_indexed_store[T_ARRAY + 1]; + bool _has_field_store[T_VOID]; + bool _has_indexed_store[T_VOID]; // simplified access to methods of GlobalValueNumbering ValueMap* current_map() { return _gvn->current_map(); } @@ -276,12 +276,12 @@ class ShortLoopOptimizer : public ValueNumberingVisitor { void kill_memory() { _too_complicated_loop = true; } void kill_field(ciField* field, bool all_offsets) { current_map()->kill_field(field, all_offsets); - assert(field->type()->basic_type() >= 0 && field->type()->basic_type() <= T_ARRAY, "Invalid type"); + assert(field->type()->basic_type() >= 0 && field->type()->basic_type() < T_VOID, "Invalid type"); _has_field_store[field->type()->basic_type()] = true; } void kill_array(ValueType* type) { current_map()->kill_array(type); - BasicType basic_type = as_BasicType(type); assert(basic_type >= 0 && basic_type <= T_ARRAY, "Invalid type"); + BasicType basic_type = as_BasicType(type); assert(basic_type >= 0 && basic_type < T_VOID, "Invalid type"); _has_indexed_store[basic_type] = true; } @@ -291,19 +291,19 @@ class ShortLoopOptimizer : public ValueNumberingVisitor { , _loop_blocks(ValueMapMaxLoopSize) , _too_complicated_loop(false) { - for (int i=0; i<= T_ARRAY; i++){ + for (int i = 0; i < T_VOID; i++) { _has_field_store[i] = false; _has_indexed_store[i] = false; } } bool has_field_store(BasicType type) { - assert(type >= 0 && type <= T_ARRAY, "Invalid type"); + assert(type >= 0 && type < T_VOID, "Invalid type"); return _has_field_store[type]; } bool has_indexed_store(BasicType type) { - assert(type >= 0 && type <= T_ARRAY, "Invalid type"); + assert(type >= 0 && type < T_VOID, "Invalid type"); return _has_indexed_store[type]; } diff --git a/src/hotspot/share/ci/ciEnv.cpp b/src/hotspot/share/ci/ciEnv.cpp index b0986152346..1f7284ea51c 100644 --- a/src/hotspot/share/ci/ciEnv.cpp +++ b/src/hotspot/share/ci/ciEnv.cpp @@ -413,12 +413,10 @@ ciKlass* ciEnv::get_klass_by_name_impl(ciKlass* accessing_klass, // Now we need to check the SystemDictionary Symbol* sym = name->get_symbol(); - if (sym->char_at(0) == JVM_SIGNATURE_CLASS && - sym->char_at(sym->utf8_length()-1) == JVM_SIGNATURE_ENDCLASS) { + if (Signature::has_envelope(sym)) { // This is a name from a signature. Strip off the trimmings. // Call recursive to keep scope of strippedsym. - TempNewSymbol strippedsym = SymbolTable::new_symbol(sym->as_utf8()+1, - sym->utf8_length()-2); + TempNewSymbol strippedsym = Signature::strip_envelope(sym); ciSymbol* strippedname = get_symbol(strippedsym); return get_klass_by_name_impl(accessing_klass, cpool, strippedname, require_local); } @@ -466,18 +464,17 @@ ciKlass* ciEnv::get_klass_by_name_impl(ciKlass* accessing_klass, // we must build an array type around it. The CI requires array klasses // to be loaded if their element klasses are loaded, except when memory // is exhausted. - if (sym->char_at(0) == JVM_SIGNATURE_ARRAY && + if (Signature::is_array(sym) && (sym->char_at(1) == JVM_SIGNATURE_ARRAY || sym->char_at(1) == JVM_SIGNATURE_CLASS)) { // We have an unloaded array. // Build it on the fly if the element class exists. - TempNewSymbol elem_sym = SymbolTable::new_symbol(sym->as_utf8()+1, - sym->utf8_length()-1); - + SignatureStream ss(sym, false); + ss.skip_array_prefix(1); // Get element ciKlass recursively. ciKlass* elem_klass = get_klass_by_name_impl(accessing_klass, cpool, - get_symbol(elem_sym), + get_symbol(ss.as_symbol()), require_local); if (elem_klass != NULL && elem_klass->is_loaded()) { // Now make an array for it @@ -609,7 +606,7 @@ ciConstant ciEnv::get_constant_by_index_impl(const constantPoolHandle& cpool, } BasicType bt = T_OBJECT; if (cpool->tag_at(index).is_dynamic_constant()) - bt = FieldType::basic_type(cpool->uncached_signature_ref_at(index)); + bt = Signature::basic_type(cpool->uncached_signature_ref_at(index)); if (is_reference_type(bt)) { } else { // we have to unbox the primitive value @@ -791,6 +788,8 @@ Method* ciEnv::lookup_method(ciInstanceKlass* accessor, ciMethod* ciEnv::get_method_by_index_impl(const constantPoolHandle& cpool, int index, Bytecodes::Code bc, ciInstanceKlass* accessor) { + assert(cpool.not_null(), "need constant pool"); + assert(accessor != NULL, "need origin of access"); if (bc == Bytecodes::_invokedynamic) { ConstantPoolCacheEntry* cpce = cpool->invokedynamic_cp_cache_entry_at(index); bool is_resolved = !cpce->is_f1_null(); diff --git a/src/hotspot/share/ci/ciField.cpp b/src/hotspot/share/ci/ciField.cpp index 41bbde92f7a..5c03b15f218 100644 --- a/src/hotspot/share/ci/ciField.cpp +++ b/src/hotspot/share/ci/ciField.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -86,7 +86,7 @@ ciField::ciField(ciInstanceKlass* klass, int index) : Symbol* signature = cpool->symbol_at(sig_index); _signature = ciEnv::current(THREAD)->get_symbol(signature); - BasicType field_type = FieldType::basic_type(signature); + BasicType field_type = Signature::basic_type(signature); // If the field is a pointer type, get the klass of the // field. diff --git a/src/hotspot/share/ci/ciKlass.hpp b/src/hotspot/share/ci/ciKlass.hpp index 2e329d2a32a..4d5eedab179 100644 --- a/src/hotspot/share/ci/ciKlass.hpp +++ b/src/hotspot/share/ci/ciKlass.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,6 +44,7 @@ class ciKlass : public ciType { friend class ciMethod; friend class ciMethodData; friend class ciObjArrayKlass; + friend class ciSignature; friend class ciReceiverTypeData; private: diff --git a/src/hotspot/share/ci/ciObjArrayKlass.cpp b/src/hotspot/share/ci/ciObjArrayKlass.cpp index 2ce543fcfc1..a460413a6ee 100644 --- a/src/hotspot/share/ci/ciObjArrayKlass.cpp +++ b/src/hotspot/share/ci/ciObjArrayKlass.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -108,37 +108,23 @@ ciSymbol* ciObjArrayKlass::construct_array_name(ciSymbol* element_name, int dimension) { EXCEPTION_CONTEXT; int element_len = element_name->utf8_length(); - + int buflen = dimension + element_len + 3; // '['+ + 'L'? + (element) + ';'? + '\0' + char* name = CURRENT_THREAD_ENV->name_buffer(buflen); + int pos = 0; + for ( ; pos < dimension; pos++) { + name[pos] = JVM_SIGNATURE_ARRAY; + } Symbol* base_name_sym = element_name->get_symbol(); - char* name; - - if (base_name_sym->char_at(0) == JVM_SIGNATURE_ARRAY || - (base_name_sym->char_at(0) == JVM_SIGNATURE_CLASS && // watch package name 'Lxx' - base_name_sym->char_at(element_len-1) == JVM_SIGNATURE_ENDCLASS)) { - - int new_len = element_len + dimension + 1; // for the ['s and '\0' - name = CURRENT_THREAD_ENV->name_buffer(new_len); - int pos = 0; - for ( ; pos < dimension; pos++) { - name[pos] = JVM_SIGNATURE_ARRAY; - } - strncpy(name+pos, (char*)element_name->base(), element_len); - name[new_len-1] = '\0'; + if (Signature::is_array(base_name_sym) || + Signature::has_envelope(base_name_sym)) { + strncpy(&name[pos], (char*)element_name->base(), element_len); + name[pos + element_len] = '\0'; } else { - int new_len = 3 // for L, ;, and '\0' - + dimension // for ['s - + element_len; - - name = CURRENT_THREAD_ENV->name_buffer(new_len); - int pos = 0; - for ( ; pos < dimension; pos++) { - name[pos] = JVM_SIGNATURE_ARRAY; - } name[pos++] = JVM_SIGNATURE_CLASS; - strncpy(name+pos, (char*)element_name->base(), element_len); - name[new_len-2] = JVM_SIGNATURE_ENDCLASS; - name[new_len-1] = '\0'; + strncpy(&name[pos], (char*)element_name->base(), element_len); + name[pos + element_len] = JVM_SIGNATURE_ENDCLASS; + name[pos + element_len + 1] = '\0'; } return ciSymbol::make(name); } diff --git a/src/hotspot/share/ci/ciObjectFactory.cpp b/src/hotspot/share/ci/ciObjectFactory.cpp index 01ccbfe5e15..f74f5e627a0 100644 --- a/src/hotspot/share/ci/ciObjectFactory.cpp +++ b/src/hotspot/share/ci/ciObjectFactory.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,6 @@ #include "memory/allocation.inline.hpp" #include "memory/universe.hpp" #include "oops/oop.inline.hpp" -#include "runtime/fieldType.hpp" #include "runtime/handles.inline.hpp" #include "utilities/macros.hpp" @@ -418,6 +417,7 @@ ciMethod* ciObjectFactory::get_unloaded_method(ciInstanceKlass* holder, ciSymbol* name, ciSymbol* signature, ciInstanceKlass* accessor) { + assert(accessor != NULL, "need origin of access"); ciSignature* that = NULL; for (int i = 0; i < _unloaded_methods->length(); i++) { ciMethod* entry = _unloaded_methods->at(i); @@ -488,20 +488,14 @@ ciKlass* ciObjectFactory::get_unloaded_klass(ciKlass* accessing_klass, // unloaded InstanceKlass. Deal with both. if (name->char_at(0) == JVM_SIGNATURE_ARRAY) { // Decompose the name.' - FieldArrayInfo fd; - BasicType element_type = FieldType::get_array_info(name->get_symbol(), - fd, THREAD); - if (HAS_PENDING_EXCEPTION) { - CLEAR_PENDING_EXCEPTION; - CURRENT_THREAD_ENV->record_out_of_memory_failure(); - return ciEnv::_unloaded_ciobjarrayklass; - } - int dimension = fd.dimension(); + SignatureStream ss(name->get_symbol(), false); + int dimension = ss.skip_array_prefix(); // skip all '['s + BasicType element_type = ss.type(); assert(element_type != T_ARRAY, "unsuccessful decomposition"); ciKlass* element_klass = NULL; if (element_type == T_OBJECT) { ciEnv *env = CURRENT_THREAD_ENV; - ciSymbol* ci_name = env->get_symbol(fd.object_key()); + ciSymbol* ci_name = env->get_symbol(ss.as_symbol()); element_klass = env->get_klass_by_name(accessing_klass, ci_name, false)->as_instance_klass(); } else { diff --git a/src/hotspot/share/ci/ciSignature.cpp b/src/hotspot/share/ci/ciSignature.cpp index aa12e7aab38..4b69ab9330d 100644 --- a/src/hotspot/share/ci/ciSignature.cpp +++ b/src/hotspot/share/ci/ciSignature.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,7 @@ ciSignature::ciSignature(ciKlass* accessing_klass, const constantPoolHandle& cpool, ciSymbol* symbol) { ASSERT_IN_VM; EXCEPTION_CONTEXT; + assert(accessing_klass != NULL, "need origin of access"); _accessing_klass = accessing_klass; _symbol = symbol; @@ -55,11 +56,10 @@ ciSignature::ciSignature(ciKlass* accessing_klass, const constantPoolHandle& cpo for (; ; ss.next()) { // Process one element of the signature ciType* type; - if (!ss.is_object()) { + if (!ss.is_reference()) { type = ciType::make(ss.type()); } else { - Symbol* name = ss.as_symbol(); - ciSymbol* klass_name = env->get_symbol(name); + ciSymbol* klass_name = env->get_symbol(ss.as_symbol()); type = env->get_klass_by_name_impl(_accessing_klass, cpool, klass_name, false); } _types->append(type); diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index 20d97ae5fae..8c168f344cb 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -665,7 +665,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, "Illegal zero length constant pool entry at %d in class %s", name_index, CHECK); - if (sig->char_at(0) == JVM_SIGNATURE_FUNC) { + if (Signature::is_method(sig)) { // Format check method name and signature verify_legal_method_name(name, CHECK); verify_legal_method_signature(name, sig, CHECK); @@ -690,9 +690,8 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, const Symbol* const signature = cp->symbol_at(signature_ref_index); if (_need_verify) { // CONSTANT_Dynamic's name and signature are verified above, when iterating NameAndType_info. - // Need only to be sure signature is non-zero length and the right type. - if (signature->utf8_length() == 0 || - signature->char_at(0) == JVM_SIGNATURE_FUNC) { + // Need only to be sure signature is the right type. + if (Signature::is_method(signature)) { throwIllegalSignature("CONSTANT_Dynamic", name, signature, CHECK); } } @@ -716,8 +715,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, if (_need_verify) { // Field name and signature are verified above, when iterating NameAndType_info. // Need only to be sure signature is non-zero length and the right type. - if (signature->utf8_length() == 0 || - signature->char_at(0) == JVM_SIGNATURE_FUNC) { + if (Signature::is_method(signature)) { throwIllegalSignature("Field", name, signature, CHECK); } } @@ -725,8 +723,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, if (_need_verify) { // Method name and signature are verified above, when iterating NameAndType_info. // Need only to be sure signature is non-zero length and the right type. - if (signature->utf8_length() == 0 || - signature->char_at(0) != JVM_SIGNATURE_FUNC) { + if (!Signature::is_method(signature)) { throwIllegalSignature("Method", name, signature, CHECK); } } @@ -1723,7 +1720,7 @@ void ClassFileParser::parse_fields(const ClassFileStream* const cfs, injected[n].signature_index, 0); - const BasicType type = FieldType::basic_type(injected[n].signature()); + const BasicType type = Signature::basic_type(injected[n].signature()); // Remember how many oops we encountered and compute allocation type const FieldAllocationType atype = fac->update(false, type); @@ -2796,21 +2793,8 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs, m->set_constants(_cp); m->set_name_index(name_index); m->set_signature_index(signature_index); - - ResultTypeFinder rtf(cp->symbol_at(signature_index)); - m->constMethod()->set_result_type(rtf.type()); - - if (args_size >= 0) { - m->set_size_of_parameters(args_size); - } else { - m->compute_size_of_parameters(THREAD); - } -#ifdef ASSERT - if (args_size >= 0) { - m->compute_size_of_parameters(THREAD); - assert(args_size == m->size_of_parameters(), ""); - } -#endif + m->compute_from_signature(cp->symbol_at(signature_index)); + assert(args_size < 0 || args_size == m->size_of_parameters(), ""); // Fill in code attribute information m->set_max_stack(max_stack); diff --git a/src/hotspot/share/classfile/classListParser.cpp b/src/hotspot/share/classfile/classListParser.cpp index 2f05b9d2cfd..b4f83e3ec47 100644 --- a/src/hotspot/share/classfile/classListParser.cpp +++ b/src/hotspot/share/classfile/classListParser.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,6 @@ #include "logging/logTag.hpp" #include "memory/metaspaceShared.hpp" #include "memory/resourceArea.hpp" -#include "runtime/fieldType.hpp" #include "runtime/handles.inline.hpp" #include "runtime/javaCalls.hpp" #include "utilities/defaultStream.hpp" @@ -338,7 +337,7 @@ Klass* ClassListParser::load_current_class(TRAPS) { error("If source location is not specified, interface(s) must not be specified"); } - bool non_array = !FieldType::is_array(class_name_symbol); + bool non_array = !Signature::is_array(class_name_symbol); JavaValue result(T_OBJECT); if (non_array) { diff --git a/src/hotspot/share/classfile/defaultMethods.cpp b/src/hotspot/share/classfile/defaultMethods.cpp index 1c465ecdc59..6fb83924a2a 100644 --- a/src/hotspot/share/classfile/defaultMethods.cpp +++ b/src/hotspot/share/classfile/defaultMethods.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -901,8 +901,7 @@ static Method* new_method( m->set_constants(NULL); // This will get filled in later m->set_name_index(cp->utf8(name)); m->set_signature_index(cp->utf8(sig)); - ResultTypeFinder rtf(sig); - m->constMethod()->set_result_type(rtf.type()); + m->compute_from_signature(sig); m->set_size_of_parameters(params); m->set_max_stack(max_stack); m->set_max_locals(params); diff --git a/src/hotspot/share/classfile/placeholders.cpp b/src/hotspot/share/classfile/placeholders.cpp index 5dc6c74ed53..ef290503862 100644 --- a/src/hotspot/share/classfile/placeholders.cpp +++ b/src/hotspot/share/classfile/placeholders.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,6 @@ #include "classfile/placeholders.hpp" #include "classfile/systemDictionary.hpp" #include "oops/oop.inline.hpp" -#include "runtime/fieldType.hpp" #include "utilities/hashtable.inline.hpp" // Placeholder methods diff --git a/src/hotspot/share/classfile/stackMapTable.cpp b/src/hotspot/share/classfile/stackMapTable.cpp index 95e79c169f5..59f1b077cdb 100644 --- a/src/hotspot/share/classfile/stackMapTable.cpp +++ b/src/hotspot/share/classfile/stackMapTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ #include "memory/resourceArea.hpp" #include "oops/constantPool.hpp" #include "oops/oop.inline.hpp" -#include "runtime/fieldType.hpp" #include "runtime/handles.inline.hpp" StackMapTable::StackMapTable(StackMapReader* reader, StackMapFrame* init_frame, diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index af0f2bd0d2e..decaabe2d56 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -74,7 +74,6 @@ #include "prims/methodHandles.hpp" #include "runtime/arguments.hpp" #include "runtime/biasedLocking.hpp" -#include "runtime/fieldType.hpp" #include "runtime/handles.inline.hpp" #include "runtime/java.hpp" #include "runtime/javaCalls.hpp" @@ -240,7 +239,7 @@ Klass* SystemDictionary::resolve_or_fail(Symbol* class_name, // Forwards to resolve_array_class_or_null or resolve_instance_class_or_null Klass* SystemDictionary::resolve_or_null(Symbol* class_name, Handle class_loader, Handle protection_domain, TRAPS) { - if (FieldType::is_array(class_name)) { + if (Signature::is_array(class_name)) { return resolve_array_class_or_null(class_name, class_loader, protection_domain, THREAD); } else { return resolve_instance_class_or_null_helper(class_name, class_loader, protection_domain, THREAD); @@ -252,8 +251,8 @@ InstanceKlass* SystemDictionary::resolve_instance_class_or_null_helper(Symbol* c Handle class_loader, Handle protection_domain, TRAPS) { - assert(class_name != NULL && !FieldType::is_array(class_name), "must be"); - if (FieldType::is_obj(class_name)) { + assert(class_name != NULL && !Signature::is_array(class_name), "must be"); + if (Signature::has_envelope(class_name)) { ResourceMark rm(THREAD); // Ignore wrapping L and ;. TempNewSymbol name = SymbolTable::new_symbol(class_name->as_C_string() + 1, @@ -274,24 +273,24 @@ Klass* SystemDictionary::resolve_array_class_or_null(Symbol* class_name, Handle class_loader, Handle protection_domain, TRAPS) { - assert(FieldType::is_array(class_name), "must be array"); + assert(Signature::is_array(class_name), "must be array"); + ResourceMark rm(THREAD); + SignatureStream ss(class_name, false); + int ndims = ss.skip_array_prefix(); // skip all '['s Klass* k = NULL; - FieldArrayInfo fd; - // dimension and object_key in FieldArrayInfo are assigned as a side-effect - // of this call - BasicType t = FieldType::get_array_info(class_name, fd, CHECK_NULL); - if (t == T_OBJECT) { - // naked oop "k" is OK here -- we assign back into it - k = SystemDictionary::resolve_instance_class_or_null(fd.object_key(), + BasicType t = ss.type(); + if (ss.has_envelope()) { + Symbol* obj_class = ss.as_symbol(); + k = SystemDictionary::resolve_instance_class_or_null(obj_class, class_loader, protection_domain, CHECK_NULL); if (k != NULL) { - k = k->array_klass(fd.dimension(), CHECK_NULL); + k = k->array_klass(ndims, CHECK_NULL); } } else { k = Universe::typeArrayKlassObj(t); - k = TypeArrayKlass::cast(k)->array_klass(fd.dimension(), CHECK_NULL); + k = TypeArrayKlass::cast(k)->array_klass(ndims, CHECK_NULL); } return k; } @@ -342,7 +341,7 @@ InstanceKlass* SystemDictionary::resolve_super_or_fail(Symbol* child_name, Handle protection_domain, bool is_superclass, TRAPS) { - assert(!FieldType::is_array(super_name), "invalid super class name"); + assert(!Signature::is_array(super_name), "invalid super class name"); #if INCLUDE_CDS if (DumpSharedSpaces) { // Special processing for handling UNREGISTERED shared classes. @@ -654,8 +653,8 @@ InstanceKlass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, Handle class_loader, Handle protection_domain, TRAPS) { - assert(name != NULL && !FieldType::is_array(name) && - !FieldType::is_obj(name), "invalid class name"); + assert(name != NULL && !Signature::is_array(name) && + !Signature::has_envelope(name), "invalid class name"); EventClassLoad class_load_start_event; @@ -960,19 +959,21 @@ Klass* SystemDictionary::find_instance_or_array_klass(Symbol* class_name, Klass* k = NULL; assert(class_name != NULL, "class name must be non NULL"); - if (FieldType::is_array(class_name)) { + if (Signature::is_array(class_name)) { // The name refers to an array. Parse the name. // dimension and object_key in FieldArrayInfo are assigned as a // side-effect of this call - FieldArrayInfo fd; - BasicType t = FieldType::get_array_info(class_name, fd, CHECK_(NULL)); + SignatureStream ss(class_name, false); + int ndims = ss.skip_array_prefix(); // skip all '['s + BasicType t = ss.type(); if (t != T_OBJECT) { k = Universe::typeArrayKlassObj(t); } else { - k = SystemDictionary::find(fd.object_key(), class_loader, protection_domain, THREAD); + Symbol* obj_class = ss.as_symbol(); + k = SystemDictionary::find(obj_class, class_loader, protection_domain, THREAD); } if (k != NULL) { - k = k->array_klass_or_null(fd.dimension()); + k = k->array_klass_or_null(ndims); } } else { k = find(class_name, class_loader, protection_domain, THREAD); @@ -2167,20 +2168,21 @@ Klass* SystemDictionary::find_constrained_instance_or_array_klass( // Now look to see if it has been loaded elsewhere, and is subject to // a loader constraint that would require this loader to return the // klass that is already loaded. - if (FieldType::is_array(class_name)) { + if (Signature::is_array(class_name)) { // For array classes, their Klass*s are not kept in the // constraint table. The element Klass*s are. - FieldArrayInfo fd; - BasicType t = FieldType::get_array_info(class_name, fd, CHECK_(NULL)); + SignatureStream ss(class_name, false); + int ndims = ss.skip_array_prefix(); // skip all '['s + BasicType t = ss.type(); if (t != T_OBJECT) { klass = Universe::typeArrayKlassObj(t); } else { MutexLocker mu(THREAD, SystemDictionary_lock); - klass = constraints()->find_constrained_klass(fd.object_key(), class_loader); + klass = constraints()->find_constrained_klass(ss.as_symbol(), class_loader); } // If element class already loaded, allocate array klass if (klass != NULL) { - klass = klass->array_klass_or_null(fd.dimension()); + klass = klass->array_klass_or_null(ndims); } } else { MutexLocker mu(THREAD, SystemDictionary_lock); @@ -2200,21 +2202,22 @@ bool SystemDictionary::add_loader_constraint(Symbol* class_name, ClassLoaderData* loader_data2 = class_loader_data(class_loader2); Symbol* constraint_name = NULL; - // Needs to be in same scope as constraint_name in case a Symbol is created and - // assigned to constraint_name. - FieldArrayInfo fd; - if (!FieldType::is_array(class_name)) { + + if (!Signature::is_array(class_name)) { constraint_name = class_name; } else { // For array classes, their Klass*s are not kept in the // constraint table. The element classes are. - BasicType t = FieldType::get_array_info(class_name, fd, CHECK_(false)); - // primitive types always pass - if (t != T_OBJECT) { - return true; - } else { - constraint_name = fd.object_key(); + SignatureStream ss(class_name, false); + ss.skip_array_prefix(); // skip all '['s + if (!ss.has_envelope()) { + return true; // primitive types always pass } + constraint_name = ss.as_symbol(); + // Increment refcount to keep constraint_name alive after + // SignatureStream is destructed. It will be decremented below + // before returning. + constraint_name->increment_refcount(); } Dictionary* dictionary1 = loader_data1->dictionary(); @@ -2227,8 +2230,12 @@ bool SystemDictionary::add_loader_constraint(Symbol* class_name, MutexLocker mu_s(THREAD, SystemDictionary_lock); InstanceKlass* klass1 = find_class(d_hash1, constraint_name, dictionary1); InstanceKlass* klass2 = find_class(d_hash2, constraint_name, dictionary2); - return constraints()->add_entry(constraint_name, klass1, class_loader1, - klass2, class_loader2); + bool result = constraints()->add_entry(constraint_name, klass1, class_loader1, + klass2, class_loader2); + if (Signature::is_array(class_name)) { + constraint_name->decrement_refcount(); + } + return result; } } @@ -2325,15 +2332,16 @@ Symbol* SystemDictionary::check_signature_loaders(Symbol* signature, return NULL; } - SignatureStream sig_strm(signature, is_method); - while (!sig_strm.is_done()) { - if (sig_strm.is_object()) { - Symbol* sig = sig_strm.as_symbol(); + for (SignatureStream ss(signature, is_method); !ss.is_done(); ss.next()) { + if (ss.is_reference()) { + Symbol* sig = ss.as_symbol(); + // Note: In the future, if template-like types can take + // arguments, we will want to recognize them and dig out class + // names hiding inside the argument lists. if (!add_loader_constraint(sig, loader1, loader2, THREAD)) { return sig; } } - sig_strm.next(); } return NULL; } @@ -2419,9 +2427,9 @@ static Method* unpack_method_and_appendix(Handle mname, Method* SystemDictionary::find_method_handle_invoker(Klass* klass, Symbol* name, Symbol* signature, - Klass* accessing_klass, - Handle *appendix_result, - TRAPS) { + Klass* accessing_klass, + Handle *appendix_result, + TRAPS) { assert(THREAD->can_call_java() ,""); Handle method_type = SystemDictionary::find_method_handle_type(signature, accessing_klass, CHECK_NULL); @@ -2474,14 +2482,6 @@ static bool is_always_visible_class(oop mirror) { InstanceKlass::cast(klass)->is_same_class_package(SystemDictionary::MethodHandle_klass())); // java.lang.invoke } - -// Return the Java mirror (java.lang.Class instance) for a single-character -// descriptor. This result, when available, is the same as produced by the -// heavier API point of the same name that takes a Symbol. -oop SystemDictionary::find_java_mirror_for_type(char signature_char) { - return java_lang_Class::primitive_mirror(char2type(signature_char)); -} - // Find or construct the Java mirror (java.lang.Class instance) for a // for the given field type signature, as interpreted relative to the // given class loader. Handles primitives, void, references, arrays, @@ -2498,19 +2498,17 @@ Handle SystemDictionary::find_java_mirror_for_type(Symbol* signature, assert(accessing_klass == NULL || (class_loader.is_null() && protection_domain.is_null()), "one or the other, or perhaps neither"); - Symbol* type = signature; + SignatureStream ss(signature, false); // What we have here must be a valid field descriptor, // and all valid field descriptors are supported. // Produce the same java.lang.Class that reflection reports. - if (type->utf8_length() == 1) { + if (ss.is_primitive() || (ss.type() == T_VOID)) { // It's a primitive. (Void has a primitive mirror too.) - char ch = type->char_at(0); - assert(is_java_primitive(char2type(ch)) || ch == JVM_SIGNATURE_VOID, ""); - return Handle(THREAD, find_java_mirror_for_type(ch)); + return Handle(THREAD, java_lang_Class::primitive_mirror(ss.type())); - } else if (FieldType::is_obj(type) || FieldType::is_array(type)) { + } else if (ss.is_reference()) { // It's a reference type. if (accessing_klass != NULL) { @@ -2519,11 +2517,11 @@ Handle SystemDictionary::find_java_mirror_for_type(Symbol* signature, } Klass* constant_type_klass; if (failure_mode == SignatureStream::ReturnNull) { - constant_type_klass = resolve_or_null(type, class_loader, protection_domain, + constant_type_klass = resolve_or_null(signature, class_loader, protection_domain, CHECK_(empty)); } else { bool throw_error = (failure_mode == SignatureStream::NCDFError); - constant_type_klass = resolve_or_fail(type, class_loader, protection_domain, + constant_type_klass = resolve_or_fail(signature, class_loader, protection_domain, throw_error, CHECK_(empty)); } if (constant_type_klass == NULL) { @@ -2586,7 +2584,7 @@ Handle SystemDictionary::find_method_handle_type(Symbol* signature, // Use neutral class loader to lookup candidate classes to be placed in the cache. mirror = ss.as_java_mirror(Handle(), Handle(), SignatureStream::ReturnNull, CHECK_(empty)); - if (mirror == NULL || (ss.is_object() && !is_always_visible_class(mirror))) { + if (mirror == NULL || (ss.is_reference() && !is_always_visible_class(mirror))) { // Fall back to accessing_klass context. can_be_cached = false; } diff --git a/src/hotspot/share/classfile/systemDictionary.hpp b/src/hotspot/share/classfile/systemDictionary.hpp index 936a12dc5ee..838c1089bc3 100644 --- a/src/hotspot/share/classfile/systemDictionary.hpp +++ b/src/hotspot/share/classfile/systemDictionary.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -497,10 +497,6 @@ class SystemDictionary : AllStatic { failure_mode, THREAD); } - - // fast short-cut for the one-character case: - static oop find_java_mirror_for_type(char signature_char); - // find a java.lang.invoke.MethodType object for a given signature // (asks Java to compute it if necessary, except in a compiler thread) static Handle find_method_handle_type(Symbol* signature, diff --git a/src/hotspot/share/classfile/verificationType.cpp b/src/hotspot/share/classfile/verificationType.cpp index 623495c3a1c..34027a7c252 100644 --- a/src/hotspot/share/classfile/verificationType.cpp +++ b/src/hotspot/share/classfile/verificationType.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -120,27 +120,29 @@ bool VerificationType::is_reference_assignable_from( VerificationType VerificationType::get_component(ClassVerifier *context, TRAPS) const { assert(is_array() && name()->utf8_length() >= 2, "Must be a valid array"); - Symbol* component; - switch (name()->char_at(1)) { - case JVM_SIGNATURE_BOOLEAN: return VerificationType(Boolean); - case JVM_SIGNATURE_BYTE: return VerificationType(Byte); - case JVM_SIGNATURE_CHAR: return VerificationType(Char); - case JVM_SIGNATURE_SHORT: return VerificationType(Short); - case JVM_SIGNATURE_INT: return VerificationType(Integer); - case JVM_SIGNATURE_LONG: return VerificationType(Long); - case JVM_SIGNATURE_FLOAT: return VerificationType(Float); - case JVM_SIGNATURE_DOUBLE: return VerificationType(Double); - case JVM_SIGNATURE_ARRAY: - component = context->create_temporary_symbol( - name(), 1, name()->utf8_length()); - return VerificationType::reference_type(component); - case JVM_SIGNATURE_CLASS: - component = context->create_temporary_symbol( - name(), 2, name()->utf8_length() - 1); - return VerificationType::reference_type(component); - default: - // Met an invalid type signature, e.g. [X - return VerificationType::bogus_type(); + SignatureStream ss(name(), false); + ss.skip_array_prefix(1); + switch (ss.type()) { + case T_BOOLEAN: return VerificationType(Boolean); + case T_BYTE: return VerificationType(Byte); + case T_CHAR: return VerificationType(Char); + case T_SHORT: return VerificationType(Short); + case T_INT: return VerificationType(Integer); + case T_LONG: return VerificationType(Long); + case T_FLOAT: return VerificationType(Float); + case T_DOUBLE: return VerificationType(Double); + case T_ARRAY: + case T_OBJECT: { + guarantee(ss.is_reference(), "unchecked verifier input?"); + Symbol* component = ss.as_symbol(); + // Create another symbol to save as signature stream unreferences this symbol. + Symbol* component_copy = context->create_temporary_symbol(component); + assert(component_copy == component, "symbols don't match"); + return VerificationType::reference_type(component_copy); + } + default: + // Met an invalid type signature, e.g. [X + return VerificationType::bogus_type(); } } diff --git a/src/hotspot/share/classfile/vmSymbols.cpp b/src/hotspot/share/classfile/vmSymbols.cpp index d15c9b9c6f0..51cf1279505 100644 --- a/src/hotspot/share/classfile/vmSymbols.cpp +++ b/src/hotspot/share/classfile/vmSymbols.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -99,13 +99,13 @@ void vmSymbols::initialize(TRAPS) { _type_signatures[T_SHORT] = short_signature(); _type_signatures[T_BOOLEAN] = bool_signature(); _type_signatures[T_VOID] = void_signature(); - // no single signatures for T_OBJECT or T_ARRAY #ifdef ASSERT for (int i = (int)T_BOOLEAN; i < (int)T_VOID+1; i++) { Symbol* s = _type_signatures[i]; if (s == NULL) continue; - BasicType st = signature_type(s); - assert(st == i, ""); + SignatureStream ss(s, false); + assert(ss.type() == i, "matching signature"); + assert(!ss.is_reference(), "no single-char signature for T_OBJECT, etc."); } #endif } @@ -209,20 +209,6 @@ void vmSymbols::serialize(SerializeClosure* soc) { soc->do_region((u_char*)_type_signatures, sizeof(_type_signatures)); } - -BasicType vmSymbols::signature_type(const Symbol* s) { - assert(s != NULL, "checking"); - if (s->utf8_length() == 1) { - BasicType result = char2type(s->char_at(0)); - if (is_java_primitive(result) || result == T_VOID) { - assert(s == _type_signatures[result], ""); - return result; - } - } - return T_OBJECT; -} - - static int mid_hint = (int)vmSymbols::FIRST_SID+1; #ifndef PRODUCT diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index b0c193f980c..c7318f0a747 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1566,8 +1566,6 @@ class vmSymbols: AllStatic { assert(_type_signatures[t] != NULL, "domain check"); return _type_signatures[t]; } - // inverse of type_signature; returns T_OBJECT if s is not recognized - static BasicType signature_type(const Symbol* s); static Symbol* symbol_at(SID id) { assert(id >= FIRST_SID && id < SID_LIMIT, "oob"); diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 5358d7a02fa..69349430b9d 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -3151,12 +3151,10 @@ void nmethod::print_nmethod_labels(outputStream* stream, address block_begin, bo m->method_holder()->print_value_on(stream); } else { bool did_name = false; - if (!at_this && ss.is_object()) { - Symbol* name = ss.as_symbol_or_null(); - if (name != NULL) { - name->print_value_on(stream); - did_name = true; - } + if (!at_this && ss.is_reference()) { + Symbol* name = ss.as_symbol(); + name->print_value_on(stream); + did_name = true; } if (!did_name) stream->print("%s", type2name(t)); diff --git a/src/hotspot/share/compiler/methodMatcher.cpp b/src/hotspot/share/compiler/methodMatcher.cpp index fd3bfeb1dd0..b72806c4f81 100644 --- a/src/hotspot/share/compiler/methodMatcher.cpp +++ b/src/hotspot/share/compiler/methodMatcher.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -271,7 +271,8 @@ void MethodMatcher::parse_method_pattern(char*& line, const char*& error_msg, Me } if ((strchr(method_name, JVM_SIGNATURE_SPECIAL) != NULL) || (strchr(method_name, JVM_SIGNATURE_ENDSPECIAL) != NULL)) { - if ((strncmp("", method_name, 255) != 0) && (strncmp("", method_name, 255) != 0)) { + if (!vmSymbols::object_initializer_name()->equals(method_name) && + !vmSymbols::class_initializer_name()->equals(method_name)) { error_msg = "Chars '<' and '>' only allowed in and "; return; } diff --git a/src/hotspot/share/interpreter/bytecode.cpp b/src/hotspot/share/interpreter/bytecode.cpp index cc9b112092f..c10056d5d4e 100644 --- a/src/hotspot/share/interpreter/bytecode.cpp +++ b/src/hotspot/share/interpreter/bytecode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ #include "oops/constantPool.hpp" #include "oops/cpCache.inline.hpp" #include "oops/oop.inline.hpp" -#include "runtime/fieldType.hpp" #include "runtime/handles.inline.hpp" #include "runtime/safepoint.hpp" #include "runtime/signature.hpp" diff --git a/src/hotspot/share/interpreter/bytecodeUtils.cpp b/src/hotspot/share/interpreter/bytecodeUtils.cpp index 1f5711f810f..b263c05049d 100644 --- a/src/hotspot/share/interpreter/bytecodeUtils.cpp +++ b/src/hotspot/share/interpreter/bytecodeUtils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2019 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -975,7 +975,7 @@ int ExceptionMessageBuilder::do_instruction(int bci) { // Simulate the bytecode: pop the address, push the 'value' loaded // from the field. stack->pop(1 - Bytecodes::depth(code)); - stack->push(bci, char2type((char) signature->char_at(0))); + stack->push(bci, Signature::basic_type(signature)); break; } @@ -986,8 +986,8 @@ int ExceptionMessageBuilder::do_instruction(int bci) { int name_and_type_index = cp->name_and_type_ref_index_at(cp_index); int type_index = cp->signature_ref_index_at(name_and_type_index); Symbol* signature = cp->symbol_at(type_index); - ResultTypeFinder result_type(signature); - stack->pop(type2size[char2type((char) signature->char_at(0))] - Bytecodes::depth(code) - 1); + BasicType bt = Signature::basic_type(signature); + stack->pop(type2size[bt] - Bytecodes::depth(code) - 1); break; } @@ -1137,7 +1137,8 @@ int ExceptionMessageBuilder::get_NPE_null_slot(int bci) { int name_and_type_index = cp->name_and_type_ref_index_at(cp_index); int type_index = cp->signature_ref_index_at(name_and_type_index); Symbol* signature = cp->symbol_at(type_index); - return type2size[char2type((char) signature->char_at(0))]; + BasicType bt = Signature::basic_type(signature); + return type2size[bt]; } case Bytecodes::_invokevirtual: case Bytecodes::_invokespecial: diff --git a/src/hotspot/share/interpreter/interpreterRuntime.cpp b/src/hotspot/share/interpreter/interpreterRuntime.cpp index 5e7b97ec165..3862cfeea57 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.cpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1369,7 +1369,7 @@ void SignatureHandlerLibrary::add(const methodHandle& method) { // use slow signature handler if we can't do better int handler_index = -1; // check if we can use customized (fast) signature handler - if (UseFastSignatureHandlers && method->size_of_parameters() <= Fingerprinter::max_size_of_parameters) { + if (UseFastSignatureHandlers && method->size_of_parameters() <= Fingerprinter::fp_max_size_of_parameters) { // use customized signature handler MutexLocker mu(SignatureHandlerLibrary_lock); // make sure data structure is initialized diff --git a/src/hotspot/share/interpreter/oopMapCache.cpp b/src/hotspot/share/interpreter/oopMapCache.cpp index 652a336f201..87c39279fc8 100644 --- a/src/hotspot/share/interpreter/oopMapCache.cpp +++ b/src/hotspot/share/interpreter/oopMapCache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -257,7 +257,7 @@ class MaskFillerForNative: public NativeSignatureIterator { } void generate() { - NativeSignatureIterator::iterate(); + iterate(); } }; diff --git a/src/hotspot/share/interpreter/rewriter.cpp b/src/hotspot/share/interpreter/rewriter.cpp index d66620f0ff0..a80b8c6f7ab 100644 --- a/src/hotspot/share/interpreter/rewriter.cpp +++ b/src/hotspot/share/interpreter/rewriter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -330,7 +330,7 @@ void Rewriter::maybe_rewrite_ldc(address bcp, int offset, bool is_wide, tag.is_string() || (tag.is_dynamic_constant() && // keep regular ldc interpreter logic for condy primitives - is_reference_type(FieldType::basic_type(_pool->uncached_signature_ref_at(cp_index)))) + is_reference_type(Signature::basic_type(_pool->uncached_signature_ref_at(cp_index)))) ) { int ref_index = cp_entry_to_resolved_references(cp_index); if (is_wide) { diff --git a/src/hotspot/share/jvmci/compilerRuntime.cpp b/src/hotspot/share/jvmci/compilerRuntime.cpp index 62afff6cd33..d90f1e705f2 100644 --- a/src/hotspot/share/jvmci/compilerRuntime.cpp +++ b/src/hotspot/share/jvmci/compilerRuntime.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -72,13 +72,11 @@ Klass* CompilerRuntime::resolve_klass_helper(JavaThread *thread, const char* nam Handle loader(THREAD, caller->method_holder()->class_loader()); Handle protection_domain(THREAD, caller->method_holder()->protection_domain()); - // Ignore wrapping L and ; - if (name[0] == JVM_SIGNATURE_CLASS) { - assert(len > 2, "small name %s", name); - name++; - len -= 2; - } TempNewSymbol sym = SymbolTable::new_symbol(name, len); + if (sym != NULL && Signature::has_envelope(sym)) { + // Ignore wrapping L and ; + sym = Signature::strip_envelope(sym); + } if (sym == NULL) { return NULL; } diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index 558ab408c70..22ff42ea65e 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -539,30 +539,25 @@ C2V_VMENTRY_NULL(jobject, lookupType, (JNIEnv* env, jobject, jstring jname, jcla JVMCI_THROW_MSG_NULL(ClassNotFoundException, str); } } else { - if (class_name->char_at(0) == JVM_SIGNATURE_CLASS && - class_name->char_at(class_name->utf8_length()-1) == JVM_SIGNATURE_ENDCLASS) { + if (Signature::has_envelope(class_name)) { // This is a name from a signature. Strip off the trimmings. // Call recursive to keep scope of strippedsym. - TempNewSymbol strippedsym = SymbolTable::new_symbol(class_name->as_utf8()+1, - class_name->utf8_length()-2); + TempNewSymbol strippedsym = Signature::strip_envelope(class_name); resolved_klass = SystemDictionary::find(strippedsym, class_loader, protection_domain, CHECK_0); - } else if (FieldType::is_array(class_name)) { - FieldArrayInfo fd; - // dimension and object_key in FieldArrayInfo are assigned as a side-effect - // of this call - BasicType t = FieldType::get_array_info(class_name, fd, CHECK_0); - if (t == T_OBJECT) { - TempNewSymbol strippedsym = SymbolTable::new_symbol(class_name->as_utf8()+1+fd.dimension(), - class_name->utf8_length()-2-fd.dimension()); + } else if (Signature::is_array(class_name)) { + SignatureStream ss(class_name, false); + int ndim = ss.skip_array_prefix(); + if (ss.type() == T_OBJECT) { + Symbol* strippedsym = ss.as_symbol(); resolved_klass = SystemDictionary::find(strippedsym, - class_loader, - protection_domain, - CHECK_0); + class_loader, + protection_domain, + CHECK_0); if (!resolved_klass.is_null()) { - resolved_klass = resolved_klass->array_klass(fd.dimension(), CHECK_0); + resolved_klass = resolved_klass->array_klass(ndim, CHECK_0); } } else { - resolved_klass = TypeArrayKlass::cast(Universe::typeArrayKlassObj(t))->array_klass(fd.dimension(), CHECK_0); + resolved_klass = TypeArrayKlass::cast(Universe::typeArrayKlassObj(ss.type()))->array_klass(ndim, CHECK_0); } } else { resolved_klass = SystemDictionary::find(class_name, class_loader, protection_domain, CHECK_0); @@ -1036,18 +1031,18 @@ C2V_VMENTRY_NULL(jobject, executeHotSpotNmethod, (JNIEnv* env, jobject, jobject JavaCallArguments jca(mh->size_of_parameters()); JavaArgumentUnboxer jap(signature, &jca, (arrayOop) JNIHandles::resolve(args), mh->is_static()); - JavaValue result(jap.get_ret_type()); + JavaValue result(jap.return_type()); jca.set_alternative_target(nm); JavaCalls::call(&result, mh, &jca, CHECK_NULL); - if (jap.get_ret_type() == T_VOID) { + if (jap.return_type() == T_VOID) { return NULL; - } else if (is_reference_type(jap.get_ret_type())) { + } else if (is_reference_type(jap.return_type())) { return JNIHandles::make_local((oop) result.get_jobject()); } else { jvalue *value = (jvalue *) result.get_value_addr(); // Narrow the value down if required (Important on big endian machines) - switch (jap.get_ret_type()) { + switch (jap.return_type()) { case T_BOOLEAN: value->z = (jboolean) value->i; break; @@ -1063,7 +1058,7 @@ C2V_VMENTRY_NULL(jobject, executeHotSpotNmethod, (JNIEnv* env, jobject, jobject default: break; } - JVMCIObject o = JVMCIENV->create_box(jap.get_ret_type(), value, JVMCI_CHECK_NULL); + JVMCIObject o = JVMCIENV->create_box(jap.return_type(), value, JVMCI_CHECK_NULL); return JVMCIENV->get_jobject(o); } C2V_END diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp index 6ddc6cd4854..761e94238e3 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -132,7 +132,12 @@ class JavaArgumentUnboxer : public SignatureIterator { Handle next_arg(BasicType expectedType); public: - JavaArgumentUnboxer(Symbol* signature, JavaCallArguments* jca, arrayOop args, bool is_static) : SignatureIterator(signature) { + JavaArgumentUnboxer(Symbol* signature, + JavaCallArguments* jca, + arrayOop args, + bool is_static) + : SignatureIterator(signature) + { this->_return_type = T_ILLEGAL; _jca = jca; _index = 0; @@ -140,24 +145,31 @@ class JavaArgumentUnboxer : public SignatureIterator { if (!is_static) { _jca->push_oop(next_arg(T_OBJECT)); } - iterate(); + do_parameters_on(this); assert(_index == args->length(), "arg count mismatch with signature"); } - inline void do_bool() { if (!is_return_type()) _jca->push_int(next_arg(T_BOOLEAN)->bool_field(java_lang_boxing_object::value_offset_in_bytes(T_BOOLEAN))); } - inline void do_char() { if (!is_return_type()) _jca->push_int(next_arg(T_CHAR)->char_field(java_lang_boxing_object::value_offset_in_bytes(T_CHAR))); } - inline void do_short() { if (!is_return_type()) _jca->push_int(next_arg(T_SHORT)->short_field(java_lang_boxing_object::value_offset_in_bytes(T_SHORT))); } - inline void do_byte() { if (!is_return_type()) _jca->push_int(next_arg(T_BYTE)->byte_field(java_lang_boxing_object::value_offset_in_bytes(T_BYTE))); } - inline void do_int() { if (!is_return_type()) _jca->push_int(next_arg(T_INT)->int_field(java_lang_boxing_object::value_offset_in_bytes(T_INT))); } - - inline void do_long() { if (!is_return_type()) _jca->push_long(next_arg(T_LONG)->long_field(java_lang_boxing_object::value_offset_in_bytes(T_LONG))); } - inline void do_float() { if (!is_return_type()) _jca->push_float(next_arg(T_FLOAT)->float_field(java_lang_boxing_object::value_offset_in_bytes(T_FLOAT))); } - inline void do_double() { if (!is_return_type()) _jca->push_double(next_arg(T_DOUBLE)->double_field(java_lang_boxing_object::value_offset_in_bytes(T_DOUBLE))); } - - inline void do_object() { _jca->push_oop(next_arg(T_OBJECT)); } - inline void do_object(int begin, int end) { if (!is_return_type()) _jca->push_oop(next_arg(T_OBJECT)); } - inline void do_array(int begin, int end) { if (!is_return_type()) _jca->push_oop(next_arg(T_OBJECT)); } - inline void do_void() { } + private: + friend class SignatureIterator; // so do_parameters_on can call do_type + void do_type(BasicType type) { + if (is_reference_type(type)) { + _jca->push_oop(next_arg(T_OBJECT)); + return; + } + Handle arg = next_arg(type); + int box_offset = java_lang_boxing_object::value_offset_in_bytes(type); + switch (type) { + case T_BOOLEAN: _jca->push_int(arg->bool_field(box_offset)); break; + case T_CHAR: _jca->push_int(arg->char_field(box_offset)); break; + case T_SHORT: _jca->push_int(arg->short_field(box_offset)); break; + case T_BYTE: _jca->push_int(arg->byte_field(box_offset)); break; + case T_INT: _jca->push_int(arg->int_field(box_offset)); break; + case T_LONG: _jca->push_long(arg->long_field(box_offset)); break; + case T_FLOAT: _jca->push_float(arg->float_field(box_offset)); break; + case T_DOUBLE: _jca->push_double(arg->double_field(box_offset)); break; + default: ShouldNotReachHere(); + } + } }; class JNIHandleMark : public StackObj { diff --git a/src/hotspot/share/oops/constMethod.cpp b/src/hotspot/share/oops/constMethod.cpp index 69f037823bf..fad701edef6 100644 --- a/src/hotspot/share/oops/constMethod.cpp +++ b/src/hotspot/share/oops/constMethod.cpp @@ -67,7 +67,7 @@ ConstMethod::ConstMethod(int byte_code_size, set_max_locals(0); set_method_idnum(0); set_size_of_parameters(0); - set_result_type(T_VOID); + set_result_type((BasicType)0); } // Accessor that copies to metadata. diff --git a/src/hotspot/share/oops/constantPool.cpp b/src/hotspot/share/oops/constantPool.cpp index ddd4e62433a..89a0f8e5523 100644 --- a/src/hotspot/share/oops/constantPool.cpp +++ b/src/hotspot/share/oops/constantPool.cpp @@ -49,7 +49,6 @@ #include "oops/oop.inline.hpp" #include "oops/typeArrayOop.inline.hpp" #include "runtime/atomic.hpp" -#include "runtime/fieldType.hpp" #include "runtime/handles.inline.hpp" #include "runtime/init.hpp" #include "runtime/javaCalls.hpp" @@ -728,7 +727,7 @@ char* ConstantPool::string_at_noresolve(int which) { } BasicType ConstantPool::basic_type_for_signature_at(int which) const { - return FieldType::basic_type(symbol_at(which)); + return Signature::basic_type(symbol_at(which)); } @@ -840,7 +839,7 @@ BasicType ConstantPool::basic_type_for_constant_at(int which) { tag.is_dynamic_constant_in_error()) { // have to look at the signature for this one Symbol* constant_type = uncached_signature_ref_at(which); - return FieldType::basic_type(constant_type); + return Signature::basic_type(constant_type); } return tag.basic_type(); } @@ -950,7 +949,7 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp, save_and_throw_exception(this_cp, index, tag, CHECK_NULL); } result_oop = bootstrap_specifier.resolved_value()(); - BasicType type = FieldType::basic_type(bootstrap_specifier.signature()); + BasicType type = Signature::basic_type(bootstrap_specifier.signature()); if (!is_reference_type(type)) { // Make sure the primitive value is properly boxed. // This is a JDK responsibility. diff --git a/src/hotspot/share/oops/generateOopMap.cpp b/src/hotspot/share/oops/generateOopMap.cpp index f3973db7961..a21f7e0f97c 100644 --- a/src/hotspot/share/oops/generateOopMap.cpp +++ b/src/hotspot/share/oops/generateOopMap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -114,22 +114,22 @@ class ComputeCallStack : public SignatureIterator { void set(CellTypeState state) { _effect[_idx++] = state; } int length() { return _idx; }; - virtual void do_bool () { set(CellTypeState::value); }; - virtual void do_char () { set(CellTypeState::value); }; - virtual void do_float () { set(CellTypeState::value); }; - virtual void do_byte () { set(CellTypeState::value); }; - virtual void do_short () { set(CellTypeState::value); }; - virtual void do_int () { set(CellTypeState::value); }; - virtual void do_void () { set(CellTypeState::bottom);}; - virtual void do_object(int begin, int end) { set(CellTypeState::ref); }; - virtual void do_array (int begin, int end) { set(CellTypeState::ref); }; - - void do_double() { set(CellTypeState::value); - set(CellTypeState::value); } - void do_long () { set(CellTypeState::value); - set(CellTypeState::value); } - -public: + friend class SignatureIterator; // so do_parameters_on can call do_type + void do_type(BasicType type, bool for_return = false) { + if (for_return && type == T_VOID) { + set(CellTypeState::bottom); + } else if (is_reference_type(type)) { + set(CellTypeState::ref); + } else { + assert(is_java_primitive(type), ""); + set(CellTypeState::value); + if (is_double_word_type(type)) { + set(CellTypeState::value); + } + } + } + + public: ComputeCallStack(Symbol* signature) : SignatureIterator(signature) {}; // Compute methods @@ -140,7 +140,7 @@ class ComputeCallStack : public SignatureIterator { if (!is_static) effect[_idx++] = CellTypeState::ref; - iterate_parameters(); + do_parameters_on(this); return length(); }; @@ -148,7 +148,7 @@ class ComputeCallStack : public SignatureIterator { int compute_for_returntype(CellTypeState *effect) { _idx = 0; _effect = effect; - iterate_returntype(); + do_type(return_type(), true); set(CellTypeState::bottom); // Always terminate with a bottom state, so ppush works return length(); @@ -168,22 +168,22 @@ class ComputeEntryStack : public SignatureIterator { void set(CellTypeState state) { _effect[_idx++] = state; } int length() { return _idx; }; - virtual void do_bool () { set(CellTypeState::value); }; - virtual void do_char () { set(CellTypeState::value); }; - virtual void do_float () { set(CellTypeState::value); }; - virtual void do_byte () { set(CellTypeState::value); }; - virtual void do_short () { set(CellTypeState::value); }; - virtual void do_int () { set(CellTypeState::value); }; - virtual void do_void () { set(CellTypeState::bottom);}; - virtual void do_object(int begin, int end) { set(CellTypeState::make_slot_ref(_idx)); } - virtual void do_array (int begin, int end) { set(CellTypeState::make_slot_ref(_idx)); } - - void do_double() { set(CellTypeState::value); - set(CellTypeState::value); } - void do_long () { set(CellTypeState::value); - set(CellTypeState::value); } - -public: + friend class SignatureIterator; // so do_parameters_on can call do_type + void do_type(BasicType type, bool for_return = false) { + if (for_return && type == T_VOID) { + set(CellTypeState::bottom); + } else if (is_reference_type(type)) { + set(CellTypeState::make_slot_ref(_idx)); + } else { + assert(is_java_primitive(type), ""); + set(CellTypeState::value); + if (is_double_word_type(type)) { + set(CellTypeState::value); + } + } + } + + public: ComputeEntryStack(Symbol* signature) : SignatureIterator(signature) {}; // Compute methods @@ -194,7 +194,7 @@ class ComputeEntryStack : public SignatureIterator { if (!is_static) effect[_idx++] = CellTypeState::make_slot_ref(0); - iterate_parameters(); + do_parameters_on(this); return length(); }; @@ -202,7 +202,7 @@ class ComputeEntryStack : public SignatureIterator { int compute_for_returntype(CellTypeState *effect) { _idx = 0; _effect = effect; - iterate_returntype(); + do_type(return_type(), true); set(CellTypeState::bottom); // Always terminate with a bottom state, so ppush works return length(); @@ -1930,12 +1930,8 @@ void GenerateOopMap::do_field(int is_get, int is_static, int idx, int bci) { int signatureIdx = cp->signature_ref_index_at(nameAndTypeIdx); Symbol* signature = cp->symbol_at(signatureIdx); - // Parse signature (espcially simple for fields) - assert(signature->utf8_length() > 0, "field signatures cannot have zero length"); - // The signature is UFT8 encoded, but the first char is always ASCII for signatures. - char sigch = (char)*(signature->base()); CellTypeState temp[4]; - CellTypeState *eff = sigchar_to_effect(sigch, bci, temp); + CellTypeState *eff = signature_to_effect(signature, bci, temp); CellTypeState in[4]; CellTypeState *out; @@ -1991,16 +1987,17 @@ void GenerateOopMap::do_method(int is_static, int is_interface, int idx, int bci } // This is used to parse the signature for fields, since they are very simple... -CellTypeState *GenerateOopMap::sigchar_to_effect(char sigch, int bci, CellTypeState *out) { +CellTypeState *GenerateOopMap::signature_to_effect(const Symbol* sig, int bci, CellTypeState *out) { // Object and array - if (sigch==JVM_SIGNATURE_CLASS || sigch==JVM_SIGNATURE_ARRAY) { + BasicType bt = Signature::basic_type(sig); + if (is_reference_type(bt)) { out[0] = CellTypeState::make_line_ref(bci); out[1] = CellTypeState::bottom; return out; } - if (sigch == JVM_SIGNATURE_LONG || sigch == JVM_SIGNATURE_DOUBLE) return vvCTS; // Long and Double - if (sigch == JVM_SIGNATURE_VOID) return epsilonCTS; // Void - return vCTS; // Otherwise + if (is_double_word_type(bt)) return vvCTS; // Long and Double + if (bt == T_VOID) return epsilonCTS; // Void + return vCTS; // Otherwise } long GenerateOopMap::_total_byte_count = 0; diff --git a/src/hotspot/share/oops/generateOopMap.hpp b/src/hotspot/share/oops/generateOopMap.hpp index 89effafd4c5..e6d1f98a1b2 100644 --- a/src/hotspot/share/oops/generateOopMap.hpp +++ b/src/hotspot/share/oops/generateOopMap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -403,7 +403,7 @@ class GenerateOopMap { void do_monitorexit (int bci); void do_return_monitor_check (); void do_checkcast (); - CellTypeState *sigchar_to_effect (char sigch, int bci, CellTypeState *out); + CellTypeState *signature_to_effect (const Symbol* sig, int bci, CellTypeState *out); int copy_cts (CellTypeState *dst, CellTypeState *src); // Error handling diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index f670abc8491..d2f32e0785e 100644 --- a/src/hotspot/share/oops/method.cpp +++ b/src/hotspot/share/oops/method.cpp @@ -577,9 +577,16 @@ int Method::extra_stack_words() { return extra_stack_entries() * Interpreter::stackElementSize; } -void Method::compute_size_of_parameters(Thread *thread) { - ArgumentSizeComputer asc(signature()); - set_size_of_parameters(asc.size() + (is_static() ? 0 : 1)); +// Derive size of parameters, return type, and fingerprint, +// all in one pass, which is run at load time. +// We need the first two, and might as well grab the third. +void Method::compute_from_signature(Symbol* sig) { + // At this point, since we are scanning the signature, + // we might as well compute the whole fingerprint. + Fingerprinter fp(sig, is_static()); + set_size_of_parameters(fp.size_of_parameters()); + constMethod()->set_result_type(fp.return_type()); + constMethod()->set_fingerprint(fp.fingerprint()); } bool Method::is_empty_method() const { @@ -1443,9 +1450,7 @@ methodHandle Method::make_method_handle_intrinsic(vmIntrinsics::ID iid, m->set_signature_index(_imcp_invoke_signature); assert(MethodHandles::is_signature_polymorphic_name(m->name()), ""); assert(m->signature() == signature, ""); - ResultTypeFinder rtf(signature); - m->constMethod()->set_result_type(rtf.type()); - m->compute_size_of_parameters(THREAD); + m->compute_from_signature(signature); m->init_intrinsic_id(); assert(m->is_method_handle_intrinsic(), ""); #ifdef ASSERT @@ -1685,7 +1690,7 @@ bool Method::load_signature_classes(const methodHandle& m, TRAPS) { ResourceMark rm(THREAD); Symbol* signature = m->signature(); for(SignatureStream ss(signature); !ss.is_done(); ss.next()) { - if (ss.is_object()) { + if (ss.is_reference()) { Symbol* sym = ss.as_symbol(); Symbol* name = sym; Klass* klass = SystemDictionary::resolve_or_null(name, class_loader, @@ -1713,8 +1718,7 @@ bool Method::has_unloaded_classes_in_signature(const methodHandle& m, TRAPS) { Symbol* signature = m->signature(); for(SignatureStream ss(signature); !ss.is_done(); ss.next()) { if (ss.type() == T_OBJECT) { - Symbol* name = ss.as_symbol_or_null(); - if (name == NULL) return true; + Symbol* name = ss.as_symbol(); Klass* klass = SystemDictionary::find(name, class_loader, protection_domain, THREAD); if (klass == NULL) return true; } @@ -1733,7 +1737,7 @@ void Method::print_short_name(outputStream* st) { name()->print_symbol_on(st); if (WizardMode) signature()->print_symbol_on(st); else if (MethodHandles::is_signature_polymorphic(intrinsic_id())) - MethodHandles::print_as_basic_type_signature_on(st, signature(), true); + MethodHandles::print_as_basic_type_signature_on(st, signature()); } // Comparer for sorting an object array containing @@ -1786,8 +1790,8 @@ class SignatureTypePrinter : public SignatureTypeNames { _use_separator = false; } - void print_parameters() { _use_separator = false; iterate_parameters(); } - void print_returntype() { _use_separator = false; iterate_returntype(); } + void print_parameters() { _use_separator = false; do_parameters_on(this); } + void print_returntype() { _use_separator = false; do_type(return_type()); } }; diff --git a/src/hotspot/share/oops/method.hpp b/src/hotspot/share/oops/method.hpp index 3806afba380..21c390a1894 100644 --- a/src/hotspot/share/oops/method.hpp +++ b/src/hotspot/share/oops/method.hpp @@ -307,7 +307,10 @@ class Method : public Metadata { } } - // size of parameters + // Derive stuff from the signature at load time. + void compute_from_signature(Symbol* sig); + + // size of parameters (receiver if any + arguments) int size_of_parameters() const { return constMethod()->size_of_parameters(); } void set_size_of_parameters(int size) { constMethod()->set_size_of_parameters(size); } @@ -605,7 +608,6 @@ class Method : public Metadata { // method holder (the Klass* holding this method) InstanceKlass* method_holder() const { return constants()->pool_holder(); } - void compute_size_of_parameters(Thread *thread); // word size of parameters (receiver if any + arguments) Symbol* klass_name() const; // returns the name of the method holder BasicType result_type() const { return constMethod()->result_type(); } bool is_returning_oop() const { BasicType r = result_type(); return is_reference_type(r); } diff --git a/src/hotspot/share/oops/methodData.cpp b/src/hotspot/share/oops/methodData.cpp index 79a5c3be5cb..4e557834057 100644 --- a/src/hotspot/share/oops/methodData.cpp +++ b/src/hotspot/share/oops/methodData.cpp @@ -199,8 +199,8 @@ int TypeStackSlotEntries::compute_cell_count(Symbol* signature, bool include_rec // Parameter profiling include the receiver int args_count = include_receiver ? 1 : 0; ResourceMark rm; - SignatureStream ss(signature); - args_count += ss.reference_parameter_count(); + ReferenceArgumentCount rac(signature); + args_count += rac.count(); args_count = MIN2(args_count, max); return args_count * per_arg_cell_count; } @@ -227,32 +227,28 @@ int TypeEntriesAtCall::compute_cell_count(BytecodeStream* stream) { return header_cell + args_cell + ret_cell; } -class ArgumentOffsetComputer : public SignatureInfo { +class ArgumentOffsetComputer : public SignatureIterator { private: int _max; + int _offset; GrowableArray _offsets; - void set(int size, BasicType type) { _size += size; } - void do_object(int begin, int end) { - if (_offsets.length() < _max) { - _offsets.push(_size); + friend class SignatureIterator; // so do_parameters_on can call do_type + void do_type(BasicType type) { + if (is_reference_type(type) && _offsets.length() < _max) { + _offsets.push(_offset); } - SignatureInfo::do_object(begin, end); - } - void do_array (int begin, int end) { - if (_offsets.length() < _max) { - _offsets.push(_size); - } - SignatureInfo::do_array(begin, end); + _offset += parameter_type_word_count(type); } -public: + public: ArgumentOffsetComputer(Symbol* signature, int max) - : SignatureInfo(signature), _max(max), _offsets(Thread::current(), max) { + : SignatureIterator(signature), + _max(max), _offset(0), + _offsets(Thread::current(), max) { + do_parameters_on(this); // non-virtual template execution } - int total() { lazy_iterate_parameters(); return _size; } - int off_at(int i) const { return _offsets.at(i); } }; @@ -266,7 +262,6 @@ void TypeStackSlotEntries::post_initialize(Symbol* signature, bool has_receiver, start += 1; } ArgumentOffsetComputer aos(signature, _number_of_entries-start); - aos.total(); for (int i = start; i < _number_of_entries; i++) { set_stack_slot(i, aos.off_at(i-start) + (has_receiver ? 1 : 0)); set_type(i, type_none()); @@ -277,11 +272,11 @@ void CallTypeData::post_initialize(BytecodeStream* stream, MethodData* mdo) { assert(Bytecodes::is_invoke(stream->code()), "should be invoke"); Bytecode_invoke inv(stream->method(), stream->bci()); - SignatureStream ss(inv.signature()); if (has_arguments()) { #ifdef ASSERT ResourceMark rm; - int count = MIN2(ss.reference_parameter_count(), (int)TypeProfileArgsLimit); + ReferenceArgumentCount rac(inv.signature()); + int count = MIN2(rac.count(), (int)TypeProfileArgsLimit); assert(count > 0, "room for args type but none found?"); check_number_of_arguments(count); #endif @@ -301,8 +296,8 @@ void VirtualCallTypeData::post_initialize(BytecodeStream* stream, MethodData* md if (has_arguments()) { #ifdef ASSERT ResourceMark rm; - SignatureStream ss(inv.signature()); - int count = MIN2(ss.reference_parameter_count(), (int)TypeProfileArgsLimit); + ReferenceArgumentCount rac(inv.signature()); + int count = MIN2(rac.count(), (int)TypeProfileArgsLimit); assert(count > 0, "room for args type but none found?"); check_number_of_arguments(count); #endif diff --git a/src/hotspot/share/oops/symbol.cpp b/src/hotspot/share/oops/symbol.cpp index ca63d5d437f..0b4dea061b8 100644 --- a/src/hotspot/share/oops/symbol.cpp +++ b/src/hotspot/share/oops/symbol.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,6 +52,7 @@ uint32_t Symbol::pack_length_and_refcount(int length, int refcount) { Symbol::Symbol(const u1* name, int length, int refcount) { _length_and_refcount = pack_length_and_refcount(length, refcount); _identity_hash = (short)os::random(); + _body[0] = 0; // in case length == 0 for (int i = 0; i < length; i++) { byte_at_put(i, name[i]); } @@ -82,20 +83,31 @@ void Symbol::set_permanent() { // ------------------------------------------------------------------ -// Symbol::starts_with +// Symbol::contains_byte_at // -// Tests if the symbol starts with the specified prefix of the given -// length. -bool Symbol::starts_with(const char* prefix, int len) const { - if (len > utf8_length()) return false; - while (len-- > 0) { - if (prefix[len] != char_at(len)) - return false; - } - assert(len == -1, "we should be at the beginning"); - return true; +// Tests if the symbol contains the given byte at the given position. +bool Symbol::contains_byte_at(int position, char code_byte) const { + if (position < 0) return false; // can happen with ends_with + if (position >= utf8_length()) return false; + return code_byte == char_at(position); } +// ------------------------------------------------------------------ +// Symbol::contains_utf8_at +// +// Tests if the symbol contains the given utf8 substring +// at the given byte position. +bool Symbol::contains_utf8_at(int position, const char* substring, int len) const { + assert(len >= 0 && substring != NULL, "substring must be valid"); + if (len <= 1) + return len == 0 || contains_byte_at(position, substring[0]); + if (position < 0) return false; // can happen with ends_with + if (position + len > utf8_length()) return false; + if (memcmp((char*)base() + position, substring, len) == 0) + return true; + else + return false; +} // ------------------------------------------------------------------ // Symbol::index_of @@ -116,8 +128,11 @@ int Symbol::index_of_at(int i, const char* str, int len) const { if (scan == NULL) return -1; // not found assert(scan >= bytes+i && scan <= limit, "scan oob"); - if (memcmp(scan, str, len) == 0) + if (len <= 2 + ? (char) scan[len-1] == str[len-1] + : memcmp(scan+1, str+1, len-1) == 0) { return (int)(scan - bytes); + } } return -1; } @@ -186,8 +201,8 @@ const char* Symbol::as_klass_external_name(char* buf, int size) const { int length = (int)strlen(str); // Turn all '/'s into '.'s (also for array klasses) for (int index = 0; index < length; index++) { - if (str[index] == '/') { - str[index] = '.'; + if (str[index] == JVM_SIGNATURE_SLASH) { + str[index] = JVM_SIGNATURE_DOT; } } return str; @@ -208,28 +223,25 @@ const char* Symbol::as_klass_external_name() const { return str; } -static void print_class(outputStream *os, char *class_str, int len) { - for (int i = 0; i < len; ++i) { - if (class_str[i] == JVM_SIGNATURE_SLASH) { +static void print_class(outputStream *os, const SignatureStream& ss) { + int sb = ss.raw_symbol_begin(), se = ss.raw_symbol_end(); + for (int i = sb; i < se; ++i) { + int ch = ss.raw_char_at(i); + if (ch == JVM_SIGNATURE_SLASH) { os->put(JVM_SIGNATURE_DOT); } else { - os->put(class_str[i]); + os->put(ch); } } } -static void print_array(outputStream *os, char *array_str, int len) { - int dimensions = 0; - for (int i = 0; i < len; ++i) { - if (array_str[i] == JVM_SIGNATURE_ARRAY) { - dimensions++; - } else if (array_str[i] == JVM_SIGNATURE_CLASS) { - // Expected format: L;. Skip 'L' and ';' delimiting the type name. - print_class(os, array_str+i+1, len-i-2); - break; - } else { - os->print("%s", type2name(char2type(array_str[i]))); - } +static void print_array(outputStream *os, SignatureStream& ss) { + int dimensions = ss.skip_array_prefix(); + assert(dimensions > 0, ""); + if (ss.is_reference()) { + print_class(os, ss); + } else { + os->print("%s", type2name(ss.type())); } for (int i = 0; i < dimensions; ++i) { os->print("[]"); @@ -240,10 +252,9 @@ void Symbol::print_as_signature_external_return_type(outputStream *os) { for (SignatureStream ss(this); !ss.is_done(); ss.next()) { if (ss.at_return_type()) { if (ss.is_array()) { - print_array(os, (char*)ss.raw_bytes(), (int)ss.raw_length()); - } else if (ss.is_object()) { - // Expected format: L;. Skip 'L' and ';' delimiting the class name. - print_class(os, (char*)ss.raw_bytes()+1, (int)ss.raw_length()-2); + print_array(os, ss); + } else if (ss.is_reference()) { + print_class(os, ss); } else { os->print("%s", type2name(ss.type())); } @@ -257,10 +268,9 @@ void Symbol::print_as_signature_external_parameters(outputStream *os) { if (ss.at_return_type()) break; if (!first) { os->print(", "); } if (ss.is_array()) { - print_array(os, (char*)ss.raw_bytes(), (int)ss.raw_length()); - } else if (ss.is_object()) { - // Skip 'L' and ';'. - print_class(os, (char*)ss.raw_bytes()+1, (int)ss.raw_length()-2); + print_array(os, ss); + } else if (ss.is_reference()) { + print_class(os, ss); } else { os->print("%s", type2name(ss.type())); } diff --git a/src/hotspot/share/oops/symbol.hpp b/src/hotspot/share/oops/symbol.hpp index d4bbc9f7ff7..676253f77c5 100644 --- a/src/hotspot/share/oops/symbol.hpp +++ b/src/hotspot/share/oops/symbol.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -189,20 +189,34 @@ class Symbol : public MetaspaceObj { bool equals(const char* str, int len) const { int l = utf8_length(); if (l != len) return false; - while (l-- > 0) { - if (str[l] != char_at(l)) - return false; - } - assert(l == -1, "we should be at the beginning"); - return true; + return contains_utf8_at(0, str, len); } bool equals(const char* str) const { return equals(str, (int) strlen(str)); } // Tests if the symbol starts with the given prefix. - bool starts_with(const char* prefix, int len) const; + bool starts_with(const char* prefix, int len) const { + return contains_utf8_at(0, prefix, len); + } bool starts_with(const char* prefix) const { return starts_with(prefix, (int) strlen(prefix)); } + bool starts_with(int prefix_char) const { + return contains_byte_at(0, prefix_char); + } + // Tests if the symbol ends with the given suffix. + bool ends_with(const char* suffix, int len) const { + return contains_utf8_at(utf8_length() - len, suffix, len); + } + bool ends_with(const char* suffix) const { + return ends_with(suffix, (int) strlen(suffix)); + } + bool ends_with(int suffix_char) const { + return contains_byte_at(utf8_length()-1, suffix_char); + } + // Tests if the symbol contains the given utf8 substring + // or byte at the given byte position. + bool contains_utf8_at(int position, const char* substring, int len) const; + bool contains_byte_at(int position, char code_byte) const; // Tests if the symbol starts with the given prefix. int index_of_at(int i, const char* str, int len) const; diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp index 2c55751f294..cb85a31490e 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -862,40 +862,29 @@ class JNI_ArgumentPusher : public SignatureIterator { protected: JavaCallArguments* _arguments; - virtual void get_bool () = 0; - virtual void get_char () = 0; - virtual void get_short () = 0; - virtual void get_byte () = 0; - virtual void get_int () = 0; - virtual void get_long () = 0; - virtual void get_float () = 0; - virtual void get_double () = 0; - virtual void get_object () = 0; - - JNI_ArgumentPusher(Symbol* signature) : SignatureIterator(signature) { - this->_return_type = T_ILLEGAL; + void push_int(jint x) { _arguments->push_int(x); } + void push_long(jlong x) { _arguments->push_long(x); } + void push_float(jfloat x) { _arguments->push_float(x); } + void push_double(jdouble x) { _arguments->push_double(x); } + void push_object(jobject x) { _arguments->push_jobject(x); } + + void push_boolean(jboolean b) { + // Normalize boolean arguments from native code by converting 1-255 to JNI_TRUE and + // 0 to JNI_FALSE. Boolean return values from native are normalized the same in + // TemplateInterpreterGenerator::generate_result_handler_for and + // SharedRuntime::generate_native_wrapper. + push_int(b == 0 ? JNI_FALSE : JNI_TRUE); + } + + JNI_ArgumentPusher(Method* method) + : SignatureIterator(method->signature(), + Fingerprinter(methodHandle(Thread::current(), method)).fingerprint()) + { _arguments = NULL; } public: - virtual void iterate( uint64_t fingerprint ) = 0; - - void set_java_argument_object(JavaCallArguments *arguments) { _arguments = arguments; } - - inline void do_bool() { if (!is_return_type()) get_bool(); } - inline void do_char() { if (!is_return_type()) get_char(); } - inline void do_short() { if (!is_return_type()) get_short(); } - inline void do_byte() { if (!is_return_type()) get_byte(); } - inline void do_int() { if (!is_return_type()) get_int(); } - inline void do_long() { if (!is_return_type()) get_long(); } - inline void do_float() { if (!is_return_type()) get_float(); } - inline void do_double() { if (!is_return_type()) get_double(); } - inline void do_object(int begin, int end) { if (!is_return_type()) get_object(); } - inline void do_array(int begin, int end) { if (!is_return_type()) get_object(); } // do_array uses get_object -- there is no get_array - inline void do_void() { } - - JavaCallArguments* arguments() { return _arguments; } - void push_receiver(Handle h) { _arguments->push_oop(h); } + virtual void push_arguments_on(JavaCallArguments* arguments) = 0; }; @@ -903,89 +892,42 @@ class JNI_ArgumentPusherVaArg : public JNI_ArgumentPusher { protected: va_list _ap; - inline void get_bool() { - // Normalize boolean arguments from native code by converting 1-255 to JNI_TRUE and - // 0 to JNI_FALSE. Boolean return values from native are normalized the same in - // TemplateInterpreterGenerator::generate_result_handler_for and - // SharedRuntime::generate_native_wrapper. - jboolean b = va_arg(_ap, jint); - _arguments->push_int((jint)(b == 0 ? JNI_FALSE : JNI_TRUE)); + void set_ap(va_list rap) { + va_copy(_ap, rap); } - inline void get_char() { _arguments->push_int(va_arg(_ap, jint)); } // char is coerced to int when using va_arg - inline void get_short() { _arguments->push_int(va_arg(_ap, jint)); } // short is coerced to int when using va_arg - inline void get_byte() { _arguments->push_int(va_arg(_ap, jint)); } // byte is coerced to int when using va_arg - inline void get_int() { _arguments->push_int(va_arg(_ap, jint)); } - - // each of these paths is exercized by the various jck Call[Static,Nonvirtual,][Void,Int,..]Method[A,V,] tests - - inline void get_long() { _arguments->push_long(va_arg(_ap, jlong)); } - inline void get_float() { _arguments->push_float((jfloat)va_arg(_ap, jdouble)); } // float is coerced to double w/ va_arg - inline void get_double() { _arguments->push_double(va_arg(_ap, jdouble)); } - inline void get_object() { _arguments->push_jobject(va_arg(_ap, jobject)); } - inline void set_ap(va_list rap) { - va_copy(_ap, rap); + friend class SignatureIterator; // so do_parameters_on can call do_type + void do_type(BasicType type) { + switch (type) { + // these are coerced to int when using va_arg + case T_BYTE: + case T_CHAR: + case T_SHORT: + case T_INT: push_int(va_arg(_ap, jint)); break; + case T_BOOLEAN: push_boolean((jboolean) va_arg(_ap, jint)); break; + + // each of these paths is exercised by the various jck Call[Static,Nonvirtual,][Void,Int,..]Method[A,V,] tests + + case T_LONG: push_long(va_arg(_ap, jlong)); break; + // float is coerced to double w/ va_arg + case T_FLOAT: push_float((jfloat) va_arg(_ap, jdouble)); break; + case T_DOUBLE: push_double(va_arg(_ap, jdouble)); break; + + case T_ARRAY: + case T_OBJECT: push_object(va_arg(_ap, jobject)); break; + default: ShouldNotReachHere(); + } } public: - JNI_ArgumentPusherVaArg(Symbol* signature, va_list rap) - : JNI_ArgumentPusher(signature) { - set_ap(rap); - } JNI_ArgumentPusherVaArg(jmethodID method_id, va_list rap) - : JNI_ArgumentPusher(Method::resolve_jmethod_id(method_id)->signature()) { + : JNI_ArgumentPusher(Method::resolve_jmethod_id(method_id)) { set_ap(rap); } - // Optimized path if we have the bitvector form of signature - void iterate( uint64_t fingerprint ) { - if (fingerprint == (uint64_t)CONST64(-1)) { - SignatureIterator::iterate(); // Must be too many arguments - } else { - _return_type = (BasicType)((fingerprint >> static_feature_size) & - result_feature_mask); - - assert(fingerprint, "Fingerprint should not be 0"); - fingerprint = fingerprint >> (static_feature_size + result_feature_size); - while ( 1 ) { - switch ( fingerprint & parameter_feature_mask ) { - case bool_parm: - get_bool(); - break; - case char_parm: - get_char(); - break; - case short_parm: - get_short(); - break; - case byte_parm: - get_byte(); - break; - case int_parm: - get_int(); - break; - case obj_parm: - get_object(); - break; - case long_parm: - get_long(); - break; - case float_parm: - get_float(); - break; - case double_parm: - get_double(); - break; - case done_parm: - return; - break; - default: - ShouldNotReachHere(); - break; - } - fingerprint >>= parameter_feature_size; - } - } + virtual void push_arguments_on(JavaCallArguments* arguments) { + _arguments = arguments; + do_parameters_on(this); } }; @@ -994,84 +936,34 @@ class JNI_ArgumentPusherArray : public JNI_ArgumentPusher { protected: const jvalue *_ap; - inline void get_bool() { - // Normalize boolean arguments from native code by converting 1-255 to JNI_TRUE and - // 0 to JNI_FALSE. Boolean return values from native are normalized the same in - // TemplateInterpreterGenerator::generate_result_handler_for and - // SharedRuntime::generate_native_wrapper. - jboolean b = (_ap++)->z; - _arguments->push_int((jint)(b == 0 ? JNI_FALSE : JNI_TRUE)); - } - inline void get_char() { _arguments->push_int((jint)(_ap++)->c); } - inline void get_short() { _arguments->push_int((jint)(_ap++)->s); } - inline void get_byte() { _arguments->push_int((jint)(_ap++)->b); } - inline void get_int() { _arguments->push_int((jint)(_ap++)->i); } - - inline void get_long() { _arguments->push_long((_ap++)->j); } - inline void get_float() { _arguments->push_float((_ap++)->f); } - inline void get_double() { _arguments->push_double((_ap++)->d);} - inline void get_object() { _arguments->push_jobject((_ap++)->l); } - inline void set_ap(const jvalue *rap) { _ap = rap; } - public: - JNI_ArgumentPusherArray(Symbol* signature, const jvalue *rap) - : JNI_ArgumentPusher(signature) { - set_ap(rap); + friend class SignatureIterator; // so do_parameters_on can call do_type + void do_type(BasicType type) { + switch (type) { + case T_CHAR: push_int((_ap++)->c); break; + case T_SHORT: push_int((_ap++)->s); break; + case T_BYTE: push_int((_ap++)->b); break; + case T_INT: push_int((_ap++)->i); break; + case T_BOOLEAN: push_boolean((_ap++)->z); break; + case T_LONG: push_long((_ap++)->j); break; + case T_FLOAT: push_float((_ap++)->f); break; + case T_DOUBLE: push_double((_ap++)->d); break; + case T_ARRAY: + case T_OBJECT: push_object((_ap++)->l); break; + default: ShouldNotReachHere(); + } } + + public: JNI_ArgumentPusherArray(jmethodID method_id, const jvalue *rap) - : JNI_ArgumentPusher(Method::resolve_jmethod_id(method_id)->signature()) { + : JNI_ArgumentPusher(Method::resolve_jmethod_id(method_id)) { set_ap(rap); } - // Optimized path if we have the bitvector form of signature - void iterate( uint64_t fingerprint ) { - if (fingerprint == (uint64_t)CONST64(-1)) { - SignatureIterator::iterate(); // Must be too many arguments - } else { - _return_type = (BasicType)((fingerprint >> static_feature_size) & - result_feature_mask); - assert(fingerprint, "Fingerprint should not be 0"); - fingerprint = fingerprint >> (static_feature_size + result_feature_size); - while ( 1 ) { - switch ( fingerprint & parameter_feature_mask ) { - case bool_parm: - get_bool(); - break; - case char_parm: - get_char(); - break; - case short_parm: - get_short(); - break; - case byte_parm: - get_byte(); - break; - case int_parm: - get_int(); - break; - case obj_parm: - get_object(); - break; - case long_parm: - get_long(); - break; - case float_parm: - get_float(); - break; - case double_parm: - get_double(); - break; - case done_parm: - return; - break; - default: - ShouldNotReachHere(); - break; - } - fingerprint >>= parameter_feature_size; - } - } + virtual void push_arguments_on(JavaCallArguments* arguments) { + _arguments = arguments; + do_parameters_on(this); } }; @@ -1092,14 +984,13 @@ static void jni_invoke_static(JNIEnv *env, JavaValue* result, jobject receiver, ResourceMark rm(THREAD); int number_of_parameters = method->size_of_parameters(); JavaCallArguments java_args(number_of_parameters); - args->set_java_argument_object(&java_args); assert(method->is_static(), "method should be static"); // Fill out JavaCallArguments object - args->iterate( Fingerprinter(method).fingerprint() ); + args->push_arguments_on(&java_args); // Initialize result type - result->set_type(args->get_ret_type()); + result->set_type(args->return_type()); // Invoke the method. Result is returned as oop. JavaCalls::call(result, method, &java_args, CHECK); @@ -1153,16 +1044,15 @@ static void jni_invoke_nonstatic(JNIEnv *env, JavaValue* result, jobject receive // the jni parser ResourceMark rm(THREAD); JavaCallArguments java_args(number_of_parameters); - args->set_java_argument_object(&java_args); // handle arguments assert(!method->is_static(), "method %s should not be static", method->name_and_sig_as_C_string()); - args->push_receiver(h_recv); // Push jobject handle + java_args.push_oop(h_recv); // Push jobject handle // Fill out JavaCallArguments object - args->iterate( Fingerprinter(method).fingerprint() ); + args->push_arguments_on(&java_args); // Initialize result type - result->set_type(args->get_ret_type()); + result->set_type(args->return_type()); // Invoke the method. Result is returned as oop. JavaCalls::call(result, method, &java_args, CHECK); diff --git a/src/hotspot/share/prims/jvmtiImpl.cpp b/src/hotspot/share/prims/jvmtiImpl.cpp index 4bf4d49c49e..c22eb9a3dc8 100644 --- a/src/hotspot/share/prims/jvmtiImpl.cpp +++ b/src/hotspot/share/prims/jvmtiImpl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -570,8 +570,7 @@ bool VM_GetOrSetLocal::check_slot_type_lvt(javaVFrame* jvf) { return false; // Incorrect slot index } Symbol* sign_sym = method_oop->constants()->symbol_at(signature_idx); - const char* signature = (const char *) sign_sym->as_utf8(); - BasicType slot_type = char2type(signature[0]); + BasicType slot_type = Signature::basic_type(sign_sym); switch (slot_type) { case T_BYTE: @@ -602,6 +601,7 @@ bool VM_GetOrSetLocal::check_slot_type_lvt(javaVFrame* jvf) { Klass* ob_k = obj->klass(); NULL_CHECK(ob_k, (_result = JVMTI_ERROR_INVALID_OBJECT, false)); + const char* signature = (const char *) sign_sym->as_utf8(); if (!is_assignable(signature, ob_k, cur_thread)) { _result = JVMTI_ERROR_TYPE_MISMATCH; return false; diff --git a/src/hotspot/share/prims/methodHandles.cpp b/src/hotspot/share/prims/methodHandles.cpp index 3a1f0dc57d7..ee0575cc906 100644 --- a/src/hotspot/share/prims/methodHandles.cpp +++ b/src/hotspot/share/prims/methodHandles.cpp @@ -539,25 +539,21 @@ enum { OBJ_SIG_LEN = 18 }; bool MethodHandles::is_basic_type_signature(Symbol* sig) { assert(vmSymbols::object_signature()->utf8_length() == (int)OBJ_SIG_LEN, ""); assert(vmSymbols::object_signature()->equals(OBJ_SIG), ""); - const int len = sig->utf8_length(); - for (int i = 0; i < len; i++) { - switch (sig->char_at(i)) { - case JVM_SIGNATURE_CLASS: + for (SignatureStream ss(sig, sig->starts_with(JVM_SIGNATURE_FUNC)); !ss.is_done(); ss.next()) { + switch (ss.type()) { + case T_OBJECT: // only java/lang/Object is valid here - if (sig->index_of_at(i, OBJ_SIG, OBJ_SIG_LEN) != i) + if (strncmp((char*) ss.raw_bytes(), OBJ_SIG, OBJ_SIG_LEN) != 0) return false; - i += OBJ_SIG_LEN-1; //-1 because of i++ in loop - continue; - case JVM_SIGNATURE_FUNC: - case JVM_SIGNATURE_ENDFUNC: - case JVM_SIGNATURE_VOID: - case JVM_SIGNATURE_INT: - case JVM_SIGNATURE_LONG: - case JVM_SIGNATURE_FLOAT: - case JVM_SIGNATURE_DOUBLE: - continue; + break; + case T_VOID: + case T_INT: + case T_LONG: + case T_FLOAT: + case T_DOUBLE: + break; default: - // subword types (T_BYTE etc.), arrays + // subword types (T_BYTE etc.), Q-descriptors, arrays return false; } } @@ -571,8 +567,8 @@ Symbol* MethodHandles::lookup_basic_type_signature(Symbol* sig, bool keep_last_a } else if (is_basic_type_signature(sig)) { sig->increment_refcount(); return sig; // that was easy - } else if (sig->char_at(0) != JVM_SIGNATURE_FUNC) { - BasicType bt = char2type(sig->char_at(0)); + } else if (!sig->starts_with(JVM_SIGNATURE_FUNC)) { + BasicType bt = Signature::basic_type(sig); if (is_subword_type(bt)) { bsig = vmSymbols::int_signature(); } else { @@ -615,71 +611,26 @@ Symbol* MethodHandles::lookup_basic_type_signature(Symbol* sig, bool keep_last_a } void MethodHandles::print_as_basic_type_signature_on(outputStream* st, - Symbol* sig, - bool keep_arrays, - bool keep_basic_names) { + Symbol* sig) { st = st ? st : tty; - int len = sig->utf8_length(); - int array = 0; bool prev_type = false; - for (int i = 0; i < len; i++) { - char ch = sig->char_at(i); - switch (ch) { - case JVM_SIGNATURE_FUNC: - case JVM_SIGNATURE_ENDFUNC: - prev_type = false; - st->put(ch); - continue; - case JVM_SIGNATURE_ARRAY: - if (!keep_basic_names && keep_arrays) - st->put(ch); - array++; - continue; - case JVM_SIGNATURE_CLASS: - { - if (prev_type) st->put(','); - int start = i+1, slash = start; - while (++i < len && (ch = sig->char_at(i)) != JVM_SIGNATURE_ENDCLASS) { - if (ch == JVM_SIGNATURE_SLASH || ch == JVM_SIGNATURE_DOT || ch == '$') slash = i+1; - } - if (slash < i) start = slash; - if (!keep_basic_names) { - st->put(JVM_SIGNATURE_CLASS); - } else { - for (int j = start; j < i; j++) - st->put(sig->char_at(j)); - prev_type = true; - } - break; - } - default: - { - if (array && char2type(ch) != T_ILLEGAL && !keep_arrays) { - ch = JVM_SIGNATURE_ARRAY; - array = 0; - } - if (prev_type) st->put(','); - const char* n = NULL; - if (keep_basic_names) - n = type2name(char2type(ch)); - if (n == NULL) { - // unknown letter, or we don't want to know its name - st->put(ch); - } else { - st->print("%s", n); - prev_type = true; - } - break; - } - } - // Switch break goes here to take care of array suffix: - if (prev_type) { - while (array > 0) { - st->print("[]"); - --array; - } + bool is_method = (sig->char_at(0) == JVM_SIGNATURE_FUNC); + if (is_method) st->put(JVM_SIGNATURE_FUNC); + for (SignatureStream ss(sig, is_method); !ss.is_done(); ss.next()) { + if (ss.at_return_type()) + st->put(JVM_SIGNATURE_ENDFUNC); + else if (prev_type) + st->put(','); + const char* cp = (const char*) ss.raw_bytes(); + if (ss.is_array()) { + st->put(JVM_SIGNATURE_ARRAY); + if (ss.array_prefix_length() == 1) + st->put(cp[1]); + else + st->put(JVM_SIGNATURE_CLASS); + } else { + st->put(cp[0]); } - array = 0; } } @@ -696,7 +647,7 @@ oop MethodHandles::field_name_or_null(Symbol* s) { oop MethodHandles::field_signature_type_or_null(Symbol* s) { if (s == NULL) return NULL; - BasicType bt = FieldType::basic_type(s); + BasicType bt = Signature::basic_type(s); if (is_java_primitive(bt)) { assert(s->utf8_length() == 1, ""); return java_lang_Class::primitive_mirror(bt); @@ -982,8 +933,7 @@ int MethodHandles::find_MemberNames(Klass* k, if (name->utf8_length() == 0) return 0; // a match is not possible } if (sig != NULL) { - if (sig->utf8_length() == 0) return 0; // a match is not possible - if (sig->char_at(0) == JVM_SIGNATURE_FUNC) + if (sig->starts_with(JVM_SIGNATURE_FUNC)) match_flags &= ~(IS_FIELD | IS_TYPE); else match_flags &= ~(IS_CONSTRUCTOR | IS_METHOD); diff --git a/src/hotspot/share/prims/methodHandles.hpp b/src/hotspot/share/prims/methodHandles.hpp index e04508fc757..54f36202a5f 100644 --- a/src/hotspot/share/prims/methodHandles.hpp +++ b/src/hotspot/share/prims/methodHandles.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -155,7 +155,7 @@ class MethodHandles: AllStatic { } static bool is_basic_type_signature(Symbol* sig); - static void print_as_basic_type_signature_on(outputStream* st, Symbol* sig, bool keep_arrays = false, bool keep_basic_names = false); + static void print_as_basic_type_signature_on(outputStream* st, Symbol* sig); // decoding CONSTANT_MethodHandle constants enum { JVM_REF_MIN = JVM_REF_getField, JVM_REF_MAX = JVM_REF_invokeInterface }; diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index 11df15e0049..f5862bf491a 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -1,7 +1,7 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1165,7 +1165,7 @@ static int reassign_fields_by_klass(InstanceKlass* klass, frame* fr, RegisterMap if (!fs.access_flags().is_static() && (!skip_internal || !fs.access_flags().is_internal())) { ReassignedField field; field._offset = fs.offset(); - field._type = FieldType::basic_type(fs.signature()); + field._type = Signature::basic_type(fs.signature()); fields->append(field); } } @@ -1606,33 +1606,20 @@ Deoptimization::get_method_data(JavaThread* thread, const methodHandle& m, #if COMPILER2_OR_JVMCI void Deoptimization::load_class_by_index(const constantPoolHandle& constant_pool, int index, TRAPS) { - // in case of an unresolved klass entry, load the class. + // In case of an unresolved klass entry, load the class. + // This path is exercised from case _ldc in Parse::do_one_bytecode, + // and probably nowhere else. + // Even that case would benefit from simply re-interpreting the + // bytecode, without paying special attention to the class index. + // So this whole "class index" feature should probably be removed. + if (constant_pool->tag_at(index).is_unresolved_klass()) { Klass* tk = constant_pool->klass_at_ignore_error(index, CHECK); return; } - if (!constant_pool->tag_at(index).is_symbol()) return; - - Handle class_loader (THREAD, constant_pool->pool_holder()->class_loader()); - Symbol* symbol = constant_pool->symbol_at(index); - - // class name? - if (symbol->char_at(0) != '(') { - Handle protection_domain (THREAD, constant_pool->pool_holder()->protection_domain()); - SystemDictionary::resolve_or_null(symbol, class_loader, protection_domain, CHECK); - return; - } - - // then it must be a signature! - ResourceMark rm(THREAD); - for (SignatureStream ss(symbol); !ss.is_done(); ss.next()) { - if (ss.is_object()) { - Symbol* class_name = ss.as_symbol(); - Handle protection_domain (THREAD, constant_pool->pool_holder()->protection_domain()); - SystemDictionary::resolve_or_null(class_name, class_loader, protection_domain, CHECK); - } - } + assert(!constant_pool->tag_at(index).is_symbol(), + "no symbolic names here, please"); } diff --git a/src/hotspot/share/runtime/fieldDescriptor.hpp b/src/hotspot/share/runtime/fieldDescriptor.hpp index 35dc7f67911..189f785bb4c 100644 --- a/src/hotspot/share/runtime/fieldDescriptor.hpp +++ b/src/hotspot/share/runtime/fieldDescriptor.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,6 @@ #include "oops/fieldInfo.hpp" #include "oops/instanceKlass.hpp" #include "oops/symbol.hpp" -#include "runtime/fieldType.hpp" #include "utilities/accessFlags.hpp" #include "utilities/constantTag.hpp" diff --git a/src/hotspot/share/runtime/fieldDescriptor.inline.hpp b/src/hotspot/share/runtime/fieldDescriptor.inline.hpp index ac5661ed459..9b5e6f5b35a 100644 --- a/src/hotspot/share/runtime/fieldDescriptor.inline.hpp +++ b/src/hotspot/share/runtime/fieldDescriptor.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -76,7 +76,7 @@ inline void fieldDescriptor::set_has_initialized_final_update(const bool value) } inline BasicType fieldDescriptor::field_type() const { - return FieldType::basic_type(signature()); + return Signature::basic_type(signature()); } #endif // SHARE_RUNTIME_FIELDDESCRIPTOR_INLINE_HPP diff --git a/src/hotspot/share/runtime/frame.cpp b/src/hotspot/share/runtime/frame.cpp index efcce71de26..958539e750a 100644 --- a/src/hotspot/share/runtime/frame.cpp +++ b/src/hotspot/share/runtime/frame.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -714,17 +714,18 @@ class InterpreterFrameClosure : public OffsetClosure { }; -class InterpretedArgumentOopFinder: public SignatureInfo { +class InterpretedArgumentOopFinder: public SignatureIterator { private: OopClosure* _f; // Closure to invoke int _offset; // TOS-relative offset, decremented with each argument bool _has_receiver; // true if the callee has a receiver frame* _fr; - void set(int size, BasicType type) { - _offset -= size; + friend class SignatureIterator; // so do_parameters_on can call do_type + void do_type(BasicType type) { + _offset -= parameter_type_word_count(type); if (is_reference_type(type)) oop_offset_do(); - } + } void oop_offset_do() { oop* addr; @@ -733,7 +734,7 @@ class InterpretedArgumentOopFinder: public SignatureInfo { } public: - InterpretedArgumentOopFinder(Symbol* signature, bool has_receiver, frame* fr, OopClosure* f) : SignatureInfo(signature), _has_receiver(has_receiver) { + InterpretedArgumentOopFinder(Symbol* signature, bool has_receiver, frame* fr, OopClosure* f) : SignatureIterator(signature), _has_receiver(has_receiver) { // compute size of arguments int args_size = ArgumentSizeComputer(signature).size() + (has_receiver ? 1 : 0); assert(!fr->is_interpreted_frame() || @@ -750,7 +751,7 @@ class InterpretedArgumentOopFinder: public SignatureInfo { --_offset; oop_offset_do(); } - iterate_parameters(); + do_parameters_on(this); } }; @@ -767,18 +768,20 @@ class InterpretedArgumentOopFinder: public SignatureInfo { // visits and GC's all the arguments in entry frame -class EntryFrameOopFinder: public SignatureInfo { +class EntryFrameOopFinder: public SignatureIterator { private: bool _is_static; int _offset; frame* _fr; OopClosure* _f; - void set(int size, BasicType type) { + friend class SignatureIterator; // so do_parameters_on can call do_type + void do_type(BasicType type) { + // decrement offset before processing the type + _offset -= parameter_type_word_count(type); assert (_offset >= 0, "illegal offset"); - if (is_reference_type(type)) oop_at_offset_do(_offset); - _offset -= size; - } + if (is_reference_type(type)) oop_at_offset_do(_offset); + } void oop_at_offset_do(int offset) { assert (offset >= 0, "illegal offset"); @@ -787,17 +790,17 @@ class EntryFrameOopFinder: public SignatureInfo { } public: - EntryFrameOopFinder(frame* frame, Symbol* signature, bool is_static) : SignatureInfo(signature) { - _f = NULL; // will be set later - _fr = frame; - _is_static = is_static; - _offset = ArgumentSizeComputer(signature).size() - 1; // last parameter is at index 0 - } + EntryFrameOopFinder(frame* frame, Symbol* signature, bool is_static) : SignatureIterator(signature) { + _f = NULL; // will be set later + _fr = frame; + _is_static = is_static; + _offset = ArgumentSizeComputer(signature).size(); // pre-decremented down to zero + } void arguments_do(OopClosure* f) { _f = f; - if (!_is_static) oop_at_offset_do(_offset+1); // do the receiver - iterate_parameters(); + if (!_is_static) oop_at_offset_do(_offset); // do the receiver + do_parameters_on(this); } }; @@ -915,7 +918,7 @@ void frame::oops_code_blob_do(OopClosure* f, CodeBlobClosure* cf, const Register cf->do_code_blob(_cb); } -class CompiledArgumentOopFinder: public SignatureInfo { +class CompiledArgumentOopFinder: public SignatureIterator { protected: OopClosure* _f; int _offset; // the current offset, incremented with each argument @@ -926,9 +929,10 @@ class CompiledArgumentOopFinder: public SignatureInfo { int _arg_size; VMRegPair* _regs; // VMReg list of arguments - void set(int size, BasicType type) { - if (is_reference_type(type)) handle_oop_offset(); - _offset += size; + friend class SignatureIterator; // so do_parameters_on can call do_type + void do_type(BasicType type) { + if (is_reference_type(type)) handle_oop_offset(); + _offset += parameter_type_word_count(type); } virtual void handle_oop_offset() { @@ -940,8 +944,8 @@ class CompiledArgumentOopFinder: public SignatureInfo { } public: - CompiledArgumentOopFinder(Symbol* signature, bool has_receiver, bool has_appendix, OopClosure* f, frame fr, const RegisterMap* reg_map) - : SignatureInfo(signature) { + CompiledArgumentOopFinder(Symbol* signature, bool has_receiver, bool has_appendix, OopClosure* f, frame fr, const RegisterMap* reg_map) + : SignatureIterator(signature) { // initialize CompiledArgumentOopFinder _f = f; @@ -962,7 +966,7 @@ class CompiledArgumentOopFinder: public SignatureInfo { handle_oop_offset(); _offset++; } - iterate_parameters(); + do_parameters_on(this); if (_has_appendix) { handle_oop_offset(); _offset++; diff --git a/src/hotspot/share/runtime/javaCalls.cpp b/src/hotspot/share/runtime/javaCalls.cpp index 39059f5655f..2733fe180e4 100644 --- a/src/hotspot/share/runtime/javaCalls.cpp +++ b/src/hotspot/share/runtime/javaCalls.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -521,8 +521,6 @@ class SignatureChekker : public SignatureIterator { intptr_t* _value; public: - bool _is_return; - SignatureChekker(Symbol* signature, BasicType return_type, bool is_static, @@ -532,17 +530,19 @@ class SignatureChekker : public SignatureIterator { _pos(0), _return_type(return_type), _value_state(value_state), - _value(value), - _is_return(false) + _value(value) { if (!is_static) { check_value(true); // Receiver must be an oop } + do_parameters_on(this); + check_return_type(return_type); } - void check_value(bool type) { + private: + void check_value(bool is_reference) { uint state = _value_state[_pos++]; - if (type) { + if (is_reference) { guarantee(is_value_state_indirect_oop(state), "signature does not match pushed arguments: %u at %d", state, _pos - 1); @@ -553,38 +553,20 @@ class SignatureChekker : public SignatureIterator { } } - void check_doing_return(bool state) { _is_return = state; } - void check_return_type(BasicType t) { - guarantee(_is_return && t == _return_type, "return type does not match"); + guarantee(t == _return_type, "return type does not match"); } - void check_int(BasicType t) { - if (_is_return) { - check_return_type(t); - return; - } + void check_single_word() { check_value(false); } - void check_double(BasicType t) { check_long(t); } - - void check_long(BasicType t) { - if (_is_return) { - check_return_type(t); - return; - } - + void check_double_word() { check_value(false); check_value(false); } - void check_obj(BasicType t) { - if (_is_return) { - check_return_type(t); - return; - } - + void check_reference() { intptr_t v = _value[_pos]; if (v != 0) { // v is a "handle" referring to an oop, cast to integral type. @@ -601,17 +583,26 @@ class SignatureChekker : public SignatureIterator { check_value(true); // Verify value state. } - void do_bool() { check_int(T_BOOLEAN); } - void do_char() { check_int(T_CHAR); } - void do_float() { check_int(T_FLOAT); } - void do_double() { check_double(T_DOUBLE); } - void do_byte() { check_int(T_BYTE); } - void do_short() { check_int(T_SHORT); } - void do_int() { check_int(T_INT); } - void do_long() { check_long(T_LONG); } - void do_void() { check_return_type(T_VOID); } - void do_object(int begin, int end) { check_obj(T_OBJECT); } - void do_array(int begin, int end) { check_obj(T_OBJECT); } + friend class SignatureIterator; // so do_parameters_on can call do_type + void do_type(BasicType type) { + switch (type) { + case T_BYTE: + case T_BOOLEAN: + case T_CHAR: + case T_SHORT: + case T_INT: + case T_FLOAT: // this one also + check_single_word(); break; + case T_LONG: + case T_DOUBLE: + check_double_word(); break; + case T_ARRAY: + case T_OBJECT: + check_reference(); break; + default: + ShouldNotReachHere(); + } + } }; @@ -629,7 +620,4 @@ void JavaCallArguments::verify(const methodHandle& method, BasicType return_type method->is_static(), _value_state, _value); - sc.iterate_parameters(); - sc.check_doing_return(true); - sc.iterate_returntype(); } diff --git a/src/hotspot/share/runtime/reflection.cpp b/src/hotspot/share/runtime/reflection.cpp index 0222dafe7f9..c5dd89ee162 100644 --- a/src/hotspot/share/runtime/reflection.cpp +++ b/src/hotspot/share/runtime/reflection.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -808,8 +808,9 @@ static objArrayHandle get_exception_types(const methodHandle& method, TRAPS) { } static Handle new_type(Symbol* signature, Klass* k, TRAPS) { + SignatureStream ss(signature, false); // Basic types - BasicType type = vmSymbols::signature_type(signature); + BasicType type = ss.is_reference() ? T_OBJECT : ss.type(); if (type != T_OBJECT) { return Handle(THREAD, Universe::java_mirror(type)); } diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 6e80ac6c03d..227b6c84994 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2979,9 +2979,6 @@ VMReg SharedRuntime::name_for_receiver() { VMRegPair *SharedRuntime::find_callee_arguments(Symbol* sig, bool has_receiver, bool has_appendix, int* arg_size) { // This method is returning a data structure allocating as a // ResourceObject, so do not put any ResourceMarks in here. - char *s = sig->as_C_string(); - int len = (int)strlen(s); - s++; len--; // Skip opening paren BasicType *sig_bt = NEW_RESOURCE_ARRAY(BasicType, 256); VMRegPair *regs = NEW_RESOURCE_ARRAY(VMRegPair, 256); @@ -2990,33 +2987,11 @@ VMRegPair *SharedRuntime::find_callee_arguments(Symbol* sig, bool has_receiver, sig_bt[cnt++] = T_OBJECT; // Receiver is argument 0; not in signature } - while (*s != JVM_SIGNATURE_ENDFUNC) { // Find closing right paren - switch (*s++) { // Switch on signature character - case JVM_SIGNATURE_BYTE: sig_bt[cnt++] = T_BYTE; break; - case JVM_SIGNATURE_CHAR: sig_bt[cnt++] = T_CHAR; break; - case JVM_SIGNATURE_DOUBLE: sig_bt[cnt++] = T_DOUBLE; sig_bt[cnt++] = T_VOID; break; - case JVM_SIGNATURE_FLOAT: sig_bt[cnt++] = T_FLOAT; break; - case JVM_SIGNATURE_INT: sig_bt[cnt++] = T_INT; break; - case JVM_SIGNATURE_LONG: sig_bt[cnt++] = T_LONG; sig_bt[cnt++] = T_VOID; break; - case JVM_SIGNATURE_SHORT: sig_bt[cnt++] = T_SHORT; break; - case JVM_SIGNATURE_BOOLEAN: sig_bt[cnt++] = T_BOOLEAN; break; - case JVM_SIGNATURE_VOID: sig_bt[cnt++] = T_VOID; break; - case JVM_SIGNATURE_CLASS: // Oop - while (*s++ != JVM_SIGNATURE_ENDCLASS); // Skip signature - sig_bt[cnt++] = T_OBJECT; - break; - case JVM_SIGNATURE_ARRAY: { // Array - do { // Skip optional size - while (*s >= '0' && *s <= '9') s++; - } while (*s++ == JVM_SIGNATURE_ARRAY); // Nested arrays? - // Skip element type - if (s[-1] == JVM_SIGNATURE_CLASS) - while (*s++ != JVM_SIGNATURE_ENDCLASS); // Skip signature - sig_bt[cnt++] = T_ARRAY; - break; - } - default : ShouldNotReachHere(); - } + for (SignatureStream ss(sig); !ss.at_return_type(); ss.next()) { + BasicType type = ss.type(); + sig_bt[cnt++] = type; + if (is_double_word_type(type)) + sig_bt[cnt++] = T_VOID; } if (has_appendix) { diff --git a/src/hotspot/share/runtime/signature.cpp b/src/hotspot/share/runtime/signature.cpp index e5875a159fa..c23cdfd73de 100644 --- a/src/hotspot/share/runtime/signature.cpp +++ b/src/hotspot/share/runtime/signature.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,9 @@ #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" #include "oops/typeArrayKlass.hpp" +#include "runtime/fieldDescriptor.inline.hpp" +#include "runtime/handles.inline.hpp" +#include "runtime/safepointVerifiers.hpp" #include "runtime/signature.hpp" // Implementation of SignatureIterator @@ -44,232 +47,154 @@ // FieldType = "B" | "C" | "D" | "F" | "I" | "J" | "S" | "Z" | "L" ClassName ";" | "[" FieldType. // ClassName = string. +// The ClassName string can be any JVM-style UTF8 string except: +// - an empty string (the empty string is never a name of any kind) +// - a string which begins or ends with slash '/' (the package separator) +// - a string which contains adjacent slashes '//' (no empty package names) +// - a string which contains a semicolon ';' (the end-delimiter) +// - a string which contains a left bracket '[' (the array marker) +// - a string which contains a dot '.' (the external package separator) +// +// Other "meta-looking" characters, such as '(' and '<' and '+', +// are perfectly legitimate within a class name, for the JVM. +// Class names which contain double slashes ('a//b') and non-initial +// brackets ('a[b]') are reserved for possible enrichment of the +// type language. + +void SignatureIterator::set_fingerprint(fingerprint_t fingerprint) { + if (!fp_is_valid(fingerprint)) { + _fingerprint = fingerprint; + _return_type = T_ILLEGAL; + } else if (fingerprint != _fingerprint) { + assert(_fingerprint == zero_fingerprint(), "consistent fingerprint values"); + _fingerprint = fingerprint; + _return_type = fp_return_type(fingerprint); + } +} -SignatureIterator::SignatureIterator(Symbol* signature) { - _signature = signature; - _parameter_index = 0; +BasicType SignatureIterator::return_type() { + if (_return_type == T_ILLEGAL) { + SignatureStream ss(_signature); + ss.skip_to_return_type(); + _return_type = ss.type(); + assert(_return_type != T_ILLEGAL, "illegal return type"); + } + return _return_type; } -void SignatureIterator::expect(char c) { - if (_signature->char_at(_index) != c) fatal("expecting %c", c); - _index++; +bool SignatureIterator::fp_is_valid_type(BasicType type, bool for_return_type) { + assert(type != (BasicType)fp_parameters_done, "fingerprint is incorrectly at done"); + assert(((int)type & ~fp_parameter_feature_mask) == 0, "fingerprint feature mask yielded non-zero value"); + return (is_java_primitive(type) || + is_reference_type(type) || + (for_return_type && type == T_VOID)); } -int SignatureIterator::parse_type() { - // Note: This function could be simplified by using "return T_XXX_size;" - // instead of the assignment and the break statements. However, it - // seems that the product build for win32_i486 with MS VC++ 6.0 doesn't - // work (stack underflow for some tests) - this seems to be a VC++ 6.0 - // compiler bug (was problem - gri 4/27/2000). - int size = -1; - switch(_signature->char_at(_index)) { - case JVM_SIGNATURE_BYTE: do_byte(); if (_parameter_index < 0 ) _return_type = T_BYTE; - _index++; size = T_BYTE_size; break; - case JVM_SIGNATURE_CHAR: do_char(); if (_parameter_index < 0 ) _return_type = T_CHAR; - _index++; size = T_CHAR_size; break; - case JVM_SIGNATURE_DOUBLE: do_double(); if (_parameter_index < 0 ) _return_type = T_DOUBLE; - _index++; size = T_DOUBLE_size; break; - case JVM_SIGNATURE_FLOAT: do_float(); if (_parameter_index < 0 ) _return_type = T_FLOAT; - _index++; size = T_FLOAT_size; break; - case JVM_SIGNATURE_INT: do_int(); if (_parameter_index < 0 ) _return_type = T_INT; - _index++; size = T_INT_size; break; - case JVM_SIGNATURE_LONG: do_long(); if (_parameter_index < 0 ) _return_type = T_LONG; - _index++; size = T_LONG_size; break; - case JVM_SIGNATURE_SHORT: do_short(); if (_parameter_index < 0 ) _return_type = T_SHORT; - _index++; size = T_SHORT_size; break; - case JVM_SIGNATURE_BOOLEAN: do_bool(); if (_parameter_index < 0 ) _return_type = T_BOOLEAN; - _index++; size = T_BOOLEAN_size; break; - case JVM_SIGNATURE_VOID: do_void(); if (_parameter_index < 0 ) _return_type = T_VOID; - _index++; size = T_VOID_size; break; - case JVM_SIGNATURE_CLASS: - { int begin = ++_index; - Symbol* sig = _signature; - while (sig->char_at(_index++) != JVM_SIGNATURE_ENDCLASS) ; - do_object(begin, _index); - } - if (_parameter_index < 0 ) _return_type = T_OBJECT; - size = T_OBJECT_size; - break; - case JVM_SIGNATURE_ARRAY: - { int begin = ++_index; - Symbol* sig = _signature; - while (sig->char_at(_index) == JVM_SIGNATURE_ARRAY) { - _index++; - } - if (sig->char_at(_index) == JVM_SIGNATURE_CLASS) { - while (sig->char_at(_index++) != JVM_SIGNATURE_ENDCLASS) ; - } else { - _index++; - } - do_array(begin, _index); - if (_parameter_index < 0 ) _return_type = T_ARRAY; - } - size = T_ARRAY_size; - break; - default: - ShouldNotReachHere(); - break; - } - assert(size >= 0, "size must be set"); - return size; +ArgumentSizeComputer::ArgumentSizeComputer(Symbol* signature) + : SignatureIterator(signature) +{ + _size = 0; + do_parameters_on(this); // non-virtual template execution } +ArgumentCount::ArgumentCount(Symbol* signature) + : SignatureIterator(signature) +{ + _size = 0; + do_parameters_on(this); // non-virtual template execution +} -void SignatureIterator::check_signature_end() { - if (_index < _signature->utf8_length()) { - tty->print_cr("too many chars in signature"); - _signature->print_value_on(tty); - tty->print_cr(" @ %d", _index); - } +ReferenceArgumentCount::ReferenceArgumentCount(Symbol* signature) + : SignatureIterator(signature) +{ + _refs = 0; + do_parameters_on(this); // non-virtual template execution } +void Fingerprinter::compute_fingerprint_and_return_type(bool static_flag) { + // See if we fingerprinted this method already + if (_method != NULL) { + assert(!static_flag, "must not be passed by caller"); + static_flag = _method->is_static(); + _fingerprint = _method->constMethod()->fingerprint(); + + if (_fingerprint != zero_fingerprint()) { + _return_type = _method->result_type(); + assert(is_java_type(_return_type), "return type must be a java type"); + return; + } -void SignatureIterator::iterate_parameters() { - // Parse parameters - _index = 0; - _parameter_index = 0; - expect(JVM_SIGNATURE_FUNC); - while (_signature->char_at(_index) != JVM_SIGNATURE_ENDFUNC) _parameter_index += parse_type(); - expect(JVM_SIGNATURE_ENDFUNC); - _parameter_index = 0; -} + if (_method->size_of_parameters() > fp_max_size_of_parameters) { + _fingerprint = overflow_fingerprint(); + _method->constMethod()->set_fingerprint(_fingerprint); + // as long as we are here compute the return type: + _return_type = ResultTypeFinder(_method->signature()).type(); + assert(is_java_type(_return_type), "return type must be a java type"); + return; + } + } -// Optimized version of iterate_parameters when fingerprint is known -void SignatureIterator::iterate_parameters( uint64_t fingerprint ) { - uint64_t saved_fingerprint = fingerprint; + // Note: This will always take the slow path, since _fp==zero_fp. + initialize_accumulator(); + do_parameters_on(this); + assert(fp_is_valid_type(_return_type, true), "bad result type"); - // Check for too many arguments - if (fingerprint == (uint64_t)CONST64(-1)) { - SignatureIterator::iterate_parameters(); - return; + // Fill in the return type and static bits: + _accumulator |= _return_type << fp_static_feature_size; + if (static_flag) { + _accumulator |= fp_is_static_bit; + } else { + _param_size += 1; // this is the convention for Method::compute_size_of_parameters } - assert(fingerprint, "Fingerprint should not be 0"); - - _parameter_index = 0; - fingerprint = fingerprint >> (static_feature_size + result_feature_size); - while ( 1 ) { - switch ( fingerprint & parameter_feature_mask ) { - case bool_parm: - do_bool(); - _parameter_index += T_BOOLEAN_size; - break; - case byte_parm: - do_byte(); - _parameter_index += T_BYTE_size; - break; - case char_parm: - do_char(); - _parameter_index += T_CHAR_size; - break; - case short_parm: - do_short(); - _parameter_index += T_SHORT_size; - break; - case int_parm: - do_int(); - _parameter_index += T_INT_size; - break; - case obj_parm: - do_object(0, 0); - _parameter_index += T_OBJECT_size; - break; - case long_parm: - do_long(); - _parameter_index += T_LONG_size; - break; - case float_parm: - do_float(); - _parameter_index += T_FLOAT_size; - break; - case double_parm: - do_double(); - _parameter_index += T_DOUBLE_size; - break; - case done_parm: - return; - default: - tty->print_cr("*** parameter is " UINT64_FORMAT, fingerprint & parameter_feature_mask); - tty->print_cr("*** fingerprint is " PTR64_FORMAT, saved_fingerprint); - ShouldNotReachHere(); - break; - } - fingerprint >>= parameter_feature_size; + // Detect overflow. (We counted _param_size correctly.) + if (_method == NULL && _param_size > fp_max_size_of_parameters) { + // We did a one-pass computation of argument size, return type, + // and fingerprint. + _fingerprint = overflow_fingerprint(); + return; } -} + assert(_shift_count < BitsPerLong, + "shift count overflow %d (%d vs. %d): %s", + _shift_count, _param_size, fp_max_size_of_parameters, + _signature->as_C_string()); + assert((_accumulator >> _shift_count) == fp_parameters_done, "must be zero"); -void SignatureIterator::iterate_returntype() { - // Ignore parameters - _index = 0; - expect(JVM_SIGNATURE_FUNC); - Symbol* sig = _signature; - // Need to skip over each type in the signature's argument list until a - // closing ')' is found., then get the return type. We cannot just scan - // for the first ')' because ')' is a legal character in a type name. - while (sig->char_at(_index) != JVM_SIGNATURE_ENDFUNC) { - switch(sig->char_at(_index)) { - case JVM_SIGNATURE_BYTE: - case JVM_SIGNATURE_CHAR: - case JVM_SIGNATURE_DOUBLE: - case JVM_SIGNATURE_FLOAT: - case JVM_SIGNATURE_INT: - case JVM_SIGNATURE_LONG: - case JVM_SIGNATURE_SHORT: - case JVM_SIGNATURE_BOOLEAN: - case JVM_SIGNATURE_VOID: - { - _index++; - } - break; - case JVM_SIGNATURE_CLASS: - { - while (sig->char_at(_index++) != JVM_SIGNATURE_ENDCLASS) ; - } - break; - case JVM_SIGNATURE_ARRAY: - { - while (sig->char_at(++_index) == JVM_SIGNATURE_ARRAY) ; - if (sig->char_at(_index) == JVM_SIGNATURE_CLASS) { - while (sig->char_at(_index++) != JVM_SIGNATURE_ENDCLASS) ; - } else { - _index++; - } - } - break; - default: - ShouldNotReachHere(); - break; - } + // This is the result, along with _return_type: + _fingerprint = _accumulator; + + // Cache the result on the method itself: + if (_method != NULL) { + _method->constMethod()->set_fingerprint(_fingerprint); } - expect(JVM_SIGNATURE_ENDFUNC); - // Parse return type - _parameter_index = -1; - parse_type(); - check_signature_end(); - _parameter_index = 0; } +// Implementation of SignatureStream -void SignatureIterator::iterate() { - // Parse parameters - _parameter_index = 0; - _index = 0; - expect(JVM_SIGNATURE_FUNC); - while (_signature->char_at(_index) != JVM_SIGNATURE_ENDFUNC) _parameter_index += parse_type(); - expect(JVM_SIGNATURE_ENDFUNC); - // Parse return type - _parameter_index = -1; - parse_type(); - check_signature_end(); - _parameter_index = 0; +static inline int decode_signature_char(int ch) { + switch (ch) { +#define EACH_SIG(ch, bt, ignore) \ + case ch: return bt; + SIGNATURE_TYPES_DO(EACH_SIG, ignore) +#undef EACH_SIG + } + return 0; } - -// Implementation of SignatureStream -SignatureStream::SignatureStream(Symbol* signature, bool is_method) : - _signature(signature), _at_return_type(false), _previous_name(NULL), _names(NULL) { - _begin = _end = (is_method ? 1 : 0); // skip first '(' in method signatures +SignatureStream::SignatureStream(const Symbol* signature, + bool is_method) { + assert(!is_method || signature->starts_with(JVM_SIGNATURE_FUNC), + "method signature required"); + _signature = signature; + _limit = signature->utf8_length(); + int oz = (is_method ? 1 : 0); + _state = oz; + assert(_state == (int)(is_method ? _s_method : _s_field), "signature state incorrectly set"); + _begin = _end = oz; // skip first '(' in method signatures + _array_prefix = 0; // just for definiteness + _previous_name = NULL; + _names = NULL; next(); } @@ -279,84 +204,162 @@ SignatureStream::~SignatureStream() { for (int i = 0; i < _names->length(); i++) { _names->at(i)->decrement_refcount(); } + } else if (_previous_name != NULL && !_previous_name->is_permanent()) { + _previous_name->decrement_refcount(); } } -bool SignatureStream::is_done() const { - return _end > _signature->utf8_length(); +inline int SignatureStream::scan_non_primitive(BasicType type) { + const u1* base = _signature->bytes(); + int end = _end; + int limit = _limit; + const u1* tem; + switch (type) { + case T_OBJECT: + tem = (const u1*) memchr(&base[end], JVM_SIGNATURE_ENDCLASS, limit - end); + end = (tem == NULL ? limit : tem+1 - base); + break; + + case T_ARRAY: + while ((end < limit) && ((char)base[end] == JVM_SIGNATURE_ARRAY)) { end++; } + _array_prefix = end - _end; // number of '[' chars just skipped + if (Signature::has_envelope(base[end++])) { + tem = (const u1*) memchr(&base[end], JVM_SIGNATURE_ENDCLASS, limit - end); + end = (tem == NULL ? limit : tem+1 - base); + break; + } + break; + + default : ShouldNotReachHere(); + } + return end; } +void SignatureStream::next() { + const Symbol* sig = _signature; + int len = _limit; + if (_end >= len) { set_done(); return; } + _begin = _end; + int ch = sig->char_at(_begin); + int btcode = decode_signature_char(ch); + if (btcode == 0) { + guarantee(ch == JVM_SIGNATURE_ENDFUNC, "bad signature char %c/%d", ch, ch); + assert(_state == _s_method, "must be in method"); + _state = _s_method_return; + _begin = ++_end; + if (_end >= len) { set_done(); return; } + ch = sig->char_at(_begin); + btcode = decode_signature_char(ch); + } + BasicType bt = (BasicType) btcode; + assert(ch == type2char(bt), "bad signature char %c/%d", ch, ch); + _type = bt; + if (!is_reference_type(bt)) { + // Skip over a single character for a primitive type (or void). + _end++; + return; + } + _end = scan_non_primitive(bt); +} -void SignatureStream::next_non_primitive(int t) { - switch (t) { - case JVM_SIGNATURE_CLASS: { - _type = T_OBJECT; - Symbol* sig = _signature; - while (sig->char_at(_end++) != JVM_SIGNATURE_ENDCLASS); - break; - } - case JVM_SIGNATURE_ARRAY: { - _type = T_ARRAY; - Symbol* sig = _signature; - char c = sig->char_at(_end); - while ('0' <= c && c <= '9') c = sig->char_at(_end++); - while (sig->char_at(_end) == JVM_SIGNATURE_ARRAY) { - _end++; - c = sig->char_at(_end); - while ('0' <= c && c <= '9') c = sig->char_at(_end++); - } - switch(sig->char_at(_end)) { - case JVM_SIGNATURE_BYTE: - case JVM_SIGNATURE_CHAR: - case JVM_SIGNATURE_DOUBLE: - case JVM_SIGNATURE_FLOAT: - case JVM_SIGNATURE_INT: - case JVM_SIGNATURE_LONG: - case JVM_SIGNATURE_SHORT: - case JVM_SIGNATURE_BOOLEAN:_end++; break; - default: { - while (sig->char_at(_end++) != JVM_SIGNATURE_ENDCLASS); - break; - } - } - break; - } - case JVM_SIGNATURE_ENDFUNC: _end++; next(); _at_return_type = true; break; - default : ShouldNotReachHere(); +int SignatureStream::skip_array_prefix(int max_skip_length) { + if (_type != T_ARRAY) { + return 0; + } + if (_array_prefix > max_skip_length) { + // strip some but not all levels of T_ARRAY + _array_prefix -= max_skip_length; + _begin += max_skip_length; + return max_skip_length; } + // we are stripping all levels of T_ARRAY, + // so we must decode the next character + int whole_array_prefix = _array_prefix; + int new_begin = _begin + whole_array_prefix; + _begin = new_begin; + int ch = _signature->char_at(new_begin); + int btcode = decode_signature_char(ch); + BasicType bt = (BasicType) btcode; + assert(ch == type2char(bt), "bad signature char %c/%d", ch, ch); + _type = bt; + assert(bt != T_VOID && bt != T_ARRAY, "bad signature type"); + // Don't bother to call scan_non_primitive, since it won't + // change the value of _end. + return whole_array_prefix; } +bool Signature::is_valid_array_signature(const Symbol* sig) { + assert(sig->utf8_length() > 1, "this should already have been checked"); + assert(sig->char_at(0) == JVM_SIGNATURE_ARRAY, "this should already have been checked"); + // The first character is already checked + int i = 1; + int len = sig->utf8_length(); + // First skip all '['s + while(i < len - 1 && sig->char_at(i) == JVM_SIGNATURE_ARRAY) i++; + + // Check type + switch(sig->char_at(i)) { + case JVM_SIGNATURE_BYTE: + case JVM_SIGNATURE_CHAR: + case JVM_SIGNATURE_DOUBLE: + case JVM_SIGNATURE_FLOAT: + case JVM_SIGNATURE_INT: + case JVM_SIGNATURE_LONG: + case JVM_SIGNATURE_SHORT: + case JVM_SIGNATURE_BOOLEAN: + // If it is an array, the type is the last character + return (i + 1 == len); + case JVM_SIGNATURE_CLASS: + // If it is an object, the last character must be a ';' + return sig->char_at(len - 1) == JVM_SIGNATURE_ENDCLASS; + } + return false; +} -bool SignatureStream::is_object() const { - return _type == T_OBJECT - || _type == T_ARRAY; +BasicType Signature::basic_type(int ch) { + int btcode = decode_signature_char(ch); + if (btcode == 0) return T_ILLEGAL; + return (BasicType) btcode; } -bool SignatureStream::is_array() const { - return _type == T_ARRAY; +static const int jl_len = 10, object_len = 6, jl_object_len = jl_len + object_len; +static const char jl_str[] = "java/lang/"; + +#ifdef ASSERT +static bool signature_symbols_sane() { + static bool done; + if (done) return true; + done = true; + // test some tense code that looks for common symbol names: + assert(vmSymbols::java_lang_Object()->utf8_length() == jl_object_len && + vmSymbols::java_lang_Object()->starts_with(jl_str, jl_len) && + vmSymbols::java_lang_Object()->ends_with("Object", object_len) && + vmSymbols::java_lang_Object()->is_permanent() && + vmSymbols::java_lang_String()->utf8_length() == jl_object_len && + vmSymbols::java_lang_String()->starts_with(jl_str, jl_len) && + vmSymbols::java_lang_String()->ends_with("String", object_len) && + vmSymbols::java_lang_String()->is_permanent(), + "sanity"); + return true; } +#endif //ASSERT -Symbol* SignatureStream::as_symbol() { +// returns a symbol; the caller is responsible for decrementing it +Symbol* SignatureStream::find_symbol() { // Create a symbol from for string _begin _end - int begin = _begin; - int end = _end; - - if ( _signature->char_at(_begin) == JVM_SIGNATURE_CLASS - && _signature->char_at(_end-1) == JVM_SIGNATURE_ENDCLASS) { - begin++; - end--; - } + int begin = raw_symbol_begin(); + int end = raw_symbol_end(); const char* symbol_chars = (const char*)_signature->base() + begin; int len = end - begin; // Quick check for common symbols in signatures - assert((vmSymbols::java_lang_String()->utf8_length() == 16 && vmSymbols::java_lang_Object()->utf8_length() == 16), "sanity"); - if (len == 16 && - strncmp(symbol_chars, "java/lang/", 10) == 0) { - if (strncmp("String", symbol_chars + 10, 6) == 0) { + assert(signature_symbols_sane(), "incorrect signature sanity check"); + if (len == jl_object_len && + memcmp(symbol_chars, jl_str, jl_len) == 0) { + if (memcmp("String", symbol_chars + jl_len, object_len) == 0) { return vmSymbols::java_lang_String(); - } else if (strncmp("Object", symbol_chars + 10, 6) == 0) { + } else if (memcmp("Object", symbol_chars + jl_len, object_len) == 0) { return vmSymbols::java_lang_Object(); } } @@ -369,7 +372,17 @@ Symbol* SignatureStream::as_symbol() { // Save names for cleaning up reference count at the end of // SignatureStream scope. name = SymbolTable::new_symbol(symbol_chars, len); - if (!name->is_permanent()) { + + // Only allocate the GrowableArray for the _names buffer if more than + // one name is being processed in the signature. + if (_previous_name != NULL && + !_previous_name->is_permanent() && + !name->is_permanent() && + _names == NULL) { + _names = new GrowableArray(10); + _names->push(_previous_name); + } + if (!name->is_permanent() && _previous_name != NULL) { if (_names == NULL) { _names = new GrowableArray(10); } @@ -381,57 +394,67 @@ Symbol* SignatureStream::as_symbol() { Klass* SignatureStream::as_klass(Handle class_loader, Handle protection_domain, FailureMode failure_mode, TRAPS) { - if (!is_object()) return NULL; + if (!is_reference()) return NULL; Symbol* name = as_symbol(); + Klass* k = NULL; if (failure_mode == ReturnNull) { - return SystemDictionary::resolve_or_null(name, class_loader, protection_domain, THREAD); + // Note: SD::resolve_or_null returns NULL for most failure modes, + // but not all. Circularity errors, invalid PDs, etc., throw. + k = SystemDictionary::resolve_or_null(name, class_loader, protection_domain, CHECK_NULL); + } else if (failure_mode == CachedOrNull) { + NoSafepointVerifier nsv; // no loading, now, we mean it! + assert(!HAS_PENDING_EXCEPTION, ""); + k = SystemDictionary::find(name, class_loader, protection_domain, CHECK_NULL); + // SD::find does not trigger loading, so there should be no throws + // Still, bad things can happen, so we CHECK_NULL and ask callers + // to do likewise. + return k; } else { + // The only remaining failure mode is NCDFError. + // The test here allows for an additional mode CNFException + // if callers need to request the reflective error instead. bool throw_error = (failure_mode == NCDFError); - return SystemDictionary::resolve_or_fail(name, class_loader, protection_domain, throw_error, THREAD); + k = SystemDictionary::resolve_or_fail(name, class_loader, protection_domain, throw_error, CHECK_NULL); } + + return k; } oop SignatureStream::as_java_mirror(Handle class_loader, Handle protection_domain, FailureMode failure_mode, TRAPS) { - if (!is_object()) + if (!is_reference()) return Universe::java_mirror(type()); Klass* klass = as_klass(class_loader, protection_domain, failure_mode, CHECK_NULL); if (klass == NULL) return NULL; return klass->java_mirror(); } -Symbol* SignatureStream::as_symbol_or_null() { - // Create a symbol from for string _begin _end - ResourceMark rm; - - int begin = _begin; - int end = _end; - - if ( _signature->char_at(_begin) == JVM_SIGNATURE_CLASS - && _signature->char_at(_end-1) == JVM_SIGNATURE_ENDCLASS) { - begin++; - end--; +void SignatureStream::skip_to_return_type() { + while (!at_return_type()) { + next(); } - - char* buffer = NEW_RESOURCE_ARRAY(char, end - begin); - for (int index = begin; index < end; index++) { - buffer[index - begin] = _signature->char_at(index); - } - Symbol* result = SymbolTable::probe(buffer, end - begin); - return result; } -int SignatureStream::reference_parameter_count() { - int args_count = 0; - for ( ; !at_return_type(); next()) { - if (is_object()) { - args_count++; +#ifdef ASSERT + +extern bool signature_constants_sane(); // called from basic_types_init() + +bool signature_constants_sane() { + // for the lookup table, test every 8-bit code point, and then some: + for (int i = -256; i <= 256; i++) { + int btcode = 0; + switch (i) { +#define EACH_SIG(ch, bt, ignore) \ + case ch: { btcode = bt; break; } + SIGNATURE_TYPES_DO(EACH_SIG, ignore) +#undef EACH_SIG } + int btc = decode_signature_char(i); + assert(btc == btcode, "misconfigured table: %d => %d not %d", i, btc, btcode); } - return args_count; + return true; } -#ifdef ASSERT bool SignatureVerifier::is_valid_method_signature(Symbol* sig) { const char* method_sig = (const char*)sig->bytes(); ssize_t len = sig->utf8_length(); @@ -476,8 +499,8 @@ ssize_t SignatureVerifier::is_valid_type(const char* type, ssize_t limit) { switch (type[index]) { case JVM_SIGNATURE_BYTE: case JVM_SIGNATURE_CHAR: - case JVM_SIGNATURE_DOUBLE: case JVM_SIGNATURE_FLOAT: + case JVM_SIGNATURE_DOUBLE: case JVM_SIGNATURE_INT: case JVM_SIGNATURE_LONG: case JVM_SIGNATURE_SHORT: @@ -500,4 +523,5 @@ ssize_t SignatureVerifier::is_valid_type(const char* type, ssize_t limit) { } return -1; } + #endif // ASSERT diff --git a/src/hotspot/share/runtime/signature.hpp b/src/hotspot/share/runtime/signature.hpp index 067e8174f76..4252202b4a1 100644 --- a/src/hotspot/share/runtime/signature.hpp +++ b/src/hotspot/share/runtime/signature.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,102 +25,232 @@ #ifndef SHARE_RUNTIME_SIGNATURE_HPP #define SHARE_RUNTIME_SIGNATURE_HPP +#include "classfile/symbolTable.hpp" #include "memory/allocation.hpp" #include "oops/method.hpp" -// SignatureIterators iterate over a Java signature (or parts of it). -// (Syntax according to: "The Java Virtual Machine Specification" by -// Tim Lindholm & Frank Yellin; section 4.3 Descriptors; p. 89ff.) + +// Static routines and parsing loops for processing field and method +// descriptors. In the HotSpot sources we call them "signatures". +// +// A SignatureStream iterates over a Java descriptor (or parts of it). +// The syntax is documented in the Java Virtual Machine Specification, +// section 4.3. +// +// The syntax may be summarized as follows: +// +// MethodType: '(' {FieldType}* ')' (FieldType | 'V') +// FieldType: PrimitiveType | ObjectType | ArrayType +// PrimitiveType: 'B' | 'C' | 'D' | 'F' | 'I' | 'J' | 'S' | 'Z' +// ObjectType: 'L' ClassName ';' | ArrayType +// ArrayType: '[' FieldType +// ClassName: {UnqualifiedName '/'}* UnqualifiedName +// UnqualifiedName: NameChar {NameChar}* +// NameChar: ANY_CHAR_EXCEPT('/' | '.' | ';' | '[') // -// Example: Iterating over ([Lfoo;D)I using -// 0123456789 +// All of the concrete characters in the above grammar are given +// standard manifest constant names of the form JVM_SIGNATURE_x. +// Executable code uses these constant names in preference to raw +// character constants. Comments and assertion code sometimes use +// the raw character constants for brevity. // -// iterate_parameters() calls: do_array(2, 7); do_double(); -// iterate_returntype() calls: do_int(); -// iterate() calls: do_array(2, 7); do_double(); do_int(); +// The primitive field types (like 'I') correspond 1-1 with type codes +// (like T_INT) which form part of the specification of the 'newarray' +// instruction (JVMS 6.5, section on newarray). These type codes are +// widely used in the HotSpot code. They are joined by ad hoc codes +// like T_OBJECT and T_ARRAY (defined in HotSpot but not in the JVMS) +// so that each "basic type" of field descriptor (or void return type) +// has a corresponding T_x code. Thus, while T_x codes play a very +// minor role in the JVMS, they play a major role in the HotSpot +// sources. There are fewer than 16 such "basic types", so they fit +// nicely into bitfields. // -// is_return_type() is: false ; false ; true +// The syntax of ClassName overlaps slightly with the descriptor +// syntaxes. The strings "I" and "(I)V" are both class names +// *and* descriptors. If a class name contains any character other +// than "BCDFIJSZ()V" it cannot be confused with a descriptor. +// Class names inside of descriptors are always contained in an +// "envelope" syntax which starts with 'L' and ends with ';'. // -// NOTE: The new optimizer has an alternate, for-loop based signature -// iterator implemented in opto/type.cpp, TypeTuple::make(). +// As a confounding factor, array types report their type name strings +// in descriptor format. These name strings are easy to recognize, +// since they begin with '['. For this reason some API points on +// HotSpot look for array descriptors as well as proper class names. +// +// For historical reasons some API points that accept class names and +// array names also look for class names wrapped inside an envelope +// (like "LFoo;") and unwrap them on the fly (to a name like "Foo"). + +class Signature : AllStatic { + private: + static bool is_valid_array_signature(const Symbol* sig); + + public: + + // Returns the basic type of a field signature (or T_VOID for "V"). + // Assumes the signature is a valid field descriptor. + // Do not apply this function to class names or method signatures. + static BasicType basic_type(const Symbol* signature) { + return basic_type(signature->char_at(0)); + } + + // Returns T_ILLEGAL for an illegal signature char. + static BasicType basic_type(int ch); + + // Assuming it is either a class name or signature, + // determine if it in fact cannot be a class name. + // This means it either starts with '[' or ends with ';' + static bool not_class_name(const Symbol* signature) { + return (signature->starts_with(JVM_SIGNATURE_ARRAY) || + signature->ends_with(JVM_SIGNATURE_ENDCLASS)); + } + + // Assuming it is either a class name or signature, + // determine if it in fact is an array descriptor. + static bool is_array(const Symbol* signature) { + return (signature->utf8_length() > 1 && + signature->char_at(0) == JVM_SIGNATURE_ARRAY && + is_valid_array_signature(signature)); + } + + // Assuming it is either a class name or signature, + // determine if it contains a class name plus ';'. + static bool has_envelope(const Symbol* signature) { + return ((signature->utf8_length() > 0) && + signature->ends_with(JVM_SIGNATURE_ENDCLASS) && + has_envelope(signature->char_at(0))); + } + + // Determine if this signature char introduces an + // envelope, which is a class name plus ';'. + static bool has_envelope(char signature_char) { + return (signature_char == JVM_SIGNATURE_CLASS); + } + + // Assuming has_envelope is true, return the symbol + // inside the envelope, by stripping 'L' and ';'. + // Caller is responsible for decrementing the newly created + // Symbol's refcount, use TempNewSymbol. + static Symbol* strip_envelope(const Symbol* signature) { + assert(has_envelope(signature), "precondition"); + return SymbolTable::new_symbol((char*) signature->bytes() + 1, + signature->utf8_length() - 2); + } + + // Assuming it's either a field or method descriptor, determine + // whether it is in fact a method descriptor: + static bool is_method(const Symbol* signature) { + return signature->starts_with(JVM_SIGNATURE_FUNC); + } + + // Assuming it's a method signature, determine if it must + // return void. + static bool is_void_method(const Symbol* signature) { + assert(is_method(signature), "signature is not for a method"); + return signature->ends_with(JVM_SIGNATURE_VOID); + } +}; + +// A SignatureIterator uses a SignatureStream to produce BasicType +// results, discarding class names. This means it can be accelerated +// using a fingerprint mechanism, in many cases, without loss of type +// information. The FingerPrinter class computes and caches this +// reduced information for faster iteration. class SignatureIterator: public ResourceObj { + public: + typedef uint64_t fingerprint_t; + protected: Symbol* _signature; // the signature to iterate over - int _index; // the current character index (only valid during iteration) - int _parameter_index; // the current parameter index (0 outside iteration phase) BasicType _return_type; - - void expect(char c); - int parse_type(); // returns the parameter size in words (0 for void) - void check_signature_end(); + fingerprint_t _fingerprint; public: // Definitions used in generating and iterating the // bit field form of the signature generated by the // Fingerprinter. enum { - static_feature_size = 1, - is_static_bit = 1, - - result_feature_size = 4, - result_feature_mask = 0xF, - parameter_feature_size = 4, - parameter_feature_mask = 0xF, - - bool_parm = 1, - byte_parm = 2, - char_parm = 3, - short_parm = 4, - int_parm = 5, - long_parm = 6, - float_parm = 7, - double_parm = 8, - obj_parm = 9, - done_parm = 10, // marker for end of parameters - - // max parameters is wordsize minus - // The sign bit, termination field, the result and static bit fields - max_size_of_parameters = (BitsPerLong-1 - - result_feature_size - parameter_feature_size - - static_feature_size) / parameter_feature_size + fp_static_feature_size = 1, + fp_is_static_bit = 1, + + fp_result_feature_size = 4, + fp_result_feature_mask = right_n_bits(fp_result_feature_size), + fp_parameter_feature_size = 4, + fp_parameter_feature_mask = right_n_bits(fp_parameter_feature_size), + + fp_parameters_done = 0, // marker for end of parameters (must be zero) + + // Parameters take up full wordsize, minus the result and static bit fields. + // Since fp_parameters_done is zero, termination field arises from shifting + // in zero bits, and therefore occupies no extra space. + // The sentinel value is all-zero-bits, which is impossible for a true + // fingerprint, since at least the result field will be non-zero. + fp_max_size_of_parameters = ((BitsPerLong + - (fp_result_feature_size + fp_static_feature_size)) + / fp_parameter_feature_size) }; + static bool fp_is_valid_type(BasicType type, bool for_return_type = false); + + // Sentinel values are zero and not-zero (-1). + // No need to protect the sign bit, since every valid return type is non-zero + // (even T_VOID), and there are no valid parameter fields which are 0xF (T_VOID). + static fingerprint_t zero_fingerprint() { return (fingerprint_t)0; } + static fingerprint_t overflow_fingerprint() { return ~(fingerprint_t)0; } + static bool fp_is_valid(fingerprint_t fingerprint) { + return (fingerprint != zero_fingerprint()) && (fingerprint != overflow_fingerprint()); + } + // Constructors - SignatureIterator(Symbol* signature); + SignatureIterator(Symbol* signature, fingerprint_t fingerprint = zero_fingerprint()) { + _signature = signature; + _return_type = T_ILLEGAL; // sentinel value for uninitialized + _fingerprint = zero_fingerprint(); + if (fingerprint != _fingerprint) { + set_fingerprint(fingerprint); + } + } + + // If the fingerprint is present, we can use an accelerated loop. + void set_fingerprint(fingerprint_t fingerprint); + + // Returns the set fingerprint, or zero_fingerprint() + // if none has been set already. + fingerprint_t fingerprint() const { return _fingerprint; } // Iteration - void iterate_parameters(); // iterates over parameters only - void iterate_parameters( uint64_t fingerprint ); - void iterate_returntype(); // iterates over returntype only - void iterate(); // iterates over whole signature - // Returns the word index of the current parameter; - int parameter_index() const { return _parameter_index; } - bool is_return_type() const { return parameter_index() < 0; } - BasicType get_ret_type() const { return _return_type; } - - // Basic types - virtual void do_bool () = 0; - virtual void do_char () = 0; - virtual void do_float () = 0; - virtual void do_double() = 0; - virtual void do_byte () = 0; - virtual void do_short () = 0; - virtual void do_int () = 0; - virtual void do_long () = 0; - virtual void do_void () = 0; - - // Object types (begin indexes the first character of the entry, end indexes the first character after the entry) - virtual void do_object(int begin, int end) = 0; - virtual void do_array (int begin, int end) = 0; - - static bool is_static(uint64_t fingerprint) { - assert(fingerprint != (uint64_t)CONST64(-1), "invalid fingerprint"); - return fingerprint & is_static_bit; + // Hey look: There are no virtual methods in this class. + // So how is it customized? By calling do_parameters_on + // an object which answers to "do_type(BasicType)". + // By convention, this object is in the subclass + // itself, so the call is "do_parameters_on(this)". + // The effect of this is to inline the parsing loop + // everywhere "do_parameters_on" is called. + // If there is a valid fingerprint in the object, + // an improved loop is called which just unpacks the + // bitfields from the fingerprint. Otherwise, the + // symbol is parsed. + template inline void do_parameters_on(T* callback); // iterates over parameters only + void skip_parameters(); // skips over parameters to find return type + BasicType return_type(); // computes the value on the fly if necessary + + static bool fp_is_static(fingerprint_t fingerprint) { + assert(fp_is_valid(fingerprint), "invalid fingerprint"); + return fingerprint & fp_is_static_bit; + } + static BasicType fp_return_type(fingerprint_t fingerprint) { + assert(fp_is_valid(fingerprint), "invalid fingerprint"); + return (BasicType) ((fingerprint >> fp_static_feature_size) & fp_result_feature_mask); } - static BasicType return_type(uint64_t fingerprint) { - assert(fingerprint != (uint64_t)CONST64(-1), "invalid fingerprint"); - return (BasicType) ((fingerprint >> static_feature_size) & result_feature_mask); + static fingerprint_t fp_start_parameters(fingerprint_t fingerprint) { + assert(fp_is_valid(fingerprint), "invalid fingerprint"); + return fingerprint >> (fp_static_feature_size + fp_result_feature_size); + } + static BasicType fp_next_parameter(fingerprint_t& mask) { + int result = (mask & fp_parameter_feature_mask); + mask >>= fp_parameter_feature_size; + return (BasicType) result; } }; @@ -131,87 +261,70 @@ class SignatureTypeNames : public SignatureIterator { protected: virtual void type_name(const char* name) = 0; - void do_bool() { type_name("jboolean"); } - void do_char() { type_name("jchar" ); } - void do_float() { type_name("jfloat" ); } - void do_double() { type_name("jdouble" ); } - void do_byte() { type_name("jbyte" ); } - void do_short() { type_name("jshort" ); } - void do_int() { type_name("jint" ); } - void do_long() { type_name("jlong" ); } - void do_void() { type_name("void" ); } - void do_object(int begin, int end) { type_name("jobject" ); } - void do_array (int begin, int end) { type_name("jobject" ); } + friend class SignatureIterator; // so do_parameters_on can call do_type + void do_type(BasicType type) { + switch (type) { + case T_BOOLEAN: type_name("jboolean"); break; + case T_CHAR: type_name("jchar" ); break; + case T_FLOAT: type_name("jfloat" ); break; + case T_DOUBLE: type_name("jdouble" ); break; + case T_BYTE: type_name("jbyte" ); break; + case T_SHORT: type_name("jshort" ); break; + case T_INT: type_name("jint" ); break; + case T_LONG: type_name("jlong" ); break; + case T_VOID: type_name("void" ); break; + case T_ARRAY: + case T_OBJECT: type_name("jobject" ); break; + default: ShouldNotReachHere(); + } + } public: SignatureTypeNames(Symbol* signature) : SignatureIterator(signature) {} }; -class SignatureInfo: public SignatureIterator { - protected: - bool _has_iterated; // need this because iterate cannot be called in constructor (set is virtual!) - bool _has_iterated_return; - int _size; - - void lazy_iterate_parameters() { if (!_has_iterated) { iterate_parameters(); _has_iterated = true; } } - void lazy_iterate_return() { if (!_has_iterated_return) { iterate_returntype(); _has_iterated_return = true; } } - - virtual void set(int size, BasicType type) = 0; - - void do_bool () { set(T_BOOLEAN_size, T_BOOLEAN); } - void do_char () { set(T_CHAR_size , T_CHAR ); } - void do_float () { set(T_FLOAT_size , T_FLOAT ); } - void do_double() { set(T_DOUBLE_size , T_DOUBLE ); } - void do_byte () { set(T_BYTE_size , T_BYTE ); } - void do_short () { set(T_SHORT_size , T_SHORT ); } - void do_int () { set(T_INT_size , T_INT ); } - void do_long () { set(T_LONG_size , T_LONG ); } - void do_void () { set(T_VOID_size , T_VOID ); } - void do_object(int begin, int end) { set(T_OBJECT_size , T_OBJECT ); } - void do_array (int begin, int end) { set(T_ARRAY_size , T_ARRAY ); } +// Specialized SignatureIterator: Used to compute the argument size. +class ArgumentSizeComputer: public SignatureIterator { + private: + int _size; + friend class SignatureIterator; // so do_parameters_on can call do_type + void do_type(BasicType type) { _size += parameter_type_word_count(type); } public: - SignatureInfo(Symbol* signature) : SignatureIterator(signature) { - _has_iterated = _has_iterated_return = false; - _size = 0; - _return_type = T_ILLEGAL; - } - + ArgumentSizeComputer(Symbol* signature); + int size() { return _size; } }; -// Specialized SignatureIterator: Used to compute the argument size. - -class ArgumentSizeComputer: public SignatureInfo { +class ArgumentCount: public SignatureIterator { private: - void set(int size, BasicType type) { _size += size; } + int _size; + friend class SignatureIterator; // so do_parameters_on can call do_type + void do_type(BasicType type) { _size++; } public: - ArgumentSizeComputer(Symbol* signature) : SignatureInfo(signature) {} - - int size() { lazy_iterate_parameters(); return _size; } + ArgumentCount(Symbol* signature); + int size() { return _size; } }; -class ArgumentCount: public SignatureInfo { +class ReferenceArgumentCount: public SignatureIterator { private: - void set(int size, BasicType type) { _size ++; } + int _refs; + friend class SignatureIterator; // so do_parameters_on can call do_type + void do_type(BasicType type) { if (is_reference_type(type)) _refs++; } public: - ArgumentCount(Symbol* signature) : SignatureInfo(signature) {} - - int size() { lazy_iterate_parameters(); return _size; } + ReferenceArgumentCount(Symbol* signature); + int count() { return _refs; } }; // Specialized SignatureIterator: Used to compute the result type. -class ResultTypeFinder: public SignatureInfo { - private: - void set(int size, BasicType type) { _return_type = type; } +class ResultTypeFinder: public SignatureIterator { public: - BasicType type() { lazy_iterate_return(); return _return_type; } - - ResultTypeFinder(Symbol* signature) : SignatureInfo(signature) {} + BasicType type() { return return_type(); } + ResultTypeFinder(Symbol* signature) : SignatureIterator(signature) { } }; @@ -219,52 +332,41 @@ class ResultTypeFinder: public SignatureInfo { // is a bitvector characterizing the methods signature (incl. the receiver). class Fingerprinter: public SignatureIterator { private: - uint64_t _fingerprint; + fingerprint_t _accumulator; + int _param_size; int _shift_count; - methodHandle mh; - - public: + const Method* _method; - void do_bool() { _fingerprint |= (((uint64_t)bool_parm) << _shift_count); _shift_count += parameter_feature_size; } - void do_char() { _fingerprint |= (((uint64_t)char_parm) << _shift_count); _shift_count += parameter_feature_size; } - void do_byte() { _fingerprint |= (((uint64_t)byte_parm) << _shift_count); _shift_count += parameter_feature_size; } - void do_short() { _fingerprint |= (((uint64_t)short_parm) << _shift_count); _shift_count += parameter_feature_size; } - void do_int() { _fingerprint |= (((uint64_t)int_parm) << _shift_count); _shift_count += parameter_feature_size; } - void do_long() { _fingerprint |= (((uint64_t)long_parm) << _shift_count); _shift_count += parameter_feature_size; } - void do_float() { _fingerprint |= (((uint64_t)float_parm) << _shift_count); _shift_count += parameter_feature_size; } - void do_double() { _fingerprint |= (((uint64_t)double_parm) << _shift_count); _shift_count += parameter_feature_size; } - - void do_object(int begin, int end) { _fingerprint |= (((uint64_t)obj_parm) << _shift_count); _shift_count += parameter_feature_size; } - void do_array (int begin, int end) { _fingerprint |= (((uint64_t)obj_parm) << _shift_count); _shift_count += parameter_feature_size; } + void initialize_accumulator() { + _accumulator = 0; + _shift_count = fp_result_feature_size + fp_static_feature_size; + _param_size = 0; + } - void do_void() { ShouldNotReachHere(); } + // Out-of-line method does it all in constructor: + void compute_fingerprint_and_return_type(bool static_flag = false); - Fingerprinter(const methodHandle& method) : SignatureIterator(method->signature()) { - mh = method; - _fingerprint = 0; + friend class SignatureIterator; // so do_parameters_on can call do_type + void do_type(BasicType type) { + assert(fp_is_valid_type(type), "bad parameter type"); + _accumulator |= ((fingerprint_t)type << _shift_count); + _shift_count += fp_parameter_feature_size; + _param_size += (is_double_word_type(type) ? 2 : 1); } - uint64_t fingerprint() { - // See if we fingerprinted this method already - if (mh->constMethod()->fingerprint() != CONST64(0)) { - return mh->constMethod()->fingerprint(); - } - - if (mh->size_of_parameters() > max_size_of_parameters ) { - _fingerprint = (uint64_t)CONST64(-1); - mh->constMethod()->set_fingerprint(_fingerprint); - return _fingerprint; - } + public: + int size_of_parameters() const { return _param_size; } + // fingerprint() and return_type() are in super class - assert( (int)mh->result_type() <= (int)result_feature_mask, "bad result type"); - _fingerprint = mh->result_type(); - _fingerprint <<= static_feature_size; - if (mh->is_static()) _fingerprint |= 1; - _shift_count = result_feature_size + static_feature_size; - iterate_parameters(); - _fingerprint |= ((uint64_t)done_parm) << _shift_count;// mark end of sig - mh->constMethod()->set_fingerprint(_fingerprint); - return _fingerprint; + Fingerprinter(const methodHandle& method) + : SignatureIterator(method->signature()), + _method(method()) { + compute_fingerprint_and_return_type(); + } + Fingerprinter(Symbol* signature, bool is_static) + : SignatureIterator(signature), + _method(NULL) { + compute_fingerprint_and_return_type(is_static); } }; @@ -281,35 +383,46 @@ class NativeSignatureIterator: public SignatureIterator { int _prepended; // number of prepended JNI parameters (1 JNIEnv, plus 1 mirror if static) int _jni_offset; // the current parameter offset, starting with 0 - void do_bool () { pass_int(); _jni_offset++; _offset++; } - void do_char () { pass_int(); _jni_offset++; _offset++; } - void do_float () { pass_float(); _jni_offset++; _offset++; } -#ifdef _LP64 - void do_double() { pass_double(); _jni_offset++; _offset += 2; } -#else - void do_double() { pass_double(); _jni_offset += 2; _offset += 2; } -#endif - void do_byte () { pass_int(); _jni_offset++; _offset++; } - void do_short () { pass_int(); _jni_offset++; _offset++; } - void do_int () { pass_int(); _jni_offset++; _offset++; } -#ifdef _LP64 - void do_long () { pass_long(); _jni_offset++; _offset += 2; } -#else - void do_long () { pass_long(); _jni_offset += 2; _offset += 2; } -#endif - void do_void () { ShouldNotReachHere(); } - void do_object(int begin, int end) { pass_object(); _jni_offset++; _offset++; } - void do_array (int begin, int end) { pass_object(); _jni_offset++; _offset++; } + friend class SignatureIterator; // so do_parameters_on can call do_type + void do_type(BasicType type) { + switch (type) { + case T_BYTE: + case T_SHORT: + case T_INT: + case T_BOOLEAN: + case T_CHAR: + pass_int(); _jni_offset++; _offset++; + break; + case T_FLOAT: + pass_float(); _jni_offset++; _offset++; + break; + case T_DOUBLE: { + int jni_offset = LP64_ONLY(1) NOT_LP64(2); + pass_double(); _jni_offset += jni_offset; _offset += 2; + break; + } + case T_LONG: { + int jni_offset = LP64_ONLY(1) NOT_LP64(2); + pass_long(); _jni_offset += jni_offset; _offset += 2; + break; + } + case T_ARRAY: + case T_OBJECT: + pass_object(); _jni_offset++; _offset++; + break; + default: + ShouldNotReachHere(); + } + } public: methodHandle method() const { return _method; } int offset() const { return _offset; } int jni_offset() const { return _jni_offset + _prepended; } -// int java_offset() const { return method()->size_of_parameters() - _offset - 1; } bool is_static() const { return method()->is_static(); } virtual void pass_int() = 0; virtual void pass_long() = 0; - virtual void pass_object() = 0; + virtual void pass_object() = 0; // objects, arrays, inlines virtual void pass_float() = 0; #ifdef _LP64 virtual void pass_double() = 0; @@ -327,7 +440,9 @@ class NativeSignatureIterator: public SignatureIterator { _prepended = !is_static() ? JNIEnv_words : JNIEnv_words + mirror_words; } - // iterate() calles the 2 virtual methods according to the following invocation syntax: + void iterate() { iterate(Fingerprinter(method()).fingerprint()); } + + // iterate() calls the 3 virtual methods according to the following invocation syntax: // // {pass_int | pass_long | pass_object} // @@ -335,87 +450,132 @@ class NativeSignatureIterator: public SignatureIterator { // The offset() values refer to the Java stack offsets but are 0 based and increasing. // The java_offset() values count down to 0, and refer to the Java TOS. // The jni_offset() values increase from 1 or 2, and refer to C arguments. + // The method's return type is ignored. - void iterate() { iterate(Fingerprinter(method()).fingerprint()); - } - - - // Optimized path if we have the bitvector form of signature - void iterate( uint64_t fingerprint ) { - + void iterate(fingerprint_t fingerprint) { + set_fingerprint(fingerprint); if (!is_static()) { // handle receiver (not handled by iterate because not in signature) pass_object(); _jni_offset++; _offset++; } - - SignatureIterator::iterate_parameters( fingerprint ); + do_parameters_on(this); } }; -// Handy stream for iterating over signature +// This is the core parsing logic for iterating over signatures. +// All of the previous classes use this for doing their work. class SignatureStream : public StackObj { private: - Symbol* _signature; + const Symbol* _signature; int _begin; int _end; + int _limit; + int _array_prefix; // count of '[' before the array element descr BasicType _type; - bool _at_return_type; - Symbol* _previous_name; // cache the previously looked up symbol to avoid lookups - GrowableArray* _names; // symbols created while parsing that need to be dereferenced - public: - bool at_return_type() const { return _at_return_type; } - bool is_done() const; - void next_non_primitive(int t); - void next() { - Symbol* sig = _signature; - int len = sig->utf8_length(); - if (_end >= len) { - _end = len + 1; - return; - } + int _state; + Symbol* _previous_name; // cache the previously looked up symbol to avoid lookups + GrowableArray* _names; // symbols created while parsing that need to be dereferenced - _begin = _end; - int t = sig->char_at(_begin); - switch (t) { - case JVM_SIGNATURE_BYTE: _type = T_BYTE; break; - case JVM_SIGNATURE_CHAR: _type = T_CHAR; break; - case JVM_SIGNATURE_DOUBLE: _type = T_DOUBLE; break; - case JVM_SIGNATURE_FLOAT: _type = T_FLOAT; break; - case JVM_SIGNATURE_INT: _type = T_INT; break; - case JVM_SIGNATURE_LONG: _type = T_LONG; break; - case JVM_SIGNATURE_SHORT: _type = T_SHORT; break; - case JVM_SIGNATURE_BOOLEAN: _type = T_BOOLEAN; break; - case JVM_SIGNATURE_VOID: _type = T_VOID; break; - default : next_non_primitive(t); - return; - } - _end++; + inline int scan_non_primitive(BasicType type); + + Symbol* find_symbol(); + + enum { _s_field = 0, _s_method = 1, _s_method_return = 3 }; + void set_done() { + _state |= -2; // preserve s_method bit + assert(is_done(), "Unable to set state to done"); } - SignatureStream(Symbol* signature, bool is_method = true); + public: + bool is_method_signature() const { return (_state & (int)_s_method) != 0; } + bool at_return_type() const { return _state == (int)_s_method_return; } + bool is_done() const { return _state < 0; } + void next(); + + SignatureStream(const Symbol* signature, bool is_method = true); ~SignatureStream(); - bool is_object() const; // True if this argument is an object - bool is_array() const; // True if this argument is an array - BasicType type() const { return _type; } - Symbol* as_symbol(); - enum FailureMode { ReturnNull, NCDFError }; - Klass* as_klass(Handle class_loader, Handle protection_domain, FailureMode failure_mode, TRAPS); - oop as_java_mirror(Handle class_loader, Handle protection_domain, FailureMode failure_mode, TRAPS); - const u1* raw_bytes() { return _signature->bytes() + _begin; } - int raw_length() { return _end - _begin; } + bool is_reference() const { return is_reference_type(_type); } + bool is_array() const { return _type == T_ARRAY; } + bool is_primitive() const { return is_java_primitive(_type); } + BasicType type() const { return _type; } + + const u1* raw_bytes() const { return _signature->bytes() + _begin; } + int raw_length() const { return _end - _begin; } + int raw_begin() const { return _begin; } + int raw_end() const { return _end; } + int raw_symbol_begin() const { return _begin + (has_envelope() ? 1 : 0); } + int raw_symbol_end() const { return _end - (has_envelope() ? 1 : 0); } + char raw_char_at(int i) const { + assert(i < _limit, "index for raw_char_at is over the limit"); + return _signature->char_at(i); + } - // return same as_symbol except allocation of new symbols is avoided. - Symbol* as_symbol_or_null(); + // True if there is an embedded class name in this type, + // followed by ';'. + bool has_envelope() const { + if (!Signature::has_envelope(_signature->char_at(_begin))) + return false; + // this should always be true, but let's test it: + assert(_signature->char_at(_end-1) == JVM_SIGNATURE_ENDCLASS, "signature envelope has no semi-colon at end"); + return true; + } - // count the number of references in the signature - int reference_parameter_count(); + // return the symbol for chars in symbol_begin()..symbol_end() + Symbol* as_symbol() { + return find_symbol(); + } + + // in case you want only the return type: + void skip_to_return_type(); + + // number of '[' in array prefix + int array_prefix_length() { + return _type == T_ARRAY ? _array_prefix : 0; + } + + // In case you want only the array base type, + // reset the stream after skipping some brackets '['. + // (The argument is clipped to array_prefix_length(), + // and if it ends up as zero this call is a nop. + // The default is value skips all brackets '['.) + int skip_array_prefix(int prefix_length = 9999); + + // free-standing lookups (bring your own CL/PD pair) + enum FailureMode { ReturnNull, NCDFError, CachedOrNull }; + Klass* as_klass(Handle class_loader, Handle protection_domain, FailureMode failure_mode, TRAPS); + oop as_java_mirror(Handle class_loader, Handle protection_domain, FailureMode failure_mode, TRAPS); }; -#ifdef ASSERT -class SignatureVerifier : public StackObj { +// Here is how all the SignatureIterator classes invoke the +// SignatureStream engine to do their parsing. +template inline +void SignatureIterator::do_parameters_on(T* callback) { + fingerprint_t unaccumulator = _fingerprint; + + // Check for too many arguments, or missing fingerprint: + if (!fp_is_valid(unaccumulator)) { + SignatureStream ss(_signature); + for (; !ss.at_return_type(); ss.next()) { + callback->do_type(ss.type()); + } + // while we are here, capture the return type + _return_type = ss.type(); + } else { + // Optimized version of do_parameters when fingerprint is known + assert(_return_type != T_ILLEGAL, "return type already captured from fp"); + unaccumulator = fp_start_parameters(unaccumulator); + for (BasicType type; (type = fp_next_parameter(unaccumulator)) != (BasicType)fp_parameters_done; ) { + assert(fp_is_valid_type(type), "garbled fingerprint"); + callback->do_type(type); + } + } +} + + #ifdef ASSERT + class SignatureVerifier : public StackObj { public: static bool is_valid_method_signature(Symbol* sig); static bool is_valid_type_signature(Symbol* sig); diff --git a/src/hotspot/share/utilities/globalDefinitions.cpp b/src/hotspot/share/utilities/globalDefinitions.cpp index 54ec0b55efb..b9fa8ade4bb 100644 --- a/src/hotspot/share/utilities/globalDefinitions.cpp +++ b/src/hotspot/share/utilities/globalDefinitions.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "runtime/globals.hpp" #include "runtime/os.hpp" +#include "runtime/signature.hpp" #include "utilities/globalDefinitions.hpp" // Basic error support @@ -51,6 +52,20 @@ uint64_t OopEncodingHeapMax = 0; // Something to help porters sleep at night +#ifdef ASSERT +BasicType char2type(int ch) { + switch (ch) { +#define EACH_SIG(ch, bt, ignore) \ + case ch: return bt; + SIGNATURE_TYPES_DO(EACH_SIG, ignore) +#undef EACH_SIG + } + return T_ILLEGAL; +} + +extern bool signature_constants_sane(); +#endif //ASSERT + void basic_types_init() { #ifdef ASSERT #ifdef _LP64 @@ -84,10 +99,13 @@ void basic_types_init() { assert(wordSize == BytesPerWord, "should be the same since they're used interchangeably"); assert(wordSize == HeapWordSize, "should be the same since they're also used interchangeably"); + assert(signature_constants_sane(), ""); + int num_type_chars = 0; for (int i = 0; i < 99; i++) { if (type2char((BasicType)i) != 0) { assert(char2type(type2char((BasicType)i)) == i, "proper inverses"); + assert(Signature::basic_type(type2char((BasicType)i)) == i, "proper inverses"); num_type_chars++; } } diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp index 6bdbd789b48..d27c4b6c674 100644 --- a/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/src/hotspot/share/utilities/globalDefinitions.hpp @@ -625,6 +625,24 @@ enum BasicType { T_ILLEGAL = 99 }; +#define SIGNATURE_TYPES_DO(F, N) \ + F(JVM_SIGNATURE_BOOLEAN, T_BOOLEAN, N) \ + F(JVM_SIGNATURE_CHAR, T_CHAR, N) \ + F(JVM_SIGNATURE_FLOAT, T_FLOAT, N) \ + F(JVM_SIGNATURE_DOUBLE, T_DOUBLE, N) \ + F(JVM_SIGNATURE_BYTE, T_BYTE, N) \ + F(JVM_SIGNATURE_SHORT, T_SHORT, N) \ + F(JVM_SIGNATURE_INT, T_INT, N) \ + F(JVM_SIGNATURE_LONG, T_LONG, N) \ + F(JVM_SIGNATURE_CLASS, T_OBJECT, N) \ + F(JVM_SIGNATURE_ARRAY, T_ARRAY, N) \ + F(JVM_SIGNATURE_VOID, T_VOID, N) \ + /*end*/ + +inline bool is_java_type(BasicType t) { + return T_BOOLEAN <= t && t <= T_VOID; +} + inline bool is_java_primitive(BasicType t) { return T_BOOLEAN <= t && t <= T_LONG; } @@ -646,24 +664,6 @@ inline bool is_reference_type(BasicType t) { return (t == T_OBJECT || t == T_ARRAY); } -// Convert a char from a classfile signature to a BasicType -inline BasicType char2type(char c) { - switch( c ) { - case JVM_SIGNATURE_BYTE: return T_BYTE; - case JVM_SIGNATURE_CHAR: return T_CHAR; - case JVM_SIGNATURE_DOUBLE: return T_DOUBLE; - case JVM_SIGNATURE_FLOAT: return T_FLOAT; - case JVM_SIGNATURE_INT: return T_INT; - case JVM_SIGNATURE_LONG: return T_LONG; - case JVM_SIGNATURE_SHORT: return T_SHORT; - case JVM_SIGNATURE_BOOLEAN: return T_BOOLEAN; - case JVM_SIGNATURE_VOID: return T_VOID; - case JVM_SIGNATURE_CLASS: return T_OBJECT; - case JVM_SIGNATURE_ARRAY: return T_ARRAY; - } - return T_ILLEGAL; -} - extern char type2char_tab[T_CONFLICT+1]; // Map a BasicType to a jchar inline char type2char(BasicType t) { return (uint)t < T_CONFLICT+1 ? type2char_tab[t] : 0; } extern int type2size[T_CONFLICT+1]; // Map BasicType to result stack elements @@ -693,6 +693,13 @@ enum BasicTypeSize { T_VOID_size = 0 }; +// this works on valid parameter types but not T_VOID, T_CONFLICT, etc. +inline int parameter_type_word_count(BasicType t) { + if (is_double_word_type(t)) return 2; + assert(is_java_primitive(t) || is_reference_type(t), "no goofy types here please"); + assert(type2size[t] == 1, "must be"); + return 1; +} // maps a BasicType to its instance field storage type: // all sub-word integral types are widened to T_INT