1 /* 2 * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. 3 * Copyright 2009 Red Hat, Inc. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 * 24 */ 25 26 #include "precompiled.hpp" 27 #include "ci/ciMethod.hpp" 28 #include "shark/llvmHeaders.hpp" 29 #include "shark/sharkIntrinsics.hpp" 30 #include "shark/sharkState.hpp" 31 #include "shark/sharkValue.hpp" 32 #include "shark/shark_globals.hpp" 33 34 using namespace llvm; 35 36 bool SharkIntrinsics::is_intrinsic(ciMethod *target) { 37 switch (target->intrinsic_id()) { 38 case vmIntrinsics::_none: 39 return false; 40 41 // java.lang.Math 42 case vmIntrinsics::_min: 43 case vmIntrinsics::_max: 44 case vmIntrinsics::_dabs: 45 case vmIntrinsics::_dsin: 46 case vmIntrinsics::_dcos: 47 case vmIntrinsics::_dtan: 48 case vmIntrinsics::_datan2: 49 case vmIntrinsics::_dsqrt: 50 case vmIntrinsics::_dlog: 51 case vmIntrinsics::_dlog10: 52 case vmIntrinsics::_dpow: 53 case vmIntrinsics::_dexp: 54 return true; 55 56 // java.lang.Object 57 case vmIntrinsics::_getClass: 58 return true; 59 60 // java.lang.System 61 case vmIntrinsics::_currentTimeMillis: 62 return true; 63 64 // java.lang.Thread 65 case vmIntrinsics::_currentThread: 66 return true; 67 68 // Unsafe 69 case vmIntrinsics::_compareAndSetInt: 70 return true; 71 72 default: 73 if (SharkPerformanceWarnings) { 74 warning( 75 "unhandled intrinsic vmIntrinsic::%s", 76 vmIntrinsics::name_at(target->intrinsic_id())); 77 } 78 } 79 return false; 80 } 81 82 void SharkIntrinsics::inline_intrinsic(ciMethod *target, SharkState *state) { 83 SharkIntrinsics intrinsic(state, target); 84 intrinsic.do_intrinsic(); 85 } 86 87 void SharkIntrinsics::do_intrinsic() { 88 switch (target()->intrinsic_id()) { 89 // java.lang.Math 90 case vmIntrinsics::_min: 91 do_Math_minmax(llvm::ICmpInst::ICMP_SLE); 92 break; 93 case vmIntrinsics::_max: 94 do_Math_minmax(llvm::ICmpInst::ICMP_SGE); 95 break; 96 case vmIntrinsics::_dabs: 97 do_Math_1to1(builder()->fabs()); 98 break; 99 case vmIntrinsics::_dsin: 100 do_Math_1to1(builder()->sin()); 101 break; 102 case vmIntrinsics::_dcos: 103 do_Math_1to1(builder()->cos()); 104 break; 105 case vmIntrinsics::_dtan: 106 do_Math_1to1(builder()->tan()); 107 break; 108 case vmIntrinsics::_datan2: 109 do_Math_2to1(builder()->atan2()); 110 break; 111 case vmIntrinsics::_dsqrt: 112 do_Math_1to1(builder()->sqrt()); 113 break; 114 case vmIntrinsics::_dlog: 115 do_Math_1to1(builder()->log()); 116 break; 117 case vmIntrinsics::_dlog10: 118 do_Math_1to1(builder()->log10()); 119 break; 120 case vmIntrinsics::_dpow: 121 do_Math_2to1(builder()->pow()); 122 break; 123 case vmIntrinsics::_dexp: 124 do_Math_1to1(builder()->exp()); 125 break; 126 127 // java.lang.Object 128 case vmIntrinsics::_getClass: 129 do_Object_getClass(); 130 break; 131 132 // java.lang.System 133 case vmIntrinsics::_currentTimeMillis: 134 do_System_currentTimeMillis(); 135 break; 136 137 // java.lang.Thread 138 case vmIntrinsics::_currentThread: 139 do_Thread_currentThread(); 140 break; 141 142 // Unsafe 143 case vmIntrinsics::_compareAndSetInt: 144 do_Unsafe_compareAndSetInt(); 145 break; 146 147 default: 148 ShouldNotReachHere(); 149 } 150 } 151 152 void SharkIntrinsics::do_Math_minmax(ICmpInst::Predicate p) { 153 // Pop the arguments 154 SharkValue *sb = state()->pop(); 155 SharkValue *sa = state()->pop(); 156 Value *a = sa->jint_value(); 157 Value *b = sb->jint_value(); 158 159 // Perform the test 160 BasicBlock *ip = builder()->GetBlockInsertionPoint(); 161 BasicBlock *return_a = builder()->CreateBlock(ip, "return_a"); 162 BasicBlock *return_b = builder()->CreateBlock(ip, "return_b"); 163 BasicBlock *done = builder()->CreateBlock(ip, "done"); 164 165 builder()->CreateCondBr(builder()->CreateICmp(p, a, b), return_a, return_b); 166 167 builder()->SetInsertPoint(return_a); 168 builder()->CreateBr(done); 169 170 builder()->SetInsertPoint(return_b); 171 builder()->CreateBr(done); 172 173 builder()->SetInsertPoint(done); 174 PHINode *phi = builder()->CreatePHI(a->getType(), 0, "result"); 175 phi->addIncoming(a, return_a); 176 phi->addIncoming(b, return_b); 177 178 // Push the result 179 state()->push( 180 SharkValue::create_jint( 181 phi, 182 sa->zero_checked() && sb->zero_checked())); 183 } 184 185 void SharkIntrinsics::do_Math_1to1(Value *function) { 186 SharkValue *empty = state()->pop(); 187 assert(empty == NULL, "should be"); 188 state()->push( 189 SharkValue::create_jdouble( 190 builder()->CreateCall( 191 function, state()->pop()->jdouble_value()))); 192 state()->push(NULL); 193 } 194 195 void SharkIntrinsics::do_Math_2to1(Value *function) { 196 SharkValue *empty = state()->pop(); 197 assert(empty == NULL, "should be"); 198 Value *y = state()->pop()->jdouble_value(); 199 empty = state()->pop(); 200 assert(empty == NULL, "should be"); 201 Value *x = state()->pop()->jdouble_value(); 202 203 state()->push( 204 SharkValue::create_jdouble( 205 builder()->CreateCall2(function, x, y))); 206 state()->push(NULL); 207 } 208 209 void SharkIntrinsics::do_Object_getClass() { 210 Value *klass = builder()->CreateValueOfStructEntry( 211 state()->pop()->jobject_value(), 212 in_ByteSize(oopDesc::klass_offset_in_bytes()), 213 SharkType::klass_type(), 214 "klass"); 215 216 state()->push( 217 SharkValue::create_jobject( 218 builder()->CreateValueOfStructEntry( 219 klass, 220 Klass::java_mirror_offset(), 221 SharkType::oop_type(), 222 "java_mirror"), 223 true)); 224 } 225 226 void SharkIntrinsics::do_System_currentTimeMillis() { 227 state()->push( 228 SharkValue::create_jlong( 229 builder()->CreateCall(builder()->current_time_millis()), 230 false)); 231 state()->push(NULL); 232 } 233 234 void SharkIntrinsics::do_Thread_currentThread() { 235 state()->push( 236 SharkValue::create_jobject( 237 builder()->CreateValueOfStructEntry( 238 thread(), JavaThread::threadObj_offset(), 239 SharkType::oop_type(), 240 "threadObj"), 241 true)); 242 } 243 244 void SharkIntrinsics::do_Unsafe_compareAndSetInt() { 245 // Pop the arguments 246 Value *x = state()->pop()->jint_value(); 247 Value *e = state()->pop()->jint_value(); 248 SharkValue *empty = state()->pop(); 249 assert(empty == NULL, "should be"); 250 Value *offset = state()->pop()->jlong_value(); 251 Value *object = state()->pop()->jobject_value(); 252 Value *unsafe = state()->pop()->jobject_value(); 253 254 // Convert the offset 255 offset = builder()->CreateCall( 256 builder()->unsafe_field_offset_to_byte_offset(), 257 offset); 258 259 // Locate the field 260 Value *addr = builder()->CreateIntToPtr( 261 builder()->CreateAdd( 262 builder()->CreatePtrToInt(object, SharkType::intptr_type()), 263 builder()->CreateIntCast(offset, SharkType::intptr_type(), true)), 264 PointerType::getUnqual(SharkType::jint_type()), 265 "addr"); 266 267 // Perform the operation 268 Value *result = builder()->CreateAtomicCmpXchg(addr, e, x, llvm::SequentiallyConsistent); 269 // Push the result 270 state()->push( 271 SharkValue::create_jint( 272 builder()->CreateIntCast( 273 builder()->CreateICmpEQ(result, e), SharkType::jint_type(), true), 274 false)); 275 }