1 /* 2 * Copyright (c) 1999, 2010, 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 // sun.misc.Unsafe 69 case vmIntrinsics::_compareAndSwapInt: 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 // sun.misc.Unsafe 143 case vmIntrinsics::_compareAndSwapInt: 144 do_Unsafe_compareAndSwapInt(); 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(), "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::oop_type(), 214 "klass"); 215 216 Value *klass_part = builder()->CreateAddressOfStructEntry( 217 klass, 218 in_ByteSize(klassOopDesc::klass_part_offset_in_bytes()), 219 SharkType::klass_type(), 220 "klass_part"); 221 222 state()->push( 223 SharkValue::create_jobject( 224 builder()->CreateValueOfStructEntry( 225 klass_part, 226 in_ByteSize(Klass::java_mirror_offset_in_bytes()), 227 SharkType::oop_type(), 228 "java_mirror"), 229 true)); 230 } 231 232 void SharkIntrinsics::do_System_currentTimeMillis() { 233 state()->push( 234 SharkValue::create_jlong( 235 builder()->CreateCall(builder()->current_time_millis()), 236 false)); 237 state()->push(NULL); 238 } 239 240 void SharkIntrinsics::do_Thread_currentThread() { 241 state()->push( 242 SharkValue::create_jobject( 243 builder()->CreateValueOfStructEntry( 244 thread(), JavaThread::threadObj_offset(), 245 SharkType::oop_type(), 246 "threadObj"), 247 true)); 248 } 249 250 void SharkIntrinsics::do_Unsafe_compareAndSwapInt() { 251 // Pop the arguments 252 Value *x = state()->pop()->jint_value(); 253 Value *e = state()->pop()->jint_value(); 254 SharkValue *empty = state()->pop(); 255 assert(empty == NULL, "should be"); 256 Value *offset = state()->pop()->jlong_value(); 257 Value *object = state()->pop()->jobject_value(); 258 Value *unsafe = state()->pop()->jobject_value(); 259 260 // Convert the offset 261 offset = builder()->CreateCall( 262 builder()->unsafe_field_offset_to_byte_offset(), 263 offset); 264 265 // Locate the field 266 Value *addr = builder()->CreateIntToPtr( 267 builder()->CreateAdd( 268 builder()->CreatePtrToInt(object, SharkType::intptr_type()), 269 builder()->CreateIntCast(offset, SharkType::intptr_type(), true)), 270 PointerType::getUnqual(SharkType::jint_type()), 271 "addr"); 272 273 // Perform the operation 274 Value *result = builder()->CreateCmpxchgInt(x, addr, e); 275 276 // Push the result 277 state()->push( 278 SharkValue::create_jint( 279 builder()->CreateIntCast( 280 builder()->CreateICmpEQ(result, e), SharkType::jint_type(), true), 281 false)); 282 }