1 /*
   2  * Copyright (c) 1999, 2007, 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 "incls/_precompiled.incl"
  27 #include "incls/_sharkIntrinsics.cpp.incl"
  28 
  29 using namespace llvm;
  30 
  31 bool SharkIntrinsics::is_intrinsic(ciMethod *target) {
  32   switch (target->intrinsic_id()) {
  33   case vmIntrinsics::_none:
  34     return false;
  35 
  36     // java.lang.Math
  37   case vmIntrinsics::_min:
  38   case vmIntrinsics::_max:
  39   case vmIntrinsics::_dabs:
  40   case vmIntrinsics::_dsin:
  41   case vmIntrinsics::_dcos:
  42   case vmIntrinsics::_dtan:
  43   case vmIntrinsics::_datan2:
  44   case vmIntrinsics::_dsqrt:
  45   case vmIntrinsics::_dlog:
  46   case vmIntrinsics::_dlog10:
  47   case vmIntrinsics::_dpow:
  48   case vmIntrinsics::_dexp:
  49     return true;
  50 
  51     // java.lang.Object
  52   case vmIntrinsics::_getClass:
  53     return true;
  54 
  55     // java.lang.System
  56   case vmIntrinsics::_currentTimeMillis:
  57     return true;
  58 
  59     // java.lang.Thread
  60   case vmIntrinsics::_currentThread:
  61     return true;
  62 
  63     // sun.misc.Unsafe
  64   case vmIntrinsics::_compareAndSwapInt:
  65     return true;
  66 
  67   default:
  68     if (SharkPerformanceWarnings) {
  69       warning(
  70         "unhandled intrinsic vmIntrinsic::%s",
  71         vmIntrinsics::name_at(target->intrinsic_id()));
  72     }
  73   }
  74   return false;
  75 }
  76 
  77 void SharkIntrinsics::inline_intrinsic(ciMethod *target, SharkState *state) {
  78   SharkIntrinsics intrinsic(state, target);
  79   intrinsic.do_intrinsic();
  80 }
  81 
  82 void SharkIntrinsics::do_intrinsic() {
  83   switch (target()->intrinsic_id()) {
  84     // java.lang.Math
  85   case vmIntrinsics::_min:
  86     do_Math_minmax(llvm::ICmpInst::ICMP_SLE);
  87     break;
  88   case vmIntrinsics::_max:
  89     do_Math_minmax(llvm::ICmpInst::ICMP_SGE);
  90     break;
  91   case vmIntrinsics::_dabs:
  92     do_Math_1to1(builder()->fabs());
  93     break;
  94   case vmIntrinsics::_dsin:
  95     do_Math_1to1(builder()->sin());
  96     break;
  97   case vmIntrinsics::_dcos:
  98     do_Math_1to1(builder()->cos());
  99     break;
 100   case vmIntrinsics::_dtan:
 101     do_Math_1to1(builder()->tan());
 102     break;
 103   case vmIntrinsics::_datan2:
 104     do_Math_2to1(builder()->atan2());
 105     break;
 106   case vmIntrinsics::_dsqrt:
 107     do_Math_1to1(builder()->sqrt());
 108     break;
 109   case vmIntrinsics::_dlog:
 110     do_Math_1to1(builder()->log());
 111     break;
 112   case vmIntrinsics::_dlog10:
 113     do_Math_1to1(builder()->log10());
 114     break;
 115   case vmIntrinsics::_dpow:
 116     do_Math_2to1(builder()->pow());
 117     break;
 118   case vmIntrinsics::_dexp:
 119     do_Math_1to1(builder()->exp());
 120     break;
 121 
 122     // java.lang.Object
 123   case vmIntrinsics::_getClass:
 124     do_Object_getClass();
 125     break;
 126 
 127     // java.lang.System
 128   case vmIntrinsics::_currentTimeMillis:
 129     do_System_currentTimeMillis();
 130     break;
 131 
 132     // java.lang.Thread
 133   case vmIntrinsics::_currentThread:
 134     do_Thread_currentThread();
 135     break;
 136 
 137     // sun.misc.Unsafe
 138   case vmIntrinsics::_compareAndSwapInt:
 139     do_Unsafe_compareAndSwapInt();
 140     break;
 141 
 142   default:
 143     ShouldNotReachHere();
 144   }
 145 }
 146 
 147 void SharkIntrinsics::do_Math_minmax(ICmpInst::Predicate p) {
 148   // Pop the arguments
 149   SharkValue *sb = state()->pop();
 150   SharkValue *sa = state()->pop();
 151   Value *a = sa->jint_value();
 152   Value *b = sb->jint_value();
 153 
 154   // Perform the test
 155   BasicBlock *ip       = builder()->GetBlockInsertionPoint();
 156   BasicBlock *return_a = builder()->CreateBlock(ip, "return_a");
 157   BasicBlock *return_b = builder()->CreateBlock(ip, "return_b");
 158   BasicBlock *done     = builder()->CreateBlock(ip, "done");
 159 
 160   builder()->CreateCondBr(builder()->CreateICmp(p, a, b), return_a, return_b);
 161 
 162   builder()->SetInsertPoint(return_a);
 163   builder()->CreateBr(done);
 164 
 165   builder()->SetInsertPoint(return_b);
 166   builder()->CreateBr(done);
 167 
 168   builder()->SetInsertPoint(done);
 169   PHINode *phi = builder()->CreatePHI(a->getType(), "result");
 170   phi->addIncoming(a, return_a);
 171   phi->addIncoming(b, return_b);
 172 
 173   // Push the result
 174   state()->push(
 175     SharkValue::create_jint(
 176       phi,
 177       sa->zero_checked() && sb->zero_checked()));
 178 }
 179 
 180 void SharkIntrinsics::do_Math_1to1(Value *function) {
 181   SharkValue *empty = state()->pop();
 182   assert(empty == NULL, "should be");
 183   state()->push(
 184     SharkValue::create_jdouble(
 185       builder()->CreateCall(
 186         function, state()->pop()->jdouble_value())));
 187   state()->push(NULL);
 188 }
 189 
 190 void SharkIntrinsics::do_Math_2to1(Value *function) {
 191   SharkValue *empty = state()->pop();
 192   assert(empty == NULL, "should be");
 193   Value *y = state()->pop()->jdouble_value();
 194   empty = state()->pop();
 195   assert(empty == NULL, "should be");
 196   Value *x = state()->pop()->jdouble_value();
 197 
 198   state()->push(
 199     SharkValue::create_jdouble(
 200       builder()->CreateCall2(function, x, y)));
 201   state()->push(NULL);
 202 }
 203 
 204 void SharkIntrinsics::do_Object_getClass() {
 205   Value *klass = builder()->CreateValueOfStructEntry(
 206     state()->pop()->jobject_value(),
 207     in_ByteSize(oopDesc::klass_offset_in_bytes()),
 208     SharkType::oop_type(),
 209     "klass");
 210 
 211   Value *klass_part = builder()->CreateAddressOfStructEntry(
 212     klass,
 213     in_ByteSize(klassOopDesc::klass_part_offset_in_bytes()),
 214     SharkType::klass_type(),
 215     "klass_part");
 216 
 217   state()->push(
 218     SharkValue::create_jobject(
 219       builder()->CreateValueOfStructEntry(
 220         klass_part,
 221         in_ByteSize(Klass::java_mirror_offset_in_bytes()),
 222         SharkType::oop_type(),
 223         "java_mirror"),
 224       true));
 225 }
 226 
 227 void SharkIntrinsics::do_System_currentTimeMillis() {
 228   state()->push(
 229     SharkValue::create_jlong(
 230       builder()->CreateCall(builder()->current_time_millis()),
 231       false));
 232   state()->push(NULL);
 233 }
 234 
 235 void SharkIntrinsics::do_Thread_currentThread() {
 236   state()->push(
 237     SharkValue::create_jobject(
 238       builder()->CreateValueOfStructEntry(
 239         thread(), JavaThread::threadObj_offset(),
 240         SharkType::oop_type(),
 241         "threadObj"),
 242       true));
 243 }
 244 
 245 void SharkIntrinsics::do_Unsafe_compareAndSwapInt() {
 246   // Pop the arguments
 247   Value *x      = state()->pop()->jint_value();
 248   Value *e      = state()->pop()->jint_value();
 249   SharkValue *empty = state()->pop();
 250   assert(empty == NULL, "should be");
 251   Value *offset = state()->pop()->jlong_value();
 252   Value *object = state()->pop()->jobject_value();
 253   Value *unsafe = state()->pop()->jobject_value();
 254 
 255   // Convert the offset
 256   offset = builder()->CreateCall(
 257     builder()->unsafe_field_offset_to_byte_offset(),
 258     offset);
 259 
 260   // Locate the field
 261   Value *addr = builder()->CreateIntToPtr(
 262     builder()->CreateAdd(
 263       builder()->CreatePtrToInt(object, SharkType::intptr_type()),
 264       builder()->CreateIntCast(offset, SharkType::intptr_type(), true)),
 265     PointerType::getUnqual(SharkType::jint_type()),
 266     "addr");
 267 
 268   // Perform the operation
 269   Value *result = builder()->CreateCmpxchgInt(x, addr, e);
 270 
 271   // Push the result
 272   state()->push(
 273     SharkValue::create_jint(
 274       builder()->CreateIntCast(
 275         builder()->CreateICmpEQ(result, e), SharkType::jint_type(), true),
 276       false));
 277 }