OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "src/v8.h" |
| 6 |
| 7 #include "src/arguments.h" |
| 8 #include "src/assembler.h" |
| 9 #include "src/codegen.h" |
| 10 #include "src/runtime/runtime.h" |
| 11 #include "src/runtime/runtime-utils.h" |
| 12 #include "third_party/fdlibm/fdlibm.h" |
| 13 |
| 14 |
| 15 namespace v8 { |
| 16 namespace internal { |
| 17 |
| 18 #define RUNTIME_UNARY_MATH(Name, name) \ |
| 19 RUNTIME_FUNCTION(Runtime_Math##Name) { \ |
| 20 HandleScope scope(isolate); \ |
| 21 DCHECK(args.length() == 1); \ |
| 22 isolate->counters()->math_##name()->Increment(); \ |
| 23 CONVERT_DOUBLE_ARG_CHECKED(x, 0); \ |
| 24 return *isolate->factory()->NewHeapNumber(std::name(x)); \ |
| 25 } |
| 26 |
| 27 RUNTIME_UNARY_MATH(Acos, acos) |
| 28 RUNTIME_UNARY_MATH(Asin, asin) |
| 29 RUNTIME_UNARY_MATH(Atan, atan) |
| 30 RUNTIME_UNARY_MATH(LogRT, log) |
| 31 #undef RUNTIME_UNARY_MATH |
| 32 |
| 33 |
| 34 RUNTIME_FUNCTION(Runtime_DoubleHi) { |
| 35 HandleScope scope(isolate); |
| 36 DCHECK(args.length() == 1); |
| 37 CONVERT_DOUBLE_ARG_CHECKED(x, 0); |
| 38 uint64_t integer = double_to_uint64(x); |
| 39 integer = (integer >> 32) & 0xFFFFFFFFu; |
| 40 return *isolate->factory()->NewNumber(static_cast<int32_t>(integer)); |
| 41 } |
| 42 |
| 43 |
| 44 RUNTIME_FUNCTION(Runtime_DoubleLo) { |
| 45 HandleScope scope(isolate); |
| 46 DCHECK(args.length() == 1); |
| 47 CONVERT_DOUBLE_ARG_CHECKED(x, 0); |
| 48 return *isolate->factory()->NewNumber( |
| 49 static_cast<int32_t>(double_to_uint64(x) & 0xFFFFFFFFu)); |
| 50 } |
| 51 |
| 52 |
| 53 RUNTIME_FUNCTION(Runtime_ConstructDouble) { |
| 54 HandleScope scope(isolate); |
| 55 DCHECK(args.length() == 2); |
| 56 CONVERT_NUMBER_CHECKED(uint32_t, hi, Uint32, args[0]); |
| 57 CONVERT_NUMBER_CHECKED(uint32_t, lo, Uint32, args[1]); |
| 58 uint64_t result = (static_cast<uint64_t>(hi) << 32) | lo; |
| 59 return *isolate->factory()->NewNumber(uint64_to_double(result)); |
| 60 } |
| 61 |
| 62 |
| 63 RUNTIME_FUNCTION(Runtime_RemPiO2) { |
| 64 HandleScope handle_scope(isolate); |
| 65 DCHECK(args.length() == 1); |
| 66 CONVERT_DOUBLE_ARG_CHECKED(x, 0); |
| 67 Factory* factory = isolate->factory(); |
| 68 double y[2]; |
| 69 int n = fdlibm::rempio2(x, y); |
| 70 Handle<FixedArray> array = factory->NewFixedArray(3); |
| 71 Handle<HeapNumber> y0 = factory->NewHeapNumber(y[0]); |
| 72 Handle<HeapNumber> y1 = factory->NewHeapNumber(y[1]); |
| 73 array->set(0, Smi::FromInt(n)); |
| 74 array->set(1, *y0); |
| 75 array->set(2, *y1); |
| 76 return *factory->NewJSArrayWithElements(array); |
| 77 } |
| 78 |
| 79 |
| 80 static const double kPiDividedBy4 = 0.78539816339744830962; |
| 81 |
| 82 |
| 83 RUNTIME_FUNCTION(Runtime_MathAtan2) { |
| 84 HandleScope scope(isolate); |
| 85 DCHECK(args.length() == 2); |
| 86 isolate->counters()->math_atan2()->Increment(); |
| 87 |
| 88 CONVERT_DOUBLE_ARG_CHECKED(x, 0); |
| 89 CONVERT_DOUBLE_ARG_CHECKED(y, 1); |
| 90 double result; |
| 91 if (std::isinf(x) && std::isinf(y)) { |
| 92 // Make sure that the result in case of two infinite arguments |
| 93 // is a multiple of Pi / 4. The sign of the result is determined |
| 94 // by the first argument (x) and the sign of the second argument |
| 95 // determines the multiplier: one or three. |
| 96 int multiplier = (x < 0) ? -1 : 1; |
| 97 if (y < 0) multiplier *= 3; |
| 98 result = multiplier * kPiDividedBy4; |
| 99 } else { |
| 100 result = std::atan2(x, y); |
| 101 } |
| 102 return *isolate->factory()->NewNumber(result); |
| 103 } |
| 104 |
| 105 |
| 106 RUNTIME_FUNCTION(Runtime_MathExpRT) { |
| 107 HandleScope scope(isolate); |
| 108 DCHECK(args.length() == 1); |
| 109 isolate->counters()->math_exp()->Increment(); |
| 110 |
| 111 CONVERT_DOUBLE_ARG_CHECKED(x, 0); |
| 112 lazily_initialize_fast_exp(); |
| 113 return *isolate->factory()->NewNumber(fast_exp(x)); |
| 114 } |
| 115 |
| 116 |
| 117 RUNTIME_FUNCTION(Runtime_MathFloorRT) { |
| 118 HandleScope scope(isolate); |
| 119 DCHECK(args.length() == 1); |
| 120 isolate->counters()->math_floor()->Increment(); |
| 121 |
| 122 CONVERT_DOUBLE_ARG_CHECKED(x, 0); |
| 123 return *isolate->factory()->NewNumber(Floor(x)); |
| 124 } |
| 125 |
| 126 |
| 127 // Slow version of Math.pow. We check for fast paths for special cases. |
| 128 // Used if VFP3 is not available. |
| 129 RUNTIME_FUNCTION(Runtime_MathPowSlow) { |
| 130 HandleScope scope(isolate); |
| 131 DCHECK(args.length() == 2); |
| 132 isolate->counters()->math_pow()->Increment(); |
| 133 |
| 134 CONVERT_DOUBLE_ARG_CHECKED(x, 0); |
| 135 |
| 136 // If the second argument is a smi, it is much faster to call the |
| 137 // custom powi() function than the generic pow(). |
| 138 if (args[1]->IsSmi()) { |
| 139 int y = args.smi_at(1); |
| 140 return *isolate->factory()->NewNumber(power_double_int(x, y)); |
| 141 } |
| 142 |
| 143 CONVERT_DOUBLE_ARG_CHECKED(y, 1); |
| 144 double result = power_helper(x, y); |
| 145 if (std::isnan(result)) return isolate->heap()->nan_value(); |
| 146 return *isolate->factory()->NewNumber(result); |
| 147 } |
| 148 |
| 149 |
| 150 // Fast version of Math.pow if we know that y is not an integer and y is not |
| 151 // -0.5 or 0.5. Used as slow case from full codegen. |
| 152 RUNTIME_FUNCTION(Runtime_MathPowRT) { |
| 153 HandleScope scope(isolate); |
| 154 DCHECK(args.length() == 2); |
| 155 isolate->counters()->math_pow()->Increment(); |
| 156 |
| 157 CONVERT_DOUBLE_ARG_CHECKED(x, 0); |
| 158 CONVERT_DOUBLE_ARG_CHECKED(y, 1); |
| 159 if (y == 0) { |
| 160 return Smi::FromInt(1); |
| 161 } else { |
| 162 double result = power_double_double(x, y); |
| 163 if (std::isnan(result)) return isolate->heap()->nan_value(); |
| 164 return *isolate->factory()->NewNumber(result); |
| 165 } |
| 166 } |
| 167 |
| 168 |
| 169 RUNTIME_FUNCTION(Runtime_RoundNumber) { |
| 170 HandleScope scope(isolate); |
| 171 DCHECK(args.length() == 1); |
| 172 CONVERT_NUMBER_ARG_HANDLE_CHECKED(input, 0); |
| 173 isolate->counters()->math_round()->Increment(); |
| 174 |
| 175 if (!input->IsHeapNumber()) { |
| 176 DCHECK(input->IsSmi()); |
| 177 return *input; |
| 178 } |
| 179 |
| 180 Handle<HeapNumber> number = Handle<HeapNumber>::cast(input); |
| 181 |
| 182 double value = number->value(); |
| 183 int exponent = number->get_exponent(); |
| 184 int sign = number->get_sign(); |
| 185 |
| 186 if (exponent < -1) { |
| 187 // Number in range ]-0.5..0.5[. These always round to +/-zero. |
| 188 if (sign) return isolate->heap()->minus_zero_value(); |
| 189 return Smi::FromInt(0); |
| 190 } |
| 191 |
| 192 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and |
| 193 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar |
| 194 // argument holds for 32-bit smis). |
| 195 if (!sign && exponent < kSmiValueSize - 2) { |
| 196 return Smi::FromInt(static_cast<int>(value + 0.5)); |
| 197 } |
| 198 |
| 199 // If the magnitude is big enough, there's no place for fraction part. If we |
| 200 // try to add 0.5 to this number, 1.0 will be added instead. |
| 201 if (exponent >= 52) { |
| 202 return *number; |
| 203 } |
| 204 |
| 205 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value(); |
| 206 |
| 207 // Do not call NumberFromDouble() to avoid extra checks. |
| 208 return *isolate->factory()->NewNumber(Floor(value + 0.5)); |
| 209 } |
| 210 |
| 211 |
| 212 RUNTIME_FUNCTION(Runtime_MathSqrtRT) { |
| 213 HandleScope scope(isolate); |
| 214 DCHECK(args.length() == 1); |
| 215 isolate->counters()->math_sqrt()->Increment(); |
| 216 |
| 217 CONVERT_DOUBLE_ARG_CHECKED(x, 0); |
| 218 return *isolate->factory()->NewNumber(fast_sqrt(x)); |
| 219 } |
| 220 |
| 221 |
| 222 RUNTIME_FUNCTION(Runtime_MathFround) { |
| 223 HandleScope scope(isolate); |
| 224 DCHECK(args.length() == 1); |
| 225 |
| 226 CONVERT_DOUBLE_ARG_CHECKED(x, 0); |
| 227 float xf = DoubleToFloat32(x); |
| 228 return *isolate->factory()->NewNumber(xf); |
| 229 } |
| 230 |
| 231 |
| 232 RUNTIME_FUNCTION(RuntimeReference_MathPow) { |
| 233 SealHandleScope shs(isolate); |
| 234 return __RT_impl_Runtime_MathPowSlow(args, isolate); |
| 235 } |
| 236 |
| 237 |
| 238 RUNTIME_FUNCTION(RuntimeReference_IsMinusZero) { |
| 239 SealHandleScope shs(isolate); |
| 240 DCHECK(args.length() == 1); |
| 241 CONVERT_ARG_CHECKED(Object, obj, 0); |
| 242 if (!obj->IsHeapNumber()) return isolate->heap()->false_value(); |
| 243 HeapNumber* number = HeapNumber::cast(obj); |
| 244 return isolate->heap()->ToBoolean(IsMinusZero(number->value())); |
| 245 } |
| 246 } |
| 247 } // namespace v8::internal |
OLD | NEW |