} else {
int attempts = 0;
do {
- hash_value = random() & i::Smi::kMaxValue; // Limit range to fit a smi.
+ // Generate a random 32-bit hash value but limit range to fit
+ // within a smi.
+ hash_value = i::V8::Random() & i::Smi::kMaxValue;
attempts++;
} while (hash_value == 0 && attempts < 30);
hash_value = hash_value != 0 ? hash_value : 1; // never return 0
}
+void CodeGenerator::GenerateRandomPositiveSmi(ZoneList<Expression*>* args) {
+ VirtualFrame::SpilledScope spilled_scope;
+ ASSERT(args->length() == 0);
+ __ Call(ExternalReference::random_positive_smi_function().address(),
+ RelocInfo::RUNTIME_ENTRY);
+ frame_->EmitPush(r0);
+}
+
+
void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) {
VirtualFrame::SpilledScope spilled_scope;
ASSERT(args->length() == 2);
void GenerateLog(ZoneList<Expression*>* args);
+ // Fast support for Math.random().
+ void GenerateRandomPositiveSmi(ZoneList<Expression*>* args);
+
// Methods and constants for fast case switch statement support.
//
// Only allow fast-case switch if the range of labels is at most
}
+ExternalReference ExternalReference::random_positive_smi_function() {
+ return ExternalReference(Redirect(FUNCTION_ADDR(V8::RandomPositiveSmi)));
+}
+
+
ExternalReference ExternalReference::the_hole_value_location() {
return ExternalReference(Factory::the_hole_value().location());
}
// ExternalReferenceTable in serialize.cc manually.
static ExternalReference perform_gc_function();
-
static ExternalReference builtin_passed_function();
+ static ExternalReference random_positive_smi_function();
// Static variable Factory::the_hole_value.location()
static ExternalReference the_hole_value_location();
{&CodeGenerator::GenerateSetValueOf, "_SetValueOf"},
{&CodeGenerator::GenerateFastCharCodeAt, "_FastCharCodeAt"},
{&CodeGenerator::GenerateObjectEquals, "_ObjectEquals"},
- {&CodeGenerator::GenerateLog, "_Log"}
+ {&CodeGenerator::GenerateLog, "_Log"},
+ {&CodeGenerator::GenerateRandomPositiveSmi, "_RandomPositiveSmi"}
};
}
+void CodeGenerator::GenerateRandomPositiveSmi(ZoneList<Expression*>* args) {
+ ASSERT(args->length() == 0);
+ frame_->SpillAll();
+ __ call(FUNCTION_ADDR(V8::RandomPositiveSmi), RelocInfo::RUNTIME_ENTRY);
+ Result result = allocator_->Allocate(eax);
+ frame_->Push(&result);
+}
+
+
void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
if (CheckForInlineRuntimeCall(node)) {
return;
void GenerateGetFramePointer(ZoneList<Expression*>* args);
+ // Fast support for Math.random().
+ void GenerateRandomPositiveSmi(ZoneList<Expression*>* args);
+
// Methods and constants for fast case switch statement support.
//
// Only allow fast-case switch if the range of labels is at most
// ECMA 262 - 15.8.2.1
function MathAbs(x) {
- if (%_IsSmi(x)) {
- return x >= 0 ? x : -x;
- } else {
- return %Math_abs(ToNumber(x));
- }
+ if (%_IsSmi(x)) return x >= 0 ? x : -x;
+ if (!IS_NUMBER(x)) x = ToNumber(x);
+ return %Math_abs(x);
}
// ECMA 262 - 15.8.2.2
-function MathAcos(x) { return %Math_acos(ToNumber(x)); }
+function MathAcos(x) {
+ if (!IS_NUMBER(x)) x = ToNumber(x);
+ return %Math_acos(x);
+}
// ECMA 262 - 15.8.2.3
-function MathAsin(x) { return %Math_asin(ToNumber(x)); }
+function MathAsin(x) {
+ if (!IS_NUMBER(x)) x = ToNumber(x);
+ return %Math_asin(x);
+}
// ECMA 262 - 15.8.2.4
-function MathAtan(x) { return %Math_atan(ToNumber(x)); }
+function MathAtan(x) {
+ if (!IS_NUMBER(x)) x = ToNumber(x);
+ return %Math_atan(x);
+}
// ECMA 262 - 15.8.2.5
-function MathAtan2(x, y) { return %Math_atan2(ToNumber(x), ToNumber(y)); }
+function MathAtan2(x, y) {
+ if (!IS_NUMBER(x)) x = ToNumber(x);
+ if (!IS_NUMBER(y)) y = ToNumber(y);
+ return %Math_atan2(x, y);
+}
// ECMA 262 - 15.8.2.6
-function MathCeil(x) { return %Math_ceil(ToNumber(x)); }
+function MathCeil(x) {
+ if (!IS_NUMBER(x)) x = ToNumber(x);
+ return %Math_ceil(x);
+}
// ECMA 262 - 15.8.2.7
-function MathCos(x) { return %Math_cos(ToNumber(x)); }
+function MathCos(x) {
+ if (!IS_NUMBER(x)) x = ToNumber(x);
+ return %Math_cos(x);
+}
// ECMA 262 - 15.8.2.8
-function MathExp(x) { return %Math_exp(ToNumber(x)); }
+function MathExp(x) {
+ if (!IS_NUMBER(x)) x = ToNumber(x);
+ return %Math_exp(x);
+}
// ECMA 262 - 15.8.2.9
-function MathFloor(x) { return %Math_floor(ToNumber(x)); }
+function MathFloor(x) {
+ if (!IS_NUMBER(x)) x = ToNumber(x);
+ if (0 < x && x <= 0xFFFFFFFF) {
+ // Numbers in the range [0, 2^32) can be floored by converting
+ // them to an unsigned 32-bit value using the shift operator.
+ // We avoid doing so for -0, because the result of Math.floor(-0)
+ // has to be -0, which wouldn't be the case with the shift.
+ return x << 0;
+ } else {
+ return %Math_floor(x);
+ }
+}
// ECMA 262 - 15.8.2.10
-function MathLog(x) { return %Math_log(ToNumber(x)); }
+function MathLog(x) {
+ if (!IS_NUMBER(x)) x = ToNumber(x);
+ return %Math_log(x);
+}
// ECMA 262 - 15.8.2.11
function MathMax(arg1, arg2) { // length == 2
}
// ECMA 262 - 15.8.2.13
-function MathPow(x, y) { return %Math_pow(ToNumber(x), ToNumber(y)); }
+function MathPow(x, y) {
+ if (!IS_NUMBER(x)) x = ToNumber(x);
+ if (!IS_NUMBER(y)) y = ToNumber(y);
+ return %Math_pow(x, y);
+}
// ECMA 262 - 15.8.2.14
-function MathRandom() { return %Math_random(); }
+function MathRandom() {
+ return %_RandomPositiveSmi() / 0x40000000;
+}
// ECMA 262 - 15.8.2.15
-function MathRound(x) { return %Math_round(ToNumber(x)); }
+function MathRound(x) {
+ if (!IS_NUMBER(x)) x = ToNumber(x);
+ return %Math_round(x);
+}
// ECMA 262 - 15.8.2.16
-function MathSin(x) { return %Math_sin(ToNumber(x)); }
+function MathSin(x) {
+ if (!IS_NUMBER(x)) x = ToNumber(x);
+ return %Math_sin(x);
+}
// ECMA 262 - 15.8.2.17
-function MathSqrt(x) { return %Math_sqrt(ToNumber(x)); }
+function MathSqrt(x) {
+ if (!IS_NUMBER(x)) x = ToNumber(x);
+ return %Math_sqrt(x);
+}
// ECMA 262 - 15.8.2.18
-function MathTan(x) { return %Math_tan(ToNumber(x)); }
+function MathTan(x) {
+ if (!IS_NUMBER(x)) x = ToNumber(x);
+ return %Math_tan(x);
+}
// -------------------------------------------------------------------
}
}
-// Returns a number value with positive sign, greater than or equal to
-// 0 but less than 1, chosen randomly.
-static Object* Runtime_Math_random(Arguments args) {
- NoHandleAllocation ha;
- ASSERT(args.length() == 0);
-
- // To get much better precision, we combine the results of two
- // invocations of random(). The result is computed by normalizing a
- // double in the range [0, RAND_MAX + 1) obtained by adding the
- // high-order bits in the range [0, RAND_MAX] with the low-order
- // bits in the range [0, 1).
- double lo = static_cast<double>(random()) * (1.0 / (RAND_MAX + 1.0));
- double hi = static_cast<double>(random());
- double result = (hi + lo) * (1.0 / (RAND_MAX + 1.0));
- ASSERT(result >= 0 && result < 1);
- return Heap::AllocateHeapNumber(result);
-}
-
static Object* Runtime_Math_round(Arguments args) {
NoHandleAllocation ha;
F(Math_floor, 1) \
F(Math_log, 1) \
F(Math_pow, 2) \
- F(Math_random, 0) \
F(Math_round, 1) \
F(Math_sin, 1) \
F(Math_sqrt, 1) \
RUNTIME_ENTRY,
1,
"Runtime::PerformGC");
+ Add(ExternalReference::random_positive_smi_function().address(),
+ RUNTIME_ENTRY,
+ 2,
+ "V8::RandomPositiveSmi");
// Miscellaneous
Add(ExternalReference::builtin_passed_function().address(),
}
+uint32_t V8::Random() {
+ // Random number generator using George Marsaglia's MWC algorithm.
+ static uint32_t hi = 0;
+ static uint32_t lo = 0;
+
+ // Initialize seed using the system random(). If one of the seeds
+ // should ever become zero again, or if random() returns zero, we
+ // avoid getting stuck with zero bits in hi or lo by re-initializing
+ // them on demand.
+ if (hi == 0) hi = random();
+ if (lo == 0) lo = random();
+
+ // Mix the bits.
+ hi = 36969 * (hi & 0xFFFF) + (hi >> 16);
+ lo = 18273 * (lo & 0xFFFF) + (lo >> 16);
+ return (hi << 16) + (lo & 0xFFFF);
+}
+
+
+Smi* V8::RandomPositiveSmi() {
+ uint32_t random = Random();
+ ASSERT(IsPowerOf2(Smi::kMaxValue + 1));
+ return Smi::FromInt(random & Smi::kMaxValue);
+}
+
} } // namespace v8::internal
public:
// Global actions.
- // If Initialize is called with des == NULL, the
- // initial state is created from scratch. If a non-null Deserializer
- // is given, the initial state is created by reading the
- // deserialized data into an empty heap.
+ // If Initialize is called with des == NULL, the initial state is
+ // created from scratch. If a non-null Deserializer is given, the
+ // initial state is created by reading the deserialized data into an
+ // empty heap.
static bool Initialize(Deserializer* des);
static void TearDown();
static bool IsRunning() { return is_running_; }
// Report process out of memory. Implementation found in api.cc.
static void FatalProcessOutOfMemory(const char* location);
+
+ // Random number generation support. Not cryptographically safe.
+ static uint32_t Random();
+ static Smi* RandomPositiveSmi();
+
private:
// True if engine is currently running
static bool is_running_;