annotate anno-stable-8001107.patch @ 516:4cd7d914b0e3

rebase to current hsx/hotspot-comp
author jrose
date Sun, 06 Oct 2013 23:32:13 -0700
parents 37735140b62a
children
rev   line source
jrose@508 1 8001107: @Stable annotation for constant folding of lazily evaluated variables
jrose@502 2
jrose@504 3 diff --git a/src/share/vm/ci/ciArray.cpp b/src/share/vm/ci/ciArray.cpp
jrose@504 4 --- a/src/share/vm/ci/ciArray.cpp
jrose@504 5 +++ b/src/share/vm/ci/ciArray.cpp
jrose@504 6 @@ -26,12 +26,102 @@
jrose@504 7 #include "ci/ciArray.hpp"
jrose@504 8 #include "ci/ciKlass.hpp"
jrose@504 9 #include "ci/ciUtilities.hpp"
jrose@504 10 +#include "oops/objArrayOop.hpp"
jrose@504 11 +#include "oops/typeArrayOop.hpp"
jrose@504 12
jrose@504 13 // ciArray
jrose@504 14 //
jrose@504 15 // This class represents an arrayOop in the HotSpot virtual
jrose@504 16 // machine.
jrose@504 17
jrose@504 18 +ciArrayKlass* ciArray::array_type() {
jrose@504 19 + return klass()->as_array_klass();
jrose@504 20 +}
jrose@504 21 +
jrose@504 22 +ciType* ciArray::element_type() {
jrose@504 23 + return array_type()->element_type();
jrose@504 24 +}
jrose@504 25 +
jrose@504 26 +BasicType ciArray::element_basic_type() {
jrose@504 27 + return element_type()->basic_type();
jrose@504 28 +}
jrose@504 29 +
jrose@504 30 +static BasicType fixup_element_type(BasicType bt) {
jrose@504 31 + if (bt == T_ARRAY) return T_OBJECT;
jrose@504 32 + if (bt == T_BOOLEAN) return T_BYTE;
jrose@504 33 + return bt;
jrose@504 34 +}
jrose@504 35 +
jrose@504 36 +ciConstant ciArray::element_value_impl(BasicType elembt,
jrose@504 37 + arrayOop ary,
jrose@504 38 + int index) {
jrose@504 39 + if (ary == NULL)
jrose@504 40 + return ciConstant();
jrose@504 41 + assert(ary->is_array(), "");
jrose@504 42 + if (index < 0 || index >= ary->length())
jrose@504 43 + return ciConstant();
jrose@509 44 + ArrayKlass* ak = (ArrayKlass*) ary->klass();
jrose@504 45 + BasicType abt = ak->element_type();
jrose@504 46 + if (fixup_element_type(elembt) !=
jrose@504 47 + fixup_element_type(abt))
jrose@504 48 + return ciConstant();
jrose@504 49 + switch (elembt) {
jrose@504 50 + case T_ARRAY:
jrose@504 51 + case T_OBJECT:
jrose@504 52 + {
jrose@504 53 + assert(ary->is_objArray(), "");
jrose@504 54 + objArrayOop objary = (objArrayOop) ary;
jrose@504 55 + oop elem = objary->obj_at(index);
jrose@504 56 + ciEnv* env = CURRENT_ENV;
jrose@504 57 + ciObject* box = env->get_object(elem);
jrose@504 58 + return ciConstant(T_OBJECT, box);
jrose@504 59 + }
jrose@504 60 + }
jrose@504 61 + assert(ary->is_typeArray(), "");
jrose@504 62 + typeArrayOop tary = (typeArrayOop) ary;
jrose@504 63 + jint value = 0;
jrose@504 64 + switch (elembt) {
jrose@504 65 + case T_LONG: return ciConstant(tary->long_at(index));
jrose@504 66 + case T_FLOAT: return ciConstant(tary->float_at(index));
jrose@504 67 + case T_DOUBLE: return ciConstant(tary->double_at(index));
jrose@504 68 + default: return ciConstant();
jrose@504 69 + case T_BYTE: value = tary->byte_at(index); break;
jrose@504 70 + case T_BOOLEAN: value = tary->byte_at(index) & 1; break;
jrose@504 71 + case T_SHORT: value = tary->short_at(index); break;
jrose@504 72 + case T_CHAR: value = tary->char_at(index); break;
jrose@504 73 + case T_INT: value = tary->int_at(index); break;
jrose@504 74 + }
jrose@504 75 + return ciConstant(elembt, value);
jrose@504 76 +}
jrose@504 77 +
jrose@504 78 +// ------------------------------------------------------------------
jrose@504 79 +// ciArray::element_value
jrose@504 80 +//
jrose@504 81 +// Current value of an element.
jrose@504 82 +// Returns T_ILLEGAL if there is no element at the given index.
jrose@504 83 +ciConstant ciArray::element_value(int index) {
jrose@504 84 + BasicType elembt = element_basic_type();
jrose@504 85 + GUARDED_VM_ENTRY(
jrose@504 86 + return element_value_impl(elembt, get_arrayOop(), index);
jrose@504 87 + )
jrose@504 88 +}
jrose@504 89 +
jrose@504 90 +// ------------------------------------------------------------------
jrose@504 91 +// ciArray::element_value_by_offset
jrose@504 92 +//
jrose@504 93 +// Current value of an element at the specified offset.
jrose@504 94 +// Returns T_ILLEGAL if there is no element at the given offset.
jrose@504 95 +ciConstant ciArray::element_value_by_offset(intptr_t element_offset) {
jrose@504 96 + BasicType elembt = element_basic_type();
jrose@504 97 + intptr_t shift = exact_log2(type2aelembytes(elembt));
jrose@504 98 + intptr_t header = arrayOopDesc::base_offset_in_bytes(elembt);
jrose@504 99 + intptr_t index = (element_offset - header) >> shift;
jrose@504 100 + intptr_t offset = header + ((intptr_t)index << shift);
jrose@504 101 + if (offset != element_offset || index != (jint)index)
jrose@504 102 + return ciConstant();
jrose@504 103 + return element_value((jint) index);
jrose@504 104 +}
jrose@504 105 +
jrose@504 106 // ------------------------------------------------------------------
jrose@504 107 // ciArray::print_impl
jrose@504 108 //
jrose@504 109 diff --git a/src/share/vm/ci/ciArray.hpp b/src/share/vm/ci/ciArray.hpp
jrose@504 110 --- a/src/share/vm/ci/ciArray.hpp
jrose@504 111 +++ b/src/share/vm/ci/ciArray.hpp
jrose@504 112 @@ -51,9 +51,24 @@
jrose@504 113
jrose@504 114 void print_impl(outputStream* st);
jrose@504 115
jrose@504 116 + ciConstant element_value_impl(BasicType elembt, arrayOop ary, int index);
jrose@504 117 +
jrose@504 118 public:
jrose@504 119 int length() { return _length; }
jrose@504 120
jrose@504 121 + // Convenience routines.
jrose@504 122 + ciArrayKlass* array_type(); // klass()->as_array_klass()
jrose@504 123 + ciType* element_type(); // array_type()->element_type()
jrose@504 124 + BasicType element_basic_type(); // element_type()->basic_type()
jrose@504 125 +
jrose@504 126 + // Current value of an element.
jrose@504 127 + // Returns T_ILLEGAL if there is no element at the given index.
jrose@504 128 + ciConstant element_value(int index);
jrose@504 129 +
jrose@504 130 + // Current value of an element at the specified offset.
jrose@504 131 + // Returns T_ILLEGAL if there is no element at the given offset.
jrose@504 132 + ciConstant element_value_by_offset(intptr_t element_offset);
jrose@504 133 +
jrose@504 134 // What kind of ciObject is this?
jrose@504 135 bool is_array() { return true; }
jrose@504 136 bool is_java_object() { return true; }
jrose@502 137 diff --git a/src/share/vm/ci/ciConstant.hpp b/src/share/vm/ci/ciConstant.hpp
jrose@502 138 --- a/src/share/vm/ci/ciConstant.hpp
jrose@502 139 +++ b/src/share/vm/ci/ciConstant.hpp
jrose@502 140 @@ -41,7 +41,6 @@
jrose@502 141 union {
jrose@502 142 jint _int;
jrose@502 143 jlong _long;
jrose@502 144 - jint _long_half[2];
jrose@502 145 jfloat _float;
jrose@502 146 jdouble _double;
jrose@502 147 ciObject* _object;
jrose@502 148 @@ -111,6 +110,19 @@
jrose@502 149 return _value._object;
jrose@502 150 }
jrose@502 151
jrose@502 152 + bool is_null_or_zero() const {
jrose@502 153 + if (!is_java_primitive(basic_type()))
jrose@502 154 + return as_object()->is_null_object();
jrose@502 155 + else if (type2size[basic_type()] == 1)
jrose@502 156 + // treat float bits as int, to avoid comparison with -0 and NaN
jrose@502 157 + return (_value._int == 0);
jrose@502 158 + else if (type2size[basic_type()] == 2)
jrose@502 159 + // treat double bits as long, to avoid comparison with -0 and NaN
jrose@502 160 + return (_value._long == 0);
jrose@502 161 + else
jrose@502 162 + return false;
jrose@502 163 + }
jrose@502 164 +
jrose@502 165 // Debugging output
jrose@502 166 void print();
jrose@502 167 };
jrose@502 168 diff --git a/src/share/vm/ci/ciField.cpp b/src/share/vm/ci/ciField.cpp
jrose@502 169 --- a/src/share/vm/ci/ciField.cpp
jrose@502 170 +++ b/src/share/vm/ci/ciField.cpp
jrose@502 171 @@ -189,12 +189,14 @@
jrose@502 172 _holder = CURRENT_ENV->get_instance_klass(fd->field_holder());
jrose@502 173
jrose@502 174 // Check to see if the field is constant.
jrose@502 175 - if (_holder->is_initialized() && this->is_final()) {
jrose@502 176 + bool is_final = this->is_final();
jrose@502 177 + bool is_stable = this->is_stable();
jrose@502 178 + if (_holder->is_initialized() && (is_final || is_stable)) {
jrose@502 179 if (!this->is_static()) {
jrose@502 180 // A field can be constant if it's a final static field or if
jrose@502 181 // it's a final non-static field of a trusted class (classes in
jrose@502 182 // java.lang.invoke and sun.invoke packages and subpackages).
jrose@502 183 - if (trust_final_non_static_fields(_holder)) {
jrose@502 184 + if (is_stable || trust_final_non_static_fields(_holder)) {
jrose@502 185 _is_constant = true;
jrose@502 186 return;
jrose@502 187 }
jrose@502 188 @@ -227,7 +229,6 @@
jrose@502 189
jrose@502 190 Handle mirror = k->java_mirror();
jrose@502 191
jrose@502 192 - _is_constant = true;
jrose@502 193 switch(type()->basic_type()) {
jrose@502 194 case T_BYTE:
jrose@502 195 _constant_value = ciConstant(type()->basic_type(), mirror->byte_field(_offset));
jrose@502 196 @@ -273,6 +274,12 @@
jrose@502 197 }
jrose@502 198 }
jrose@502 199 }
jrose@502 200 + if (is_stable && _constant_value.is_null_or_zero()) {
jrose@502 201 + // It is not a constant after all; treat it as uninitialized.
jrose@502 202 + _is_constant = false;
jrose@502 203 + } else {
jrose@502 204 + _is_constant = true;
jrose@502 205 + }
jrose@502 206 } else {
jrose@502 207 _is_constant = false;
jrose@502 208 }
jrose@503 209 @@ -373,6 +380,7 @@
jrose@503 210 tty->print(" offset=%d type=", _offset);
jrose@503 211 if (_type != NULL) _type->print_name();
jrose@503 212 else tty->print("(reference)");
jrose@503 213 + tty->print(" flags=%04x", flags().as_int());
jrose@503 214 tty->print(" is_constant=%s", bool_to_str(_is_constant));
jrose@503 215 if (_is_constant && is_static()) {
jrose@503 216 tty->print(" constant_value=");
jrose@502 217 diff --git a/src/share/vm/ci/ciField.hpp b/src/share/vm/ci/ciField.hpp
jrose@502 218 --- a/src/share/vm/ci/ciField.hpp
jrose@502 219 +++ b/src/share/vm/ci/ciField.hpp
jrose@502 220 @@ -139,7 +139,10 @@
jrose@502 221 // non-constant fields. These are java.lang.System.in
jrose@502 222 // and java.lang.System.out. Abomination.
jrose@502 223 //
jrose@502 224 - // Note: the check for case 4 is not yet implemented.
jrose@502 225 + // A field is also considered constant if it is marked @Stable
jrose@502 226 + // and is non-null (or non-zero, if a primitive).
jrose@502 227 + // For non-static fields, the null/zero check must be
jrose@502 228 + // arranged by the user, as constant_value().is_null_or_zero().
jrose@502 229 bool is_constant() { return _is_constant; }
jrose@502 230
jrose@502 231 // Get the constant value of this field.
jrose@502 232 @@ -173,6 +176,7 @@
jrose@502 233 bool is_protected () { return flags().is_protected(); }
jrose@502 234 bool is_static () { return flags().is_static(); }
jrose@502 235 bool is_final () { return flags().is_final(); }
jrose@502 236 + bool is_stable () { return flags().is_stable(); }
jrose@502 237 bool is_volatile () { return flags().is_volatile(); }
jrose@502 238 bool is_transient () { return flags().is_transient(); }
jrose@502 239
jrose@502 240 diff --git a/src/share/vm/ci/ciFlags.hpp b/src/share/vm/ci/ciFlags.hpp
jrose@502 241 --- a/src/share/vm/ci/ciFlags.hpp
jrose@502 242 +++ b/src/share/vm/ci/ciFlags.hpp
jrose@502 243 @@ -59,6 +59,7 @@
jrose@502 244 bool is_interface () const { return (_flags & JVM_ACC_INTERFACE ) != 0; }
jrose@502 245 bool is_abstract () const { return (_flags & JVM_ACC_ABSTRACT ) != 0; }
jrose@502 246 bool is_strict () const { return (_flags & JVM_ACC_STRICT ) != 0; }
jrose@502 247 + bool is_stable () const { return (_flags & JVM_ACC_FIELD_STABLE) != 0; }
jrose@502 248
jrose@502 249 // Conversion
jrose@502 250 jint as_int() { return _flags; }
jrose@504 251 diff --git a/src/share/vm/ci/ciInstance.cpp b/src/share/vm/ci/ciInstance.cpp
jrose@504 252 --- a/src/share/vm/ci/ciInstance.cpp
jrose@504 253 +++ b/src/share/vm/ci/ciInstance.cpp
jrose@504 254 @@ -127,6 +127,7 @@
jrose@504 255 ciConstant ciInstance::field_value_by_offset(int field_offset) {
jrose@504 256 ciInstanceKlass* ik = klass()->as_instance_klass();
jrose@504 257 ciField* field = ik->get_field_by_offset(field_offset, false);
jrose@504 258 + if (field == NULL) return ciConstant(); // T_ILLEGAL
jrose@504 259 return field_value(field);
jrose@504 260 }
jrose@504 261
jrose@504 262 diff --git a/src/share/vm/ci/ciTypeArray.cpp b/src/share/vm/ci/ciTypeArray.cpp
jrose@504 263 --- a/src/share/vm/ci/ciTypeArray.cpp
jrose@504 264 +++ b/src/share/vm/ci/ciTypeArray.cpp
jrose@504 265 @@ -39,5 +39,10 @@
jrose@504 266 jchar ciTypeArray::char_at(int index) {
jrose@504 267 VM_ENTRY_MARK;
jrose@504 268 assert(index >= 0 && index < length(), "out of range");
jrose@504 269 - return get_typeArrayOop()->char_at(index);
jrose@504 270 + jchar c = element_value(index).as_char();
jrose@504 271 +#ifdef ASSERT
jrose@504 272 + jchar d = get_typeArrayOop()->char_at(index);
jrose@504 273 + assert(c == d, "");
jrose@504 274 +#endif //ASSERT
jrose@504 275 + return c;
jrose@504 276 }
jrose@502 277 diff --git a/src/share/vm/classfile/classFileParser.cpp b/src/share/vm/classfile/classFileParser.cpp
jrose@502 278 --- a/src/share/vm/classfile/classFileParser.cpp
jrose@502 279 +++ b/src/share/vm/classfile/classFileParser.cpp
jrose@503 280 @@ -959,6 +959,7 @@
jrose@503 281 runtime_visible_annotations_length = attribute_length;
jrose@503 282 runtime_visible_annotations = cfs->get_u1_buffer();
jrose@503 283 assert(runtime_visible_annotations != NULL, "null visible annotations");
jrose@503 284 + parse_annotations(loader_data, runtime_visible_annotations, runtime_visible_annotations_length, cp, parsed_annotations, CHECK);
jrose@503 285 cfs->skip_u1(runtime_visible_annotations_length, CHECK);
jrose@503 286 } else if (PreserveAllAnnotations && attribute_name == vmSymbols::tag_runtime_invisible_annotations()) {
jrose@503 287 runtime_invisible_annotations_length = attribute_length;
jrose@503 288 @@ -1695,7 +1696,8 @@
jrose@503 289 }
jrose@503 290
jrose@503 291 // Sift through annotations, looking for those significant to the VM:
jrose@503 292 -void ClassFileParser::parse_annotations(u1* buffer, int limit,
jrose@503 293 +void ClassFileParser::parse_annotations(ClassLoaderData* loader_data,
jrose@503 294 + u1* buffer, int limit,
jrose@503 295 constantPoolHandle cp,
jrose@503 296 ClassFileParser::AnnotationCollector* coll,
jrose@503 297 TRAPS) {
jrose@503 298 @@ -1733,7 +1735,7 @@
jrose@503 299 }
jrose@503 300
jrose@503 301 // Here is where parsing particular annotations will take place.
jrose@503 302 - AnnotationCollector::ID id = coll->annotation_index(aname);
jrose@503 303 + AnnotationCollector::ID id = coll->annotation_index(loader_data, aname);
jrose@503 304 if (id == AnnotationCollector::_unknown) continue;
jrose@503 305 coll->set_annotation(id);
jrose@503 306 // If there are no values, just set the bit and move on:
jrose@503 307 @@ -1762,28 +1764,44 @@
jrose@503 308 }
jrose@503 309 }
jrose@503 310
jrose@503 311 -ClassFileParser::AnnotationCollector::ID ClassFileParser::AnnotationCollector::annotation_index(Symbol* name) {
jrose@503 312 +ClassFileParser::AnnotationCollector::ID
jrose@503 313 +ClassFileParser::AnnotationCollector::annotation_index(ClassLoaderData* loader_data,
jrose@503 314 + Symbol* name) {
jrose@503 315 vmSymbols::SID sid = vmSymbols::find_sid(name);
jrose@503 316 + bool privileged = false;
jrose@503 317 + if (loader_data->is_the_null_class_loader_data()) {
jrose@503 318 + // Privileged code can use all annotations. Other code silently drops some.
jrose@503 319 + privileged = true;
jrose@503 320 + }
jrose@503 321 switch (sid) {
jrose@503 322 case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_ForceInline_signature):
jrose@503 323 if (_location != _in_method) break; // only allow for methods
jrose@503 324 + if (!privileged) break; // only allow in privileged code
jrose@503 325 return _method_ForceInline;
jrose@503 326 case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_DontInline_signature):
jrose@503 327 if (_location != _in_method) break; // only allow for methods
jrose@503 328 + if (!privileged) break; // only allow in privileged code
jrose@503 329 return _method_DontInline;
jrose@503 330 case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_LambdaForm_Compiled_signature):
jrose@503 331 if (_location != _in_method) break; // only allow for methods
jrose@503 332 + if (!privileged) break; // only allow in privileged code
jrose@503 333 return _method_LambdaForm_Compiled;
jrose@502 334 case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_LambdaForm_Hidden_signature):
jrose@502 335 if (_location != _in_method) break; // only allow for methods
jrose@503 336 + if (!privileged) break; // only allow in privileged code
jrose@502 337 return _method_LambdaForm_Hidden;
jrose@507 338 + case vmSymbols::VM_SYMBOL_ENUM_NAME(sun_invoke_Stable_signature):
jrose@503 339 + if (_location != _in_field) break; // only allow for fields
jrose@503 340 + if (!privileged) break; // only allow in privileged code
jrose@502 341 + return _field_Stable;
jrose@502 342 default: break;
jrose@502 343 }
jrose@502 344 return AnnotationCollector::_unknown;
jrose@502 345 }
jrose@502 346
jrose@502 347 void ClassFileParser::FieldAnnotationCollector::apply_to(FieldInfo* f) {
jrose@502 348 - fatal("no field annotations yet");
jrose@502 349 + if (has_annotation(_field_Stable))
jrose@502 350 + f->set_stable(true);
jrose@502 351 }
jrose@502 352
jrose@502 353 void ClassFileParser::MethodAnnotationCollector::apply_to(methodHandle m) {
jrose@510 354 @@ -2125,8 +2143,8 @@
jrose@503 355 runtime_visible_annotations_length = method_attribute_length;
jrose@503 356 runtime_visible_annotations = cfs->get_u1_buffer();
jrose@503 357 assert(runtime_visible_annotations != NULL, "null visible annotations");
jrose@510 358 - parse_annotations(runtime_visible_annotations,
jrose@510 359 - runtime_visible_annotations_length, cp, &parsed_annotations,
jrose@510 360 + parse_annotations(loader_data,
jrose@510 361 + runtime_visible_annotations, runtime_visible_annotations_length, cp, &parsed_annotations,
jrose@510 362 CHECK_(nullHandle));
jrose@503 363 cfs->skip_u1(runtime_visible_annotations_length, CHECK_(nullHandle));
jrose@503 364 } else if (PreserveAllAnnotations && method_attribute_name == vmSymbols::tag_runtime_invisible_annotations()) {
jrose@503 365 @@ -2785,7 +2803,8 @@
jrose@503 366 runtime_visible_annotations_length = attribute_length;
jrose@503 367 runtime_visible_annotations = cfs->get_u1_buffer();
jrose@503 368 assert(runtime_visible_annotations != NULL, "null visible annotations");
jrose@503 369 - parse_annotations(runtime_visible_annotations,
jrose@503 370 + parse_annotations(loader_data,
jrose@503 371 + runtime_visible_annotations,
jrose@503 372 runtime_visible_annotations_length,
jrose@503 373 cp,
jrose@503 374 parsed_annotations,
jrose@502 375 diff --git a/src/share/vm/classfile/classFileParser.hpp b/src/share/vm/classfile/classFileParser.hpp
jrose@502 376 --- a/src/share/vm/classfile/classFileParser.hpp
jrose@502 377 +++ b/src/share/vm/classfile/classFileParser.hpp
jrose@502 378 @@ -92,6 +92,7 @@
jrose@502 379 _method_DontInline,
jrose@502 380 _method_LambdaForm_Compiled,
jrose@502 381 _method_LambdaForm_Hidden,
jrose@502 382 + _field_Stable,
jrose@502 383 _annotation_LIMIT
jrose@502 384 };
jrose@502 385 const Location _location;
jrose@503 386 @@ -102,7 +103,7 @@
jrose@503 387 assert((int)_annotation_LIMIT <= (int)sizeof(_annotations_present) * BitsPerByte, "");
jrose@503 388 }
jrose@503 389 // If this annotation name has an ID, report it (or _none).
jrose@503 390 - ID annotation_index(Symbol* name);
jrose@503 391 + ID annotation_index(ClassLoaderData* loader_data, Symbol* name);
jrose@503 392 // Set the annotation name:
jrose@503 393 void set_annotation(ID id) {
jrose@503 394 assert((int)id >= 0 && (int)id < (int)_annotation_LIMIT, "oob");
jrose@503 395 @@ -237,7 +238,8 @@
jrose@509 396 int runtime_invisible_annotations_length, TRAPS);
jrose@503 397 int skip_annotation(u1* buffer, int limit, int index);
jrose@503 398 int skip_annotation_value(u1* buffer, int limit, int index);
jrose@503 399 - void parse_annotations(u1* buffer, int limit, constantPoolHandle cp,
jrose@503 400 + void parse_annotations(ClassLoaderData* loader_data,
jrose@503 401 + u1* buffer, int limit, constantPoolHandle cp,
jrose@503 402 /* Results (currently, only one result is supported): */
jrose@503 403 AnnotationCollector* result,
jrose@503 404 TRAPS);
jrose@502 405 diff --git a/src/share/vm/classfile/vmSymbols.hpp b/src/share/vm/classfile/vmSymbols.hpp
jrose@502 406 --- a/src/share/vm/classfile/vmSymbols.hpp
jrose@502 407 +++ b/src/share/vm/classfile/vmSymbols.hpp
jrose@502 408 @@ -255,6 +255,7 @@
jrose@502 409 template(java_lang_invoke_LambdaForm, "java/lang/invoke/LambdaForm") \
jrose@502 410 template(java_lang_invoke_ForceInline_signature, "Ljava/lang/invoke/ForceInline;") \
jrose@502 411 template(java_lang_invoke_DontInline_signature, "Ljava/lang/invoke/DontInline;") \
jrose@507 412 + template(sun_invoke_Stable_signature, "Lsun/invoke/Stable;") \
jrose@502 413 template(java_lang_invoke_LambdaForm_Compiled_signature, "Ljava/lang/invoke/LambdaForm$Compiled;") \
jrose@502 414 template(java_lang_invoke_LambdaForm_Hidden_signature, "Ljava/lang/invoke/LambdaForm$Hidden;") \
jrose@510 415 template(java_lang_invoke_MagicLambdaImpl, "java/lang/invoke/MagicLambdaImpl") \
jrose@502 416 diff --git a/src/share/vm/oops/fieldInfo.hpp b/src/share/vm/oops/fieldInfo.hpp
jrose@502 417 --- a/src/share/vm/oops/fieldInfo.hpp
jrose@502 418 +++ b/src/share/vm/oops/fieldInfo.hpp
jrose@502 419 @@ -114,6 +114,14 @@
jrose@502 420 return (access_flags() & JVM_ACC_FIELD_INTERNAL) != 0;
jrose@502 421 }
jrose@502 422
jrose@502 423 + bool is_stable() const {
jrose@502 424 + return (access_flags() & JVM_ACC_FIELD_STABLE) != 0;
jrose@502 425 + }
jrose@502 426 + void set_stable(bool z) {
jrose@502 427 + if (z) _shorts[access_flags_offset] |= JVM_ACC_FIELD_STABLE;
jrose@502 428 + else _shorts[access_flags_offset] &= ~JVM_ACC_FIELD_STABLE;
jrose@502 429 + }
jrose@502 430 +
jrose@502 431 Symbol* lookup_symbol(int symbol_index) const {
jrose@502 432 assert(is_internal(), "only internal fields");
jrose@502 433 return vmSymbols::symbol_at((vmSymbols::SID)symbol_index);
jrose@504 434 diff --git a/src/share/vm/opto/c2_globals.hpp b/src/share/vm/opto/c2_globals.hpp
jrose@504 435 --- a/src/share/vm/opto/c2_globals.hpp
jrose@504 436 +++ b/src/share/vm/opto/c2_globals.hpp
jrose@504 437 @@ -433,6 +433,9 @@
jrose@504 438 diagnostic(bool, EliminateAutoBox, false, \
jrose@504 439 "Private flag to control optimizations for autobox elimination") \
jrose@504 440 \
jrose@504 441 + diagnostic(bool, FoldStableValues, false, \
jrose@504 442 + "Private flag to control optimizations for stable variables") \
jrose@504 443 + \
jrose@504 444 product(intx, AutoBoxCacheMax, 128, \
jrose@504 445 "Sets max value cached by the java.lang.Integer autobox cache") \
jrose@504 446 \
jrose@502 447 diff --git a/src/share/vm/opto/compile.cpp b/src/share/vm/opto/compile.cpp
jrose@502 448 --- a/src/share/vm/opto/compile.cpp
jrose@502 449 +++ b/src/share/vm/opto/compile.cpp
jrose@503 450 @@ -1162,6 +1162,10 @@
jrose@503 451
jrose@503 452 // Array pointers need some flattening
jrose@503 453 const TypeAryPtr *ta = tj->isa_aryptr();
jrose@503 454 + if (ta && ta->stable()) {
jrose@503 455 + // Erase stability property for alias analysis.
jrose@503 456 + tj = ta = ta->cast_to_stable(false);
jrose@503 457 + }
jrose@503 458 if( ta && is_known_inst ) {
jrose@503 459 if ( offset != Type::OffsetBot &&
jrose@503 460 offset > arrayOopDesc::length_offset_in_bytes() ) {
jrose@503 461 @@ -1362,6 +1366,7 @@
jrose@503 462 _index = i;
jrose@503 463 _adr_type = at;
jrose@503 464 _field = NULL;
jrose@503 465 + _element = NULL;
jrose@503 466 _is_rewritable = true; // default
jrose@503 467 const TypeOopPtr *atoop = (at != NULL) ? at->isa_oopptr() : NULL;
jrose@503 468 if (atoop != NULL && atoop->is_known_instance()) {
jrose@503 469 @@ -1480,6 +1485,15 @@
jrose@503 470 && flat->is_instptr()->klass() == env()->Class_klass())
jrose@503 471 alias_type(idx)->set_rewritable(false);
jrose@503 472 }
jrose@503 473 + if (flat->isa_aryptr()) {
jrose@503 474 +#ifdef ASSERT
jrose@503 475 + const int header_size_min = arrayOopDesc::base_offset_in_bytes(T_BYTE);
jrose@503 476 + // (T_BYTE has the weakest alignment and size restrictions...)
jrose@503 477 + assert(flat->offset() < header_size_min, "array body reference must be OffsetBot");
jrose@503 478 +#endif
jrose@503 479 + if (flat->offset() == TypePtr::OffsetBot)
jrose@503 480 + alias_type(idx)->set_element(flat->is_aryptr()->elem());
jrose@503 481 + }
jrose@503 482 if (flat->isa_klassptr()) {
jrose@503 483 if (flat->offset() == in_bytes(Klass::super_check_offset_offset()))
jrose@503 484 alias_type(idx)->set_rewritable(false);
jrose@503 485 @@ -1542,7 +1556,7 @@
jrose@502 486 else
jrose@502 487 t = TypeOopPtr::make_from_klass_raw(field->holder());
jrose@502 488 AliasType* atp = alias_type(t->add_offset(field->offset_in_bytes()), field);
jrose@502 489 - assert(field->is_final() == !atp->is_rewritable(), "must get the rewritable bits correct");
jrose@502 490 + assert((field->is_final() || field->is_stable()) == !atp->is_rewritable(), "must get the rewritable bits correct");
jrose@502 491 return atp;
jrose@502 492 }
jrose@502 493
jrose@502 494 diff --git a/src/share/vm/opto/compile.hpp b/src/share/vm/opto/compile.hpp
jrose@502 495 --- a/src/share/vm/opto/compile.hpp
jrose@502 496 +++ b/src/share/vm/opto/compile.hpp
jrose@503 497 @@ -69,6 +69,7 @@
jrose@503 498 class StartNode;
jrose@503 499 class SafePointNode;
jrose@503 500 class JVMState;
jrose@503 501 +class Type;
jrose@503 502 class TypeData;
jrose@503 503 class TypePtr;
jrose@503 504 class TypeFunc;
jrose@503 505 @@ -111,6 +112,7 @@
jrose@503 506 int _index; // unique index, used with MergeMemNode
jrose@503 507 const TypePtr* _adr_type; // normalized address type
jrose@503 508 ciField* _field; // relevant instance field, or null if none
jrose@503 509 + const Type* _element; // relevant array element type, or null if none
jrose@503 510 bool _is_rewritable; // false if the memory is write-once only
jrose@503 511 int _general_index; // if this is type is an instance, the general
jrose@503 512 // type that this is an instance of
jrose@503 513 @@ -121,6 +123,7 @@
jrose@503 514 int index() const { return _index; }
jrose@503 515 const TypePtr* adr_type() const { return _adr_type; }
jrose@503 516 ciField* field() const { return _field; }
jrose@503 517 + const Type* element() const { return _element; }
jrose@503 518 bool is_rewritable() const { return _is_rewritable; }
jrose@503 519 bool is_volatile() const { return (_field ? _field->is_volatile() : false); }
jrose@503 520 int general_index() const { return (_general_index != 0) ? _general_index : _index; }
jrose@503 521 @@ -129,7 +132,12 @@
jrose@502 522 void set_field(ciField* f) {
jrose@502 523 assert(!_field,"");
jrose@502 524 _field = f;
jrose@502 525 - if (f->is_final()) _is_rewritable = false;
jrose@502 526 + if (f->is_final() || f->is_stable()) _is_rewritable = false;
jrose@502 527 + // In the case of @Stable, multiple writes are possible but may be assumed to be no-ops.
jrose@503 528 + }
jrose@503 529 + void set_element(const Type* e) {
jrose@503 530 + assert(!_element,"");
jrose@503 531 + _element = e;
jrose@502 532 }
jrose@502 533
jrose@502 534 void print_on(outputStream* st) PRODUCT_RETURN;
jrose@503 535 diff --git a/src/share/vm/opto/graphKit.cpp b/src/share/vm/opto/graphKit.cpp
jrose@503 536 --- a/src/share/vm/opto/graphKit.cpp
jrose@503 537 +++ b/src/share/vm/opto/graphKit.cpp
jrose@507 538 @@ -3788,7 +3788,7 @@
jrose@503 539 false, NULL, 0);
jrose@503 540 const TypePtr* value_field_type = string_type->add_offset(value_offset);
jrose@503 541 const TypeAryPtr* value_type = TypeAryPtr::make(TypePtr::NotNull,
jrose@503 542 - TypeAry::make(TypeInt::CHAR,TypeInt::POS),
jrose@503 543 + TypeAry::make(TypeInt::CHAR,TypeInt::POS,/*stable=*/true),
jrose@503 544 ciTypeArrayKlass::make(T_CHAR), true, 0);
jrose@503 545 int value_field_idx = C->get_alias_index(value_field_type);
jrose@503 546 return make_load(ctrl, basic_plus_adr(str, str, value_offset),
jrose@507 547 @@ -3811,7 +3811,7 @@
jrose@503 548 false, NULL, 0);
jrose@503 549 const TypePtr* value_field_type = string_type->add_offset(value_offset);
jrose@503 550 const TypeAryPtr* value_type = TypeAryPtr::make(TypePtr::NotNull,
jrose@503 551 - TypeAry::make(TypeInt::CHAR,TypeInt::POS),
jrose@503 552 + TypeAry::make(TypeInt::CHAR,TypeInt::POS,/*stable=*/true),
jrose@503 553 ciTypeArrayKlass::make(T_CHAR), true, 0);
jrose@503 554 int value_field_idx = C->get_alias_index(value_field_type);
jrose@503 555 store_to_memory(ctrl, basic_plus_adr(str, value_offset),
jrose@503 556 diff --git a/src/share/vm/opto/library_call.cpp b/src/share/vm/opto/library_call.cpp
jrose@503 557 --- a/src/share/vm/opto/library_call.cpp
jrose@503 558 +++ b/src/share/vm/opto/library_call.cpp
jrose@503 559 @@ -1230,7 +1230,7 @@
jrose@503 560
jrose@503 561 Node* target = _gvn.transform( makecon(TypeOopPtr::make_from_constant(target_array, true)) );
jrose@503 562 jint target_length = target_array->length();
jrose@503 563 - const TypeAry* target_array_type = TypeAry::make(TypeInt::CHAR, TypeInt::make(0, target_length, Type::WidenMin));
jrose@503 564 + const TypeAry* target_array_type = TypeAry::make(TypeInt::CHAR, TypeInt::make(0, target_length, Type::WidenMin), /*stable=*/true);
jrose@503 565 const TypeAryPtr* target_type = TypeAryPtr::make(TypePtr::BotPTR, target_array_type, target_array->klass(), true, Type::OffsetBot);
jrose@503 566
jrose@503 567 IdealKit kit(this, false, true);
jrose@502 568 diff --git a/src/share/vm/opto/memnode.cpp b/src/share/vm/opto/memnode.cpp
jrose@502 569 --- a/src/share/vm/opto/memnode.cpp
jrose@502 570 +++ b/src/share/vm/opto/memnode.cpp
jrose@503 571 @@ -932,12 +932,13 @@
jrose@503 572 Node* MemNode::can_see_stored_value(Node* st, PhaseTransform* phase) const {
jrose@503 573 Node* ld_adr = in(MemNode::Address);
jrose@503 574
jrose@503 575 - const TypeInstPtr* tp = phase->type(ld_adr)->isa_instptr();
jrose@503 576 + const TypeOopPtr* tp = phase->type(ld_adr)->isa_oopptr();
jrose@503 577 Compile::AliasType* atp = tp != NULL ? phase->C->alias_type(tp) : NULL;
jrose@504 578 - if (EliminateAutoBox && atp != NULL && atp->index() >= Compile::AliasIdxRaw &&
jrose@503 579 - atp->field() != NULL && !atp->field()->is_volatile()) {
jrose@504 580 + if (atp != NULL && atp->index() >= Compile::AliasIdxRaw &&
jrose@504 581 + ((EliminateAutoBox && atp->field() != NULL && !atp->field()->is_volatile())
jrose@504 582 + || (FoldStableValues && tp->isa_aryptr() && (tp->is_aryptr()->stable())))) {
jrose@502 583 uint alias_idx = atp->index();
jrose@502 584 - bool final = atp->field()->is_final();
jrose@502 585 + bool final = !atp->is_rewritable();
jrose@502 586 Node* result = NULL;
jrose@502 587 Node* current = st;
jrose@502 588 // Skip through chains of MemBarNodes checking the MergeMems for
jrose@503 589 @@ -972,7 +973,6 @@
jrose@502 590 }
jrose@502 591 }
jrose@502 592
jrose@503 593 -
jrose@502 594 // Loop around twice in the case Load -> Initialize -> Store.
jrose@502 595 // (See PhaseIterGVN::add_users_to_worklist, which knows about this case.)
jrose@503 596 for (int trip = 0; trip <= 1; trip++) {
jrose@504 597 @@ -1527,6 +1527,48 @@
jrose@504 598 // Try to guess loaded type from pointer type
jrose@504 599 if (tp->base() == Type::AryPtr) {
jrose@504 600 const Type *t = tp->is_aryptr()->elem();
jrose@504 601 +
jrose@504 602 + // Make sure the reference is not into the header, by comparing
jrose@504 603 + // the offset against the offset of the start of the array's data.
jrose@504 604 + // Different array types begin at slightly different offsets (12 vs. 16).
jrose@504 605 + // We choose T_BYTE as an example base type that is least restrictive
jrose@504 606 + // as to alignment, which will therefore produce the smallest
jrose@504 607 + // possible base offset.
jrose@504 608 + const int min_base_off = arrayOopDesc::base_offset_in_bytes(T_BYTE);
jrose@504 609 + const bool off_in_header = ((uint)off < (uint)min_base_off);
jrose@504 610 +
jrose@504 611 + // Try to constant-fold a stable array element.
jrose@504 612 + if (FoldStableValues && !off_in_header && off != Type::OffsetBot &&
jrose@504 613 + adr->is_AddP() && adr->in(AddPNode::Base)->is_Con() &&
jrose@504 614 + tp->is_aryptr()->stable()) {
jrose@504 615 + // Decode the results of GraphKit::array_element_address.
jrose@504 616 + BasicType loadbt = memory_type();
jrose@504 617 + BasicType elembt = t->array_element_basic_type();
jrose@504 618 + if (elembt == T_BOOLEAN) elembt = T_BYTE; // oddity about boolean[]
jrose@504 619 + ciArray* aobj = tp->is_aryptr()->const_oop()->as_array();
jrose@504 620 + ciConstant con = aobj->element_value_by_offset(off);
jrose@504 621 + if (con.basic_type() != T_ILLEGAL && !con.is_null_or_zero()) {
jrose@504 622 + const Type* con_type = Type::make_from_constant(con);
jrose@504 623 + if (con_type != NULL) {
jrose@504 624 + if (con_type->isa_aryptr()) {
jrose@504 625 + // Join with the array element type, in case it is also stable.
jrose@504 626 + int dim = tp->is_aryptr()->stable_dimension();
jrose@504 627 + con_type = con_type->is_aryptr()->cast_to_stable(true, dim-1);
jrose@504 628 + }
jrose@504 629 + if (loadbt == T_NARROWOOP && con_type->isa_oopptr()) {
jrose@504 630 + con_type = con_type->make_narrowoop();
jrose@504 631 + }
jrose@504 632 +#ifndef PRODUCT
jrose@504 633 + if (TraceIterativeGVN) {
jrose@504 634 + tty->print("FoldStableValues: array element [off=%d]: con_type=", off);
jrose@504 635 + con_type->dump(); tty->cr();
jrose@504 636 + }
jrose@504 637 +#endif //PRODUCT
jrose@504 638 + return con_type;
jrose@504 639 + }
jrose@504 640 + }
jrose@504 641 + }
jrose@504 642 +
jrose@504 643 // Don't do this for integer types. There is only potential profit if
jrose@504 644 // the element type t is lower than _type; that is, for int types, if _type is
jrose@504 645 // more restrictive than t. This only happens here if one is short and the other
jrose@504 646 @@ -1547,14 +1589,7 @@
jrose@504 647 && Opcode() != Op_LoadKlass && Opcode() != Op_LoadNKlass) {
jrose@504 648 // t might actually be lower than _type, if _type is a unique
jrose@504 649 // concrete subclass of abstract class t.
jrose@504 650 - // Make sure the reference is not into the header, by comparing
jrose@504 651 - // the offset against the offset of the start of the array's data.
jrose@504 652 - // Different array types begin at slightly different offsets (12 vs. 16).
jrose@504 653 - // We choose T_BYTE as an example base type that is least restrictive
jrose@504 654 - // as to alignment, which will therefore produce the smallest
jrose@504 655 - // possible base offset.
jrose@504 656 - const int min_base_off = arrayOopDesc::base_offset_in_bytes(T_BYTE);
jrose@504 657 - if ((uint)off >= (uint)min_base_off) { // is the offset beyond the header?
jrose@504 658 + if (!off_in_header) {
jrose@504 659 const Type* jt = t->join(_type);
jrose@504 660 // In any case, do not allow the join, per se, to empty out the type.
jrose@504 661 if (jt->empty() && !t->empty()) {
jrose@503 662 diff --git a/src/share/vm/opto/parse.hpp b/src/share/vm/opto/parse.hpp
jrose@503 663 --- a/src/share/vm/opto/parse.hpp
jrose@503 664 +++ b/src/share/vm/opto/parse.hpp
jrose@503 665 @@ -503,7 +503,7 @@
jrose@503 666
jrose@503 667 // loading from a constant field or the constant pool
jrose@503 668 // returns false if push failed (non-perm field constants only, not ldcs)
jrose@503 669 - bool push_constant(ciConstant con, bool require_constant = false);
jrose@503 670 + bool push_constant(ciConstant con, bool require_constant = false, const Type* basic_type = NULL);
jrose@503 671
jrose@503 672 // implementation of object creation bytecodes
jrose@503 673 void emit_guard_for_new(ciInstanceKlass* klass);
jrose@502 674 diff --git a/src/share/vm/opto/parse1.cpp b/src/share/vm/opto/parse1.cpp
jrose@502 675 --- a/src/share/vm/opto/parse1.cpp
jrose@502 676 +++ b/src/share/vm/opto/parse1.cpp
jrose@507 677 @@ -917,6 +917,7 @@
jrose@502 678 // such unusual early publications. But no barrier is needed on
jrose@502 679 // exceptional returns, since they cannot publish normally.
jrose@502 680 //
jrose@502 681 + // Any method can write a @Stable field, and we give those the same treatment.
jrose@502 682 _exits.insert_mem_bar(Op_MemBarRelease);
jrose@502 683 #ifndef PRODUCT
jrose@502 684 if (PrintOpto && (Verbose || WizardMode)) {
jrose@502 685 diff --git a/src/share/vm/opto/parse3.cpp b/src/share/vm/opto/parse3.cpp
jrose@502 686 --- a/src/share/vm/opto/parse3.cpp
jrose@502 687 +++ b/src/share/vm/opto/parse3.cpp
jrose@503 688 @@ -147,14 +147,21 @@
jrose@503 689 void Parse::do_get_xxx(Node* obj, ciField* field, bool is_field) {
jrose@503 690 // Does this field have a constant value? If so, just push the value.
jrose@503 691 if (field->is_constant()) {
jrose@503 692 - // final field
jrose@503 693 + // final or stable field
jrose@503 694 + const Type* stable_type = NULL;
jrose@504 695 + if (FoldStableValues && field->is_stable()) {
jrose@503 696 + stable_type = Type::get_const_type(field->type());
jrose@503 697 + if (field->type()->is_array_klass()) {
jrose@503 698 + int stable_dimension = field->type()->as_array_klass()->dimension();
jrose@503 699 + stable_type = stable_type->is_aryptr()->cast_to_stable(true, stable_dimension);
jrose@503 700 + }
jrose@503 701 + }
jrose@503 702 if (field->is_static()) {
jrose@503 703 // final static field
jrose@503 704 - if (push_constant(field->constant_value()))
jrose@503 705 + if (push_constant(field->constant_value(), false, stable_type))
jrose@503 706 return;
jrose@503 707 - }
jrose@503 708 - else {
jrose@503 709 - // final non-static field
jrose@503 710 + } else {
jrose@503 711 + // final or stable non-static field
jrose@503 712 // Treat final non-static fields of trusted classes (classes in
jrose@503 713 // java.lang.invoke and sun.invoke packages and subpackages) as
jrose@503 714 // compile time constants.
jrose@503 715 @@ -162,8 +169,12 @@
jrose@502 716 const TypeOopPtr* oop_ptr = obj->bottom_type()->isa_oopptr();
jrose@502 717 ciObject* constant_oop = oop_ptr->const_oop();
jrose@502 718 ciConstant constant = field->constant_value_of(constant_oop);
jrose@502 719 - if (push_constant(constant, true))
jrose@503 720 - return;
jrose@504 721 + if (FoldStableValues && field->is_stable() && constant.is_null_or_zero()) {
jrose@503 722 + // fall through to field load; the field is not yet initialized
jrose@503 723 + } else {
jrose@503 724 + if (push_constant(constant, true, stable_type))
jrose@503 725 + return;
jrose@502 726 + }
jrose@502 727 }
jrose@502 728 }
jrose@503 729 }
jrose@504 730 @@ -302,41 +313,28 @@
jrose@502 731 // Note the presence of writes to final non-static fields, so that we
jrose@502 732 // can insert a memory barrier later on to keep the writes from floating
jrose@502 733 // out of the constructor.
jrose@502 734 - if (is_field && field->is_final()) {
jrose@502 735 + // Any method can write a @Stable field; insert memory barriers after those also.
jrose@502 736 + if (is_field && field->is_final()
jrose@502 737 + || field->is_stable()) {
jrose@502 738 set_wrote_final(true);
jrose@502 739 }
jrose@502 740 }
jrose@503 741
jrose@503 742
jrose@503 743 -bool Parse::push_constant(ciConstant constant, bool require_constant) {
jrose@503 744 +bool Parse::push_constant(ciConstant constant, bool require_constant, const Type* stable_type) {
jrose@504 745 + const Type* con_type = Type::make_from_constant(constant, require_constant);
jrose@503 746 switch (constant.basic_type()) {
jrose@504 747 - case T_BOOLEAN: push( intcon(constant.as_boolean()) ); break;
jrose@504 748 - case T_INT: push( intcon(constant.as_int()) ); break;
jrose@504 749 - case T_CHAR: push( intcon(constant.as_char()) ); break;
jrose@504 750 - case T_BYTE: push( intcon(constant.as_byte()) ); break;
jrose@504 751 - case T_SHORT: push( intcon(constant.as_short()) ); break;
jrose@504 752 - case T_FLOAT: push( makecon(TypeF::make(constant.as_float())) ); break;
jrose@504 753 - case T_DOUBLE: push_pair( makecon(TypeD::make(constant.as_double())) ); break;
jrose@504 754 - case T_LONG: push_pair( longcon(constant.as_long()) ); break;
jrose@504 755 case T_ARRAY:
jrose@504 756 - case T_OBJECT: {
jrose@504 757 + case T_OBJECT:
jrose@504 758 // cases:
jrose@504 759 // can_be_constant = (oop not scavengable || ScavengeRootsInCode != 0)
jrose@504 760 // should_be_constant = (oop not scavengable || ScavengeRootsInCode >= 2)
jrose@504 761 // An oop is not scavengable if it is in the perm gen.
jrose@504 762 - ciObject* oop_constant = constant.as_object();
jrose@504 763 - if (oop_constant->is_null_object()) {
jrose@504 764 - push( zerocon(T_OBJECT) );
jrose@504 765 - break;
jrose@504 766 - } else if (require_constant || oop_constant->should_be_constant()) {
jrose@503 767 - push( makecon(TypeOopPtr::make_from_constant(oop_constant, require_constant)) );
jrose@504 768 - break;
jrose@504 769 - } else {
jrose@504 770 - // we cannot inline the oop, but we can use it later to narrow a type
jrose@504 771 - return false;
jrose@504 772 - }
jrose@504 773 - }
jrose@504 774 - case T_ILLEGAL: {
jrose@504 775 + if (stable_type != NULL && con_type != NULL && con_type->isa_oopptr())
jrose@504 776 + con_type = con_type->join(stable_type);
jrose@504 777 + break;
jrose@504 778 +
jrose@504 779 + case T_ILLEGAL:
jrose@504 780 // Invalid ciConstant returned due to OutOfMemoryError in the CI
jrose@504 781 assert(C->env()->failing(), "otherwise should not see this");
jrose@504 782 // These always occur because of object types; we are going to
jrose@504 783 @@ -344,17 +342,16 @@
jrose@504 784 push( zerocon(T_OBJECT) );
jrose@504 785 return false;
jrose@504 786 }
jrose@504 787 - default:
jrose@504 788 - ShouldNotReachHere();
jrose@504 789 +
jrose@504 790 + if (con_type == NULL)
jrose@504 791 + // we cannot inline the oop, but we can use it later to narrow a type
jrose@504 792 return false;
jrose@504 793 - }
jrose@504 794
jrose@504 795 - // success
jrose@504 796 + push_node(constant.basic_type(), makecon(con_type));
jrose@504 797 return true;
jrose@504 798 }
jrose@504 799
jrose@504 800
jrose@504 801 -
jrose@504 802 //=============================================================================
jrose@504 803 void Parse::do_anewarray() {
jrose@504 804 bool will_link;
jrose@503 805 diff --git a/src/share/vm/opto/type.cpp b/src/share/vm/opto/type.cpp
jrose@503 806 --- a/src/share/vm/opto/type.cpp
jrose@503 807 +++ b/src/share/vm/opto/type.cpp
jrose@504 808 @@ -188,6 +188,38 @@
jrose@504 809 }
jrose@504 810
jrose@504 811
jrose@504 812 +//-----------------------make_from_constant------------------------------------
jrose@504 813 +const Type* Type::make_from_constant(ciConstant constant,
jrose@504 814 + bool require_constant) {
jrose@504 815 + switch (constant.basic_type()) {
jrose@504 816 + case T_BOOLEAN: return TypeInt::make(constant.as_boolean());
jrose@504 817 + case T_CHAR: return TypeInt::make(constant.as_char());
jrose@504 818 + case T_BYTE: return TypeInt::make(constant.as_byte());
jrose@504 819 + case T_SHORT: return TypeInt::make(constant.as_short());
jrose@504 820 + case T_INT: return TypeInt::make(constant.as_int());
jrose@504 821 + case T_LONG: return TypeLong::make(constant.as_long());
jrose@504 822 + case T_FLOAT: return TypeF::make(constant.as_float());
jrose@504 823 + case T_DOUBLE: return TypeD::make(constant.as_double());
jrose@504 824 + case T_ARRAY:
jrose@504 825 + case T_OBJECT:
jrose@504 826 + {
jrose@504 827 + // cases:
jrose@504 828 + // can_be_constant = (oop not scavengable || ScavengeRootsInCode != 0)
jrose@504 829 + // should_be_constant = (oop not scavengable || ScavengeRootsInCode >= 2)
jrose@504 830 + // An oop is not scavengable if it is in the perm gen.
jrose@504 831 + ciObject* oop_constant = constant.as_object();
jrose@504 832 + if (oop_constant->is_null_object()) {
jrose@504 833 + return Type::get_zero_type(T_OBJECT);
jrose@504 834 + } else if (require_constant || oop_constant->should_be_constant()) {
jrose@504 835 + return TypeOopPtr::make_from_constant(oop_constant, require_constant);
jrose@504 836 + }
jrose@504 837 + }
jrose@504 838 + }
jrose@504 839 + // Fall through to failure
jrose@504 840 + return NULL;
jrose@504 841 +}
jrose@504 842 +
jrose@504 843 +
jrose@504 844 //------------------------------make-------------------------------------------
jrose@504 845 // Create a simple Type, with default empty symbol sets. Then hashcons it
jrose@504 846 // and look for an existing copy in the type dictionary.
jrose@504 847 @@ -1804,12 +1836,13 @@
jrose@503 848 }
jrose@503 849
jrose@503 850 //------------------------------make-------------------------------------------
jrose@503 851 -const TypeAry *TypeAry::make( const Type *elem, const TypeInt *size) {
jrose@503 852 +const TypeAry* TypeAry::make(const Type* elem, const TypeInt* size, bool stable) {
jrose@503 853 if (UseCompressedOops && elem->isa_oopptr()) {
jrose@503 854 elem = elem->make_narrowoop();
jrose@503 855 }
jrose@503 856 + assert(stable == true || stable == false, "");
jrose@503 857 size = normalize_array_size(size);
jrose@503 858 - return (TypeAry*)(new TypeAry(elem,size))->hashcons();
jrose@503 859 + return (TypeAry*)(new TypeAry(elem,size,stable))->hashcons();
jrose@503 860 }
jrose@503 861
jrose@503 862 //------------------------------meet-------------------------------------------
jrose@504 863 @@ -1830,7 +1863,8 @@
jrose@503 864 case Array: { // Meeting 2 arrays?
jrose@503 865 const TypeAry *a = t->is_ary();
jrose@503 866 return TypeAry::make(_elem->meet(a->_elem),
jrose@503 867 - _size->xmeet(a->_size)->is_int());
jrose@503 868 + _size->xmeet(a->_size)->is_int(),
jrose@503 869 + _stable & a->_stable);
jrose@503 870 }
jrose@503 871 case Top:
jrose@503 872 break;
jrose@504 873 @@ -1843,7 +1877,7 @@
jrose@503 874 const Type *TypeAry::xdual() const {
jrose@503 875 const TypeInt* size_dual = _size->dual()->is_int();
jrose@503 876 size_dual = normalize_array_size(size_dual);
jrose@503 877 - return new TypeAry( _elem->dual(), size_dual);
jrose@503 878 + return new TypeAry(_elem->dual(), size_dual, !_stable);
jrose@503 879 }
jrose@503 880
jrose@503 881 //------------------------------eq---------------------------------------------
jrose@504 882 @@ -1851,13 +1885,14 @@
jrose@504 883 bool TypeAry::eq( const Type *t ) const {
jrose@504 884 const TypeAry *a = (const TypeAry*)t;
jrose@504 885 return _elem == a->_elem &&
jrose@504 886 + _stable == a->_stable &&
jrose@504 887 _size == a->_size;
jrose@504 888 }
jrose@504 889
jrose@504 890 //------------------------------hash-------------------------------------------
jrose@504 891 // Type-specific hashing function.
jrose@504 892 int TypeAry::hash(void) const {
jrose@504 893 - return (intptr_t)_elem + (intptr_t)_size;
jrose@504 894 + return (intptr_t)_elem + (intptr_t)_size + (_stable ? 42 : 0);
jrose@504 895 }
jrose@504 896
jrose@504 897 //----------------------interface_vs_oop---------------------------------------
jrose@504 898 @@ -1874,6 +1909,7 @@
jrose@504 899 //------------------------------dump2------------------------------------------
jrose@504 900 #ifndef PRODUCT
jrose@504 901 void TypeAry::dump2( Dict &d, uint depth, outputStream *st ) const {
jrose@504 902 + if (_stable) st->print("stable:");
jrose@504 903 _elem->dump2(d, depth, st);
jrose@504 904 st->print("[");
jrose@504 905 _size->dump2(d, depth, st);
jrose@504 906 @@ -3387,11 +3423,34 @@
jrose@503 907 assert(new_size != NULL, "");
jrose@503 908 new_size = narrow_size_type(new_size);
jrose@503 909 if (new_size == size()) return this;
jrose@503 910 - const TypeAry* new_ary = TypeAry::make(elem(), new_size);
jrose@503 911 + const TypeAry* new_ary = TypeAry::make(elem(), new_size, stable());
jrose@503 912 return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _instance_id);
jrose@503 913 }
jrose@503 914
jrose@503 915
jrose@503 916 +//------------------------------cast_to_stable---------------------------------
jrose@503 917 +const TypeAryPtr* TypeAryPtr::cast_to_stable(bool stable, int stable_dimension) const {
jrose@503 918 + assert(stable == true || stable == false, "");
jrose@504 919 + if (stable_dimension <= 0 || stable_dimension == 1 && stable == this->stable()) return this;
jrose@503 920 + const Type* elem = this->elem();
jrose@504 921 + const TypePtr* elem_ptr = elem->make_ptr();
jrose@504 922 + if (stable_dimension > 1 && elem_ptr != NULL && elem_ptr->base() == Type::AryPtr)
jrose@504 923 + // If this is widened from a narrow oop, TypeAry::make will re-narrow it.
jrose@504 924 + elem = elem_ptr = elem_ptr->is_aryptr()->cast_to_stable(stable, stable_dimension - 1);
jrose@503 925 + const TypeAry* new_ary = TypeAry::make(elem, size(), stable);
jrose@503 926 + return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _instance_id);
jrose@503 927 +}
jrose@503 928 +
jrose@504 929 +//-----------------------------stable_dimension--------------------------------
jrose@504 930 +int TypeAryPtr::stable_dimension() const {
jrose@504 931 + if (!stable()) return 0;
jrose@504 932 + int dim = 1;
jrose@504 933 + const TypePtr* elem_ptr = elem()->make_ptr();
jrose@504 934 + if (elem_ptr != NULL && elem_ptr->isa_aryptr())
jrose@504 935 + dim += elem_ptr->is_aryptr()->stable_dimension();
jrose@504 936 + return dim;
jrose@504 937 +}
jrose@504 938 +
jrose@503 939 //------------------------------eq---------------------------------------------
jrose@503 940 // Structural equality check for Type representations
jrose@503 941 bool TypeAryPtr::eq( const Type *t ) const {
jrose@504 942 @@ -3499,7 +3558,7 @@
jrose@503 943 // Something like byte[int+] meets char[int+].
jrose@503 944 // This must fall to bottom, not (int[-128..65535])[int+].
jrose@503 945 instance_id = InstanceBot;
jrose@503 946 - tary = TypeAry::make(Type::BOTTOM, tary->_size);
jrose@503 947 + tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable);
jrose@503 948 }
jrose@503 949 } else // Non integral arrays.
jrose@503 950 // Must fall to bottom if exact klasses in upper lattice
jrose@504 951 @@ -3513,7 +3572,7 @@
jrose@503 952 (tap ->_klass_is_exact && !tap->klass()->is_subtype_of(klass())) ||
jrose@503 953 // 'this' is exact and super or unrelated:
jrose@503 954 (this->_klass_is_exact && !klass()->is_subtype_of(tap->klass())))) {
jrose@503 955 - tary = TypeAry::make(Type::BOTTOM, tary->_size);
jrose@503 956 + tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable);
jrose@503 957 return make( NotNull, NULL, tary, lazy_klass, false, off, InstanceBot );
jrose@503 958 }
jrose@503 959
jrose@503 960 diff --git a/src/share/vm/opto/type.hpp b/src/share/vm/opto/type.hpp
jrose@503 961 --- a/src/share/vm/opto/type.hpp
jrose@503 962 +++ b/src/share/vm/opto/type.hpp
jrose@504 963 @@ -357,6 +357,9 @@
jrose@504 964 // Mapping from CI type system to compiler type:
jrose@504 965 static const Type* get_typeflow_type(ciType* type);
jrose@504 966
jrose@504 967 + static const Type* make_from_constant(ciConstant constant,
jrose@504 968 + bool require_constant = false);
jrose@504 969 +
jrose@504 970 private:
jrose@504 971 // support arrays
jrose@504 972 static const BasicType _basic_type[];
jrose@504 973 @@ -573,8 +576,8 @@
jrose@503 974 //------------------------------TypeAry----------------------------------------
jrose@503 975 // Class of Array Types
jrose@503 976 class TypeAry : public Type {
jrose@503 977 - TypeAry( const Type *elem, const TypeInt *size) : Type(Array),
jrose@503 978 - _elem(elem), _size(size) {}
jrose@503 979 + TypeAry(const Type* elem, const TypeInt* size, bool stable) : Type(Array),
jrose@503 980 + _elem(elem), _size(size), _stable(stable) {}
jrose@503 981 public:
jrose@503 982 virtual bool eq( const Type *t ) const;
jrose@503 983 virtual int hash() const; // Type specific hashing
jrose@504 984 @@ -584,10 +587,11 @@
jrose@503 985 private:
jrose@503 986 const Type *_elem; // Element type of array
jrose@503 987 const TypeInt *_size; // Elements in array
jrose@503 988 + const bool _stable; // Are elements @Stable?
jrose@503 989 friend class TypeAryPtr;
jrose@503 990
jrose@503 991 public:
jrose@503 992 - static const TypeAry *make( const Type *elem, const TypeInt *size);
jrose@503 993 + static const TypeAry* make(const Type* elem, const TypeInt* size, bool stable = false);
jrose@503 994
jrose@503 995 virtual const Type *xmeet( const Type *t ) const;
jrose@503 996 virtual const Type *xdual() const; // Compute dual right now.
jrose@504 997 @@ -959,6 +963,7 @@
jrose@503 998 const TypeAry* ary() const { return _ary; }
jrose@503 999 const Type* elem() const { return _ary->_elem; }
jrose@503 1000 const TypeInt* size() const { return _ary->_size; }
jrose@504 1001 + bool stable() const { return _ary->_stable; }
jrose@503 1002
jrose@503 1003 static const TypeAryPtr *make( PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id = InstanceBot);
jrose@503 1004 // Constant pointer to array
jrose@504 1005 @@ -980,6 +985,9 @@
jrose@503 1006 virtual const Type *xmeet( const Type *t ) const;
jrose@503 1007 virtual const Type *xdual() const; // Compute dual right now.
jrose@503 1008
jrose@503 1009 + const TypeAryPtr* cast_to_stable(bool stable, int stable_dimension = 1) const;
jrose@504 1010 + int stable_dimension() const;
jrose@503 1011 +
jrose@503 1012 // Convenience common pre-built types.
jrose@503 1013 static const TypeAryPtr *RANGE;
jrose@503 1014 static const TypeAryPtr *OOPS;
jrose@502 1015 diff --git a/src/share/vm/utilities/accessFlags.hpp b/src/share/vm/utilities/accessFlags.hpp
jrose@502 1016 --- a/src/share/vm/utilities/accessFlags.hpp
jrose@502 1017 +++ b/src/share/vm/utilities/accessFlags.hpp
jrose@502 1018 @@ -78,11 +78,13 @@
jrose@502 1019 JVM_ACC_FIELD_ACCESS_WATCHED = 0x00002000, // field access is watched by JVMTI
jrose@502 1020 JVM_ACC_FIELD_MODIFICATION_WATCHED = 0x00008000, // field modification is watched by JVMTI
jrose@502 1021 JVM_ACC_FIELD_INTERNAL = 0x00000400, // internal field, same as JVM_ACC_ABSTRACT
jrose@503 1022 + JVM_ACC_FIELD_STABLE = 0x00000020, // @Stable field, same as JVM_ACC_SYNCHRONIZED
jrose@502 1023 JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE = 0x00000800, // field has generic signature
jrose@502 1024
jrose@502 1025 JVM_ACC_FIELD_INTERNAL_FLAGS = JVM_ACC_FIELD_ACCESS_WATCHED |
jrose@502 1026 JVM_ACC_FIELD_MODIFICATION_WATCHED |
jrose@502 1027 JVM_ACC_FIELD_INTERNAL |
jrose@502 1028 + JVM_ACC_FIELD_STABLE |
jrose@502 1029 JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE,
jrose@502 1030
jrose@502 1031 // flags accepted by set_field_flags()
jrose@502 1032 @@ -148,6 +150,7 @@
jrose@502 1033 { return (_flags & JVM_ACC_FIELD_MODIFICATION_WATCHED) != 0; }
jrose@502 1034 bool on_stack() const { return (_flags & JVM_ACC_ON_STACK) != 0; }
jrose@502 1035 bool is_internal() const { return (_flags & JVM_ACC_FIELD_INTERNAL) != 0; }
jrose@502 1036 + bool is_stable() const { return (_flags & JVM_ACC_FIELD_STABLE) != 0; }
jrose@502 1037 bool field_has_generic_signature() const
jrose@502 1038 { return (_flags & JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE) != 0; }
jrose@502 1039