Index: src/x64/lithium-codegen-x64.cc |
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc |
index 985cdc6d98e49c6fd377a9b94edc97e1d3bbbe15..893ec597d42bd43ee9c1b1c82399483a33e8fa1a 100644 |
--- a/src/x64/lithium-codegen-x64.cc |
+++ b/src/x64/lithium-codegen-x64.cc |
@@ -2966,6 +2966,18 @@ void LCodeGen::DoPower(LPower* instr) { |
void LCodeGen::DoRandom(LRandom* instr) { |
+ class DeferredDoRandom: public LDeferredCode { |
+ public: |
+ DeferredDoRandom(LCodeGen* codegen, LRandom* instr) |
+ : LDeferredCode(codegen), instr_(instr) { } |
+ virtual void Generate() { codegen()->DoDeferredRandom(instr_); } |
+ virtual LInstruction* instr() { return instr_; } |
+ private: |
+ LRandom* instr_; |
+ }; |
+ |
+ DeferredDoRandom* deferred = new DeferredDoRandom(this, instr); |
+ |
// Having marked this instruction as a call we can use any |
// registers. |
ASSERT(ToDoubleRegister(instr->result()).is(xmm1)); |
@@ -2980,12 +2992,49 @@ void LCodeGen::DoRandom(LRandom* instr) { |
Register global_object = rdi; |
#endif |
- __ PrepareCallCFunction(1); |
+ static const int kSeedSize = sizeof(uint32_t); |
+ STATIC_ASSERT(kPointerSize == 2 * kSeedSize); |
+ |
__ movq(global_object, |
FieldOperand(global_object, GlobalObject::kGlobalContextOffset)); |
- __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1); |
- __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
+ static const int kRandomSeedOffset = |
+ FixedArray::kHeaderSize + Context::RANDOM_SEED_INDEX * kPointerSize; |
+ __ movq(rbx, FieldOperand(global_object, kRandomSeedOffset)); |
+ // rbx: FixedArray of the global context's random seeds |
+ |
+ // Load state[0]. |
+ __ movl(rax, FieldOperand(rbx, ByteArray::kHeaderSize)); |
+ // If state[0] == 0, call runtime to initialize seeds. |
+ __ testl(rax, rax); |
+ __ j(zero, deferred->entry()); |
+ // Load state[1]. |
+ __ movl(rcx, FieldOperand(rbx, ByteArray::kHeaderSize + kSeedSize)); |
+ |
+ // state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16) |
+ // Only operate on the lower 32 bit of rax. |
+ __ movl(rdx, rax); |
+ __ andl(rdx, Immediate(0xFFFF)); |
+ __ imull(rdx, rdx, Immediate(18273)); |
+ __ shrl(rax, Immediate(16)); |
+ __ addl(rax, rdx); |
+ // Save state[0]. |
+ __ movl(FieldOperand(rbx, ByteArray::kHeaderSize), rax); |
+ |
+ // state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16) |
+ __ movl(rdx, rcx); |
+ __ andl(rdx, Immediate(0xFFFF)); |
+ __ imull(rdx, rdx, Immediate(36969)); |
+ __ shrl(rcx, Immediate(16)); |
+ __ addl(rcx, rdx); |
+ // Save state[1]. |
+ __ movl(FieldOperand(rbx, ByteArray::kHeaderSize + kSeedSize), rcx); |
+ |
+ // Random bit pattern = (state[0] << 14) + (state[1] & 0x3FFFF) |
+ __ shll(rax, Immediate(14)); |
+ __ andl(rcx, Immediate(0x3FFFF)); |
+ __ addl(rax, rcx); |
+ __ bind(deferred->exit()); |
// Convert 32 random bits in rax to 0.(32 random bits) in a double |
// by computing: |
// ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)). |
@@ -2998,6 +3047,14 @@ void LCodeGen::DoRandom(LRandom* instr) { |
} |
+void LCodeGen::DoDeferredRandom(LRandom* instr) { |
+ __ PrepareCallCFunction(1); |
+ __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1); |
+ __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
+ // Return value is in rax. |
+} |
+ |
+ |
void LCodeGen::DoMathLog(LUnaryMathOperation* instr) { |
ASSERT(ToDoubleRegister(instr->result()).is(xmm1)); |
TranscendentalCacheStub stub(TranscendentalCache::LOG, |