OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 5959 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5970 static MaybeObject* Runtime_Math_log(Arguments args) { | 5970 static MaybeObject* Runtime_Math_log(Arguments args) { |
5971 NoHandleAllocation ha; | 5971 NoHandleAllocation ha; |
5972 ASSERT(args.length() == 1); | 5972 ASSERT(args.length() == 1); |
5973 Counters::math_log.Increment(); | 5973 Counters::math_log.Increment(); |
5974 | 5974 |
5975 CONVERT_DOUBLE_CHECKED(x, args[0]); | 5975 CONVERT_DOUBLE_CHECKED(x, args[0]); |
5976 return TranscendentalCache::Get(TranscendentalCache::LOG, x); | 5976 return TranscendentalCache::Get(TranscendentalCache::LOG, x); |
5977 } | 5977 } |
5978 | 5978 |
5979 | 5979 |
5980 // Helper function to compute x^y, where y is known to be an | |
5981 // integer. Uses binary decomposition to limit the number of | |
5982 // multiplications; see the discussion in "Hacker's Delight" by Henry | |
5983 // S. Warren, Jr., figure 11-6, page 213. | |
5984 static double powi(double x, int y) { | |
5985 ASSERT(y != kMinInt); | |
5986 unsigned n = (y < 0) ? -y : y; | |
5987 double m = x; | |
5988 double p = 1; | |
5989 while (true) { | |
5990 if ((n & 1) != 0) p *= m; | |
5991 n >>= 1; | |
5992 if (n == 0) { | |
5993 if (y < 0) { | |
5994 // Unfortunately, we have to be careful when p has reached | |
5995 // infinity in the computation, because sometimes the higher | |
5996 // internal precision in the pow() implementation would have | |
5997 // given us a finite p. This happens very rarely. | |
5998 double result = 1.0 / p; | |
5999 return (result == 0 && isinf(p)) | |
6000 ? pow(x, static_cast<double>(y)) // Avoid pow(double, int). | |
6001 : result; | |
6002 } else { | |
6003 return p; | |
6004 } | |
6005 } | |
6006 m *= m; | |
6007 } | |
6008 } | |
6009 | |
6010 | |
6011 static MaybeObject* Runtime_Math_pow(Arguments args) { | 5980 static MaybeObject* Runtime_Math_pow(Arguments args) { |
6012 NoHandleAllocation ha; | 5981 NoHandleAllocation ha; |
6013 ASSERT(args.length() == 2); | 5982 ASSERT(args.length() == 2); |
6014 Counters::math_pow.Increment(); | 5983 Counters::math_pow.Increment(); |
6015 | 5984 |
6016 CONVERT_DOUBLE_CHECKED(x, args[0]); | 5985 CONVERT_DOUBLE_CHECKED(x, args[0]); |
6017 | 5986 |
6018 // If the second argument is a smi, it is much faster to call the | 5987 // If the second argument is a smi, it is much faster to call the |
6019 // custom powi() function than the generic pow(). | 5988 // custom powi() function than the generic pow(). |
6020 if (args[1]->IsSmi()) { | 5989 if (args[1]->IsSmi()) { |
6021 int y = Smi::cast(args[1])->value(); | 5990 int y = Smi::cast(args[1])->value(); |
6022 return Heap::NumberFromDouble(powi(x, y)); | 5991 return Heap::NumberFromDouble(power_double_int(x, y)); |
6023 } | 5992 } |
6024 | 5993 |
6025 CONVERT_DOUBLE_CHECKED(y, args[1]); | 5994 CONVERT_DOUBLE_CHECKED(y, args[1]); |
6026 | 5995 return Heap::AllocateHeapNumber(power_double_double(x, y)); |
6027 if (!isinf(x)) { | |
6028 if (y == 0.5) { | |
6029 // It's not uncommon to use Math.pow(x, 0.5) to compute the | |
6030 // square root of a number. To speed up such computations, we | |
6031 // explictly check for this case and use the sqrt() function | |
6032 // which is faster than pow(). | |
6033 return Heap::AllocateHeapNumber(sqrt(x)); | |
6034 } else if (y == -0.5) { | |
6035 // Optimized using Math.pow(x, -0.5) == 1 / Math.pow(x, 0.5). | |
6036 return Heap::AllocateHeapNumber(1.0 / sqrt(x)); | |
6037 } | |
6038 } | |
6039 | |
6040 if (y == 0) { | |
6041 return Smi::FromInt(1); | |
6042 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) { | |
6043 return Heap::nan_value(); | |
6044 } else { | |
6045 return Heap::AllocateHeapNumber(pow(x, y)); | |
6046 } | |
6047 } | 5996 } |
6048 | 5997 |
6049 // Fast version of Math.pow if we know that y is not an integer and | 5998 // Fast version of Math.pow if we know that y is not an integer and |
6050 // y is not -0.5 or 0.5. Used as slowcase from codegen. | 5999 // y is not -0.5 or 0.5. Used as slowcase from codegen. |
6051 static MaybeObject* Runtime_Math_pow_cfunction(Arguments args) { | 6000 static MaybeObject* Runtime_Math_pow_cfunction(Arguments args) { |
6052 NoHandleAllocation ha; | 6001 NoHandleAllocation ha; |
6053 ASSERT(args.length() == 2); | 6002 ASSERT(args.length() == 2); |
6054 CONVERT_DOUBLE_CHECKED(x, args[0]); | 6003 CONVERT_DOUBLE_CHECKED(x, args[0]); |
6055 CONVERT_DOUBLE_CHECKED(y, args[1]); | 6004 CONVERT_DOUBLE_CHECKED(y, args[1]); |
6056 if (y == 0) { | 6005 if (y == 0) { |
6057 return Smi::FromInt(1); | 6006 return Smi::FromInt(1); |
6058 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) { | 6007 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) { |
6059 return Heap::nan_value(); | 6008 return Heap::nan_value(); |
6060 } else { | 6009 } else { |
6061 return Heap::AllocateHeapNumber(pow(x, y)); | 6010 return Heap::AllocateHeapNumber(pow(x, y)); |
6062 } | 6011 } |
6063 } | 6012 } |
6064 | 6013 |
6065 | 6014 |
6066 static MaybeObject* Runtime_RoundNumber(Arguments args) { | 6015 static MaybeObject* Runtime_RoundNumber(Arguments args) { |
6067 NoHandleAllocation ha; | 6016 NoHandleAllocation ha; |
6068 ASSERT(args.length() == 1); | 6017 ASSERT(args.length() == 1); |
6069 Counters::math_round.Increment(); | 6018 Counters::math_round.Increment(); |
6070 | 6019 |
6071 if (!args[0]->IsHeapNumber()) { | 6020 if (!args[0]->IsHeapNumber()) { |
(...skipping 4712 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10784 } else { | 10733 } else { |
10785 // Handle last resort GC and make sure to allow future allocations | 10734 // Handle last resort GC and make sure to allow future allocations |
10786 // to grow the heap without causing GCs (if possible). | 10735 // to grow the heap without causing GCs (if possible). |
10787 Counters::gc_last_resort_from_js.Increment(); | 10736 Counters::gc_last_resort_from_js.Increment(); |
10788 Heap::CollectAllGarbage(false); | 10737 Heap::CollectAllGarbage(false); |
10789 } | 10738 } |
10790 } | 10739 } |
10791 | 10740 |
10792 | 10741 |
10793 } } // namespace v8::internal | 10742 } } // namespace v8::internal |
OLD | NEW |