1 /*
   2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #include "precompiled.hpp"
  26 #include "interpreter/interpreter.hpp"
  27 #include "oops/oop.inline.hpp"
  28 #include "oops/fieldStreams.hpp"
  29 #include "oops/method.hpp"
  30 #include "oops/objArrayKlass.hpp"
  31 #include "oops/valueKlass.hpp"
  32 #include "oops/valueArrayKlass.hpp"
  33 
  34 Method* ValueKlass::factory_method() const {
  35   for (int i = 0; i < methods()->length(); i++) {
  36     ConstMethod* cm = methods()->at(i)->constMethod();
  37     if (cm->has_valuefactory_parameter_mapping()) {
  38       return methods()->at(i);
  39     }
  40   }
  41   return NULL;
  42 }
  43 
  44 int ValueKlass::first_field_offset() {
  45   // Really inefficient, should be cached somewhere
  46   instanceKlassHandle k(this);
  47   int first_offset = INT_MAX;
  48   for (JavaFieldStream fs(k()); !fs.done(); fs.next()) {
  49     if (fs.offset() < first_offset) first_offset= fs.offset();
  50   }
  51   return first_offset;
  52 }
  53 
  54 bool ValueKlass::is_atomic() {
  55   return (nonstatic_field_size() * heapOopSize) <= longSize;
  56 }
  57 
  58 int ValueKlass::nonstatic_oop_count() {
  59   int oops = 0;
  60   int map_count = nonstatic_oop_map_count();
  61   OopMapBlock* block = start_of_nonstatic_oop_maps();
  62   OopMapBlock* end = block + map_count;
  63   while (block != end) {
  64     oops += block->count();
  65     block++;
  66   }
  67   return oops;
  68 }
  69 
  70 // Arrays of...
  71 
  72 bool ValueKlass::flatten_array() {
  73   if (!ValueArrayFlatten) {
  74     return false;
  75   }
  76 
  77   int elem_bytes = raw_value_byte_size();
  78   // Too big
  79   if ((ValueArrayElemMaxFlatSize >= 0) && (elem_bytes > ValueArrayElemMaxFlatSize)) {
  80     return false;
  81   }
  82   // Too many embedded oops
  83   if ((ValueArrayElemMaxFlatOops >= 0) && (nonstatic_oop_count() > ValueArrayElemMaxFlatOops)) {
  84     return false;
  85   }
  86 
  87   return true;
  88 }
  89 
  90 
  91 Klass* ValueKlass::array_klass_impl(instanceKlassHandle this_k, bool or_null, int n, TRAPS) {
  92   if (!ValueKlass::cast(this_k())->flatten_array()) {
  93     return InstanceKlass::array_klass_impl(this_k, or_null, n, THREAD);
  94   }
  95 
  96   // Basically the same as instanceKlass, but using "ValueArrayKlass::allocate_klass"
  97   if (this_k->array_klasses() == NULL) {
  98     if (or_null) return NULL;
  99 
 100     ResourceMark rm;
 101     JavaThread *jt = (JavaThread *)THREAD;
 102     {
 103       // Atomic creation of array_klasses
 104       MutexLocker mc(Compile_lock, THREAD);   // for vtables
 105       MutexLocker ma(MultiArray_lock, THREAD);
 106 
 107       // Check if update has already taken place
 108       if (this_k->array_klasses() == NULL) {
 109         Klass* ak;
 110         if (ValueKlass::cast(this_k())->is_atomic() || (!ValueArrayAtomicAccess)) {
 111           ak = ValueArrayKlass::allocate_klass(this_k, CHECK_NULL);
 112         }
 113         else {
 114           ak = ObjArrayKlass::allocate_objArray_klass(this_k->class_loader_data(), 1, this_k, CHECK_NULL);
 115         }
 116         this_k->set_array_klasses(ak);
 117       }
 118     }
 119   }
 120   // _this will always be set at this point
 121   ArrayKlass* ak = ArrayKlass::cast(this_k->array_klasses());
 122   if (or_null) {
 123     return ak->array_klass_or_null(n);
 124   }
 125   return ak->array_klass(n, THREAD);
 126 }
 127 
 128 Klass* ValueKlass::array_klass_impl(bool or_null, int n, TRAPS) {
 129   instanceKlassHandle this_k(THREAD, this);
 130   return array_klass_impl(this_k, or_null, n, THREAD);
 131 }
 132 
 133 Klass* ValueKlass::array_klass_impl(bool or_null, TRAPS) {
 134   return array_klass_impl(or_null, 1, THREAD);
 135 }
 136 
 137 /*
 138  * Store the value of this klass contained with src into dst.
 139  *
 140  * This operation is appropriate for use from vastore, vaload and putfield (for values)
 141  *
 142  * GC barriers currently can lock with no safepoint check and allocate c-heap,
 143  * so raw point is "safe" for now.
 144  *
 145  * Going forward, look to use machine generated (stub gen or bc) version for most used klass layouts
 146  */
 147 void ValueKlass::value_store(void* src, void* dst, bool dst_heap, bool dst_uninitialized) {
 148   // So the raw "memcpy" bytes size...
 149   size_t raw_byte_size = raw_value_byte_size();
 150 
 151   if (contains_oops() && dst_heap) {
 152     // src/dst aren't oops, need offset to adjust oop map offset
 153     int oop_offset = valueOopDescBase();
 154 
 155     // Pre-barriers...
 156     OopMapBlock* map = start_of_nonstatic_oop_maps();
 157     OopMapBlock* const end = map + nonstatic_oop_map_count();
 158     while (map != end) {
 159       // Shame we can't just use the existing oop iterator...src/dst aren't oop
 160       uintptr_t doop_address = ((uintptr_t)dst) + (map->offset() - oop_offset);
 161       if (UseCompressedOops) {
 162         oopDesc::bs()->write_ref_array_pre((narrowOop*) doop_address, map->count(), dst_uninitialized);
 163       }
 164       else {
 165         oopDesc::bs()->write_ref_array_pre((oop*) doop_address, map->count(), dst_uninitialized);
 166       }
 167       map++;
 168     }
 169 
 170     // Actual store...
 171     // oop atomic copy, even if both dst & src don't require atomic ?
 172     Copy::conjoint_jlongs_atomic((jlong*)src, (jlong*)dst, raw_byte_size / sizeof(jlong));
 173 
 174     // Post-barriers...
 175     map = start_of_nonstatic_oop_maps();
 176     while (map != end) {
 177       uintptr_t doop_address = ((uintptr_t)dst) + (map->offset() - oop_offset);
 178       oopDesc::bs()->write_ref_array((HeapWord*) doop_address, map->count());
 179       map++;
 180     }
 181   }
 182   else {   // Primitive-only case...
 183     memcpy(dst, src, raw_byte_size); // Actual store
 184   }
 185 
 186 }