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
34using namespace llvm;
35
36bool 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
82void SharkIntrinsics::inline_intrinsic(ciMethod *target, SharkState *state) {
83  SharkIntrinsics intrinsic(state, target);
84  intrinsic.do_intrinsic();
85}
86
87void 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
152void 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
185void 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
195void 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
209void 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
226void 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
234void 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
244void 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}
276