}
+void FullCodeGenerator::EmitRandomHeapNumber(CallRuntime* expr) {
+ ASSERT(expr->arguments()->length() == 0);
+ Label slow_allocate_heapnumber;
+ Label heapnumber_allocated;
+
+ __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex);
+ __ AllocateHeapNumber(r4, r1, r2, r6, &slow_allocate_heapnumber);
+ __ jmp(&heapnumber_allocated);
+
+ __ bind(&slow_allocate_heapnumber);
+ // Allocate a heap number.
+ __ CallRuntime(Runtime::kNumberAlloc, 0);
+ __ mov(r4, Operand(r0));
+
+ __ bind(&heapnumber_allocated);
+
+ // Convert 32 random bits in r0 to 0.(32 random bits) in a double
+ // by computing:
+ // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
+ __ PrepareCallCFunction(1, r0);
+ __ ldr(r0,
+ ContextOperand(context_register(), Context::GLOBAL_OBJECT_INDEX));
+ __ ldr(r0, FieldMemOperand(r0, GlobalObject::kNativeContextOffset));
+ __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
+
+ // 0x41300000 is the top half of 1.0 x 2^20 as a double.
+ // Create this constant using mov/orr to avoid PC relative load.
+ __ mov(r1, Operand(0x41000000));
+ __ orr(r1, r1, Operand(0x300000));
+ // Move 0x41300000xxxxxxxx (x = random bits) to VFP.
+ __ vmov(d7, r0, r1);
+ // Move 0x4130000000000000 to VFP.
+ __ mov(r0, Operand::Zero());
+ __ vmov(d8, r0, r1);
+ // Subtract and store the result in the heap number.
+ __ vsub(d7, d7, d8);
+ __ sub(r0, r4, Operand(kHeapObjectTag));
+ __ vstr(d7, r0, HeapNumber::kValueOffset);
+ __ mov(r0, r4);
+
+ context()->Plug(r0);
+}
+
+
void FullCodeGenerator::EmitSubString(CallRuntime* expr) {
// Load the arguments on the stack and call the stub.
SubStringStub stub;
}
+LInstruction* LChunkBuilder::DoRandom(HRandom* instr) {
+ ASSERT(instr->representation().IsDouble());
+ ASSERT(instr->global_object()->representation().IsTagged());
+ LOperand* global_object = UseTempRegister(instr->global_object());
+ LOperand* scratch = TempRegister();
+ LOperand* scratch2 = TempRegister();
+ LOperand* scratch3 = TempRegister();
+ LRandom* result = new(zone()) LRandom(
+ global_object, scratch, scratch2, scratch3);
+ return DefineFixedDouble(result, d7);
+}
+
+
LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
ASSERT(instr->left()->representation().IsTagged());
ASSERT(instr->right()->representation().IsTagged());
V(Parameter) \
V(Power) \
V(PushArgument) \
+ V(Random) \
V(RegExpLiteral) \
V(Return) \
V(SeqStringGetChar) \
};
+class LRandom V8_FINAL : public LTemplateInstruction<1, 1, 3> {
+ public:
+ LRandom(LOperand* global_object,
+ LOperand* scratch,
+ LOperand* scratch2,
+ LOperand* scratch3) {
+ inputs_[0] = global_object;
+ temps_[0] = scratch;
+ temps_[1] = scratch2;
+ temps_[2] = scratch3;
+ }
+
+ LOperand* global_object() const { return inputs_[0]; }
+ LOperand* scratch() const { return temps_[0]; }
+ LOperand* scratch2() const { return temps_[1]; }
+ LOperand* scratch3() const { return temps_[2]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(Random, "random")
+ DECLARE_HYDROGEN_ACCESSOR(Random)
+};
+
+
class LArithmeticD V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
LArithmeticD(Token::Value op, LOperand* left, LOperand* right)
}
+void LCodeGen::DoRandom(LRandom* instr) {
+ // Assert that the register size is indeed the size of each seed.
+ static const int kSeedSize = sizeof(uint32_t);
+ STATIC_ASSERT(kPointerSize == kSeedSize);
+
+ // Load native context
+ Register global_object = ToRegister(instr->global_object());
+ Register native_context = global_object;
+ __ ldr(native_context, FieldMemOperand(
+ global_object, GlobalObject::kNativeContextOffset));
+
+ // Load state (FixedArray of the native context's random seeds)
+ static const int kRandomSeedOffset =
+ FixedArray::kHeaderSize + Context::RANDOM_SEED_INDEX * kPointerSize;
+ Register state = native_context;
+ __ ldr(state, FieldMemOperand(native_context, kRandomSeedOffset));
+
+ // Load state[0].
+ Register state0 = ToRegister(instr->scratch());
+ __ ldr(state0, FieldMemOperand(state, ByteArray::kHeaderSize));
+ // Load state[1].
+ Register state1 = ToRegister(instr->scratch2());
+ __ ldr(state1, FieldMemOperand(state, ByteArray::kHeaderSize + kSeedSize));
+
+ // state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16)
+ Register scratch3 = ToRegister(instr->scratch3());
+ Register scratch4 = scratch0();
+ __ and_(scratch3, state0, Operand(0xFFFF));
+ __ mov(scratch4, Operand(18273));
+ __ mul(scratch3, scratch3, scratch4);
+ __ add(state0, scratch3, Operand(state0, LSR, 16));
+ // Save state[0].
+ __ str(state0, FieldMemOperand(state, ByteArray::kHeaderSize));
+
+ // state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16)
+ __ and_(scratch3, state1, Operand(0xFFFF));
+ __ mov(scratch4, Operand(36969));
+ __ mul(scratch3, scratch3, scratch4);
+ __ add(state1, scratch3, Operand(state1, LSR, 16));
+ // Save state[1].
+ __ str(state1, FieldMemOperand(state, ByteArray::kHeaderSize + kSeedSize));
+
+ // Random bit pattern = (state[0] << 14) + (state[1] & 0x3FFFF)
+ Register random = scratch4;
+ __ and_(random, state1, Operand(0x3FFFF));
+ __ add(random, random, Operand(state0, LSL, 14));
+
+ // 0x41300000 is the top half of 1.0 x 2^20 as a double.
+ // Create this constant using mov/orr to avoid PC relative load.
+ __ mov(scratch3, Operand(0x41000000));
+ __ orr(scratch3, scratch3, Operand(0x300000));
+ // Move 0x41300000xxxxxxxx (x = random bits) to VFP.
+ DwVfpRegister result = ToDoubleRegister(instr->result());
+ __ vmov(result, random, scratch3);
+ // Move 0x4130000000000000 to VFP.
+ __ mov(scratch4, Operand::Zero());
+ DwVfpRegister scratch5 = double_scratch0();
+ __ vmov(scratch5, scratch4, scratch3);
+ __ vsub(result, result, scratch5);
+}
+
+
void LCodeGen::DoMathExp(LMathExp* instr) {
DwVfpRegister input = ToDoubleRegister(instr->value());
DwVfpRegister result = ToDoubleRegister(instr->result());
}
+ExternalReference ExternalReference::random_uint32_function(
+ Isolate* isolate) {
+ return ExternalReference(Redirect(isolate, FUNCTION_ADDR(V8::Random)));
+}
+
+
ExternalReference ExternalReference::get_date_field_function(
Isolate* isolate) {
return ExternalReference(Redirect(isolate, FUNCTION_ADDR(JSDate::GetField)));
Isolate* isolate);
static ExternalReference flush_icache_function(Isolate* isolate);
static ExternalReference perform_gc_function(Isolate* isolate);
+ static ExternalReference random_uint32_function(Isolate* isolate);
static ExternalReference transcendental_cache_array_address(Isolate* isolate);
static ExternalReference delete_handle_scope_extensions(Isolate* isolate);
#include "objects-visiting.h"
#include "platform.h"
#include "snapshot.h"
-#include "trig-table.h"
#include "extensions/externalize-string-extension.h"
#include "extensions/gc-extension.h"
#include "extensions/statistics-extension.h"
// Initialize the embedder data slot.
Handle<FixedArray> embedder_data = factory->NewFixedArray(2);
native_context()->set_embedder_data(*embedder_data);
+
+ // Allocate the random seed slot.
+ Handle<ByteArray> random_seed = factory->NewByteArray(kRandomStateSize);
+ native_context()->set_random_seed(*random_seed);
}
InitializeExperimentalGlobal();
if (!InstallExperimentalNatives()) return;
- // We can't (de-)serialize typed arrays currently, but we are lucky: The state
- // of the random number generator and the trigonometric lookup tables needs no
- // initialization during snapshot creation time.
- uint32_t* state = NULL;
- if (!Serializer::enabled()) {
- // Initially seed the per-context random number generator using the
- // per-isolate random number generator.
- const int num_elems = 2;
- state = new uint32_t[num_elems];
- const int num_bytes = num_elems * sizeof(*state);
-
- do {
- isolate->random_number_generator()->NextBytes(state, num_bytes);
- } while (state[0] == 0 || state[1] == 0);
-
- v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(state, num_bytes);
- v8::Local<v8::Uint32Array> ta = v8::Uint32Array::New(buffer, 0, num_elems);
- Handle<JSBuiltinsObject> builtins(native_context()->builtins());
- ForceSetProperty(builtins,
- factory()->InternalizeOneByteString(
- STATIC_ASCII_VECTOR("rngstate")),
- Utils::OpenHandle(*ta),
- NONE);
-
- // Initialize trigonometric lookup tables and constants.
- const int table_num_bytes = TrigonometricLookupTable::table_num_bytes();
- v8::Local<v8::ArrayBuffer> sin_buffer = v8::ArrayBuffer::New(
- TrigonometricLookupTable::sin_table(), table_num_bytes);
- v8::Local<v8::ArrayBuffer> cos_buffer = v8::ArrayBuffer::New(
- TrigonometricLookupTable::cos_x_interval_table(), table_num_bytes);
- v8::Local<v8::Float64Array> sin_table = v8::Float64Array::New(
- sin_buffer, 0, TrigonometricLookupTable::table_size());
- v8::Local<v8::Float64Array> cos_table = v8::Float64Array::New(
- cos_buffer, 0, TrigonometricLookupTable::table_size());
-
- ForceSetProperty(builtins,
- factory()->InternalizeOneByteString(
- STATIC_ASCII_VECTOR("kSinTable")),
- Utils::OpenHandle(*sin_table),
- NONE);
- ForceSetProperty(builtins,
- factory()->InternalizeOneByteString(
- STATIC_ASCII_VECTOR("kCosXIntervalTable")),
- Utils::OpenHandle(*cos_table),
- NONE);
- ForceSetProperty(builtins,
- factory()->InternalizeOneByteString(
- STATIC_ASCII_VECTOR("kSamples")),
- factory()->NewHeapNumber(
- TrigonometricLookupTable::samples()),
- NONE);
- ForceSetProperty(builtins,
- factory()->InternalizeOneByteString(
- STATIC_ASCII_VECTOR("kIndexConvert")),
- factory()->NewHeapNumber(
- TrigonometricLookupTable::samples_over_pi_half()),
- NONE);
- }
- // TODO(svenpanne) We have to delete the state when the context dies, so we
- // remember it in the context (encoded as a Smi, our usual technique for
- // aligned pointers) and do the cleanup in
- // WeakListVisitor<Context>::VisitPhantomObject(). This hack can go away when
- // we have a way to allocate the backing store of typed arrays on the heap.
- ASSERT(reinterpret_cast<Smi*>(state)->IsSmi());
- native_context()->set_random_state(reinterpret_cast<Smi*>(state));
+ // Initially seed the per-context random number generator
+ // using the per-isolate random number generator.
+ uint32_t* state = reinterpret_cast<uint32_t*>(
+ native_context()->random_seed()->GetDataStartAddress());
+ do {
+ isolate->random_number_generator()->NextBytes(state, kRandomStateSize);
+ } while (state[0] == 0 || state[1] == 0);
result_ = native_context();
}
V(GENERATOR_OBJECT_PROTOTYPE_MAP_INDEX, Map, \
generator_object_prototype_map) \
V(GENERATOR_RESULT_MAP_INDEX, Map, generator_result_map) \
- V(RANDOM_STATE_INDEX, Smi, random_state)
+ V(RANDOM_SEED_INDEX, ByteArray, random_seed)
// JSFunctions are pairs (context, function code), sometimes also called
// closures. A Context object is used to represent function contexts and
STRICT_MODE_GENERATOR_FUNCTION_MAP_INDEX,
GENERATOR_OBJECT_PROTOTYPE_MAP_INDEX,
GENERATOR_RESULT_MAP_INDEX,
- RANDOM_STATE_INDEX,
+ RANDOM_SEED_INDEX,
// Properties from here are treated as weak references by the full GC.
// Scavenge treats them as strong references.
const int kDoubleSizeLog2 = 3;
+// Size of the state of a the random number generator.
+const int kRandomStateSize = 2 * kIntSize;
+
#if V8_HOST_ARCH_64_BIT
const int kPointerSizeLog2 = 3;
const intptr_t kIntptrSignBit = V8_INT64_C(0x8000000000000000);
}
}
- static void VisitPhantomObject(Heap*, Context* context) {
- // A bit of a hack, see the comment at the end of Genesis::Genesis().
- delete[] reinterpret_cast<uint32_t*>(context->random_state());
+ static void VisitPhantomObject(Heap*, Context*) {
}
static int WeakNextOffset() {
V(Parameter) \
V(Power) \
V(PushArgument) \
+ V(Random) \
V(RegExpLiteral) \
V(Return) \
V(Ror) \
};
+class HRandom V8_FINAL : public HTemplateInstruction<1> {
+ public:
+ DECLARE_INSTRUCTION_FACTORY_P1(HRandom, HValue*);
+
+ HValue* global_object() { return OperandAt(0); }
+
+ virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
+ return Representation::Tagged();
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(Random)
+
+ private:
+ explicit HRandom(HValue* global_object) {
+ SetOperandAt(0, global_object);
+ set_representation(Representation::Double());
+ }
+
+ virtual bool IsDeletable() const V8_OVERRIDE { return true; }
+};
+
+
class HAdd V8_FINAL : public HArithmeticBinaryOperation {
public:
static HInstruction* New(Zone* zone,
return true;
}
break;
+ case kMathRandom:
+ if (argument_count == 1 && check_type == RECEIVER_MAP_CHECK) {
+ AddCheckConstantFunction(expr->holder(), receiver, receiver_map);
+ Drop(1); // Receiver.
+ HGlobalObject* global_object = Add<HGlobalObject>();
+ HRandom* result = New<HRandom>(global_object);
+ ast_context()->ReturnInstruction(result, expr->id());
+ return true;
+ }
+ break;
case kMathMax:
case kMathMin:
if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) {
}
+// Fast support for Math.random().
+void HOptimizedGraphBuilder::GenerateRandomHeapNumber(CallRuntime* call) {
+ HGlobalObject* global_object = Add<HGlobalObject>();
+ HRandom* result = New<HRandom>(global_object);
+ return ast_context()->ReturnInstruction(result, call->id());
+}
+
+
// Fast support for StringAdd.
void HOptimizedGraphBuilder::GenerateStringAdd(CallRuntime* call) {
ASSERT_EQ(2, call->arguments()->length());
}
+void FullCodeGenerator::EmitRandomHeapNumber(CallRuntime* expr) {
+ ASSERT(expr->arguments()->length() == 0);
+
+ Label slow_allocate_heapnumber;
+ Label heapnumber_allocated;
+
+ __ AllocateHeapNumber(edi, ebx, ecx, &slow_allocate_heapnumber);
+ __ jmp(&heapnumber_allocated);
+
+ __ bind(&slow_allocate_heapnumber);
+ // Allocate a heap number.
+ __ CallRuntime(Runtime::kNumberAlloc, 0);
+ __ mov(edi, eax);
+
+ __ bind(&heapnumber_allocated);
+
+ __ PrepareCallCFunction(1, ebx);
+ __ mov(eax, ContextOperand(context_register(), Context::GLOBAL_OBJECT_INDEX));
+ __ mov(eax, FieldOperand(eax, GlobalObject::kNativeContextOffset));
+ __ mov(Operand(esp, 0), eax);
+ __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
+
+ // Convert 32 random bits in eax to 0.(32 random bits) in a double
+ // by computing:
+ // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
+ // This is implemented on both SSE2 and FPU.
+ if (CpuFeatures::IsSupported(SSE2)) {
+ CpuFeatureScope fscope(masm(), SSE2);
+ __ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
+ __ movd(xmm1, ebx);
+ __ movd(xmm0, eax);
+ __ cvtss2sd(xmm1, xmm1);
+ __ xorps(xmm0, xmm1);
+ __ subsd(xmm0, xmm1);
+ __ movsd(FieldOperand(edi, HeapNumber::kValueOffset), xmm0);
+ } else {
+ // 0x4130000000000000 is 1.0 x 2^20 as a double.
+ __ mov(FieldOperand(edi, HeapNumber::kExponentOffset),
+ Immediate(0x41300000));
+ __ mov(FieldOperand(edi, HeapNumber::kMantissaOffset), eax);
+ __ fld_d(FieldOperand(edi, HeapNumber::kValueOffset));
+ __ mov(FieldOperand(edi, HeapNumber::kMantissaOffset), Immediate(0));
+ __ fld_d(FieldOperand(edi, HeapNumber::kValueOffset));
+ __ fsubp(1);
+ __ fstp_d(FieldOperand(edi, HeapNumber::kValueOffset));
+ }
+ __ mov(eax, edi);
+ context()->Plug(eax);
+}
+
+
void FullCodeGenerator::EmitSubString(CallRuntime* expr) {
// Load the arguments on the stack and call the stub.
SubStringStub stub;
}
+void LCodeGen::DoRandom(LRandom* instr) {
+ CpuFeatureScope scope(masm(), SSE2);
+
+ // Assert that the register size is indeed the size of each seed.
+ static const int kSeedSize = sizeof(uint32_t);
+ STATIC_ASSERT(kPointerSize == kSeedSize);
+
+ // Load native context
+ Register global_object = ToRegister(instr->global_object());
+ Register native_context = global_object;
+ __ mov(native_context, FieldOperand(
+ global_object, GlobalObject::kNativeContextOffset));
+
+ // Load state (FixedArray of the native context's random seeds)
+ static const int kRandomSeedOffset =
+ FixedArray::kHeaderSize + Context::RANDOM_SEED_INDEX * kPointerSize;
+ Register state = native_context;
+ __ mov(state, FieldOperand(native_context, kRandomSeedOffset));
+
+ // Load state[0].
+ Register state0 = ToRegister(instr->scratch());
+ __ mov(state0, FieldOperand(state, ByteArray::kHeaderSize));
+ // Load state[1].
+ Register state1 = ToRegister(instr->scratch2());
+ __ mov(state1, FieldOperand(state, ByteArray::kHeaderSize + kSeedSize));
+
+ // state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16)
+ Register scratch3 = ToRegister(instr->scratch3());
+ __ movzx_w(scratch3, state0);
+ __ imul(scratch3, scratch3, 18273);
+ __ shr(state0, 16);
+ __ add(state0, scratch3);
+ // Save state[0].
+ __ mov(FieldOperand(state, ByteArray::kHeaderSize), state0);
+
+ // state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16)
+ __ movzx_w(scratch3, state1);
+ __ imul(scratch3, scratch3, 36969);
+ __ shr(state1, 16);
+ __ add(state1, scratch3);
+ // Save state[1].
+ __ mov(FieldOperand(state, ByteArray::kHeaderSize + kSeedSize), state1);
+
+ // Random bit pattern = (state[0] << 14) + (state[1] & 0x3FFFF)
+ Register random = state0;
+ __ shl(random, 14);
+ __ and_(state1, Immediate(0x3FFFF));
+ __ add(random, state1);
+
+ // Convert 32 random bits in random to 0.(32 random bits) in a double
+ // by computing:
+ // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
+ XMMRegister result = ToDoubleRegister(instr->result());
+ XMMRegister scratch4 = double_scratch0();
+ __ mov(scratch3, Immediate(0x49800000)); // 1.0 x 2^20 as single.
+ __ movd(scratch4, scratch3);
+ __ movd(result, random);
+ __ cvtss2sd(scratch4, scratch4);
+ __ xorps(result, scratch4);
+ __ subsd(result, scratch4);
+}
+
+
void LCodeGen::DoMathLog(LMathLog* instr) {
CpuFeatureScope scope(masm(), SSE2);
ASSERT(instr->value()->Equals(instr->result()));
}
+LInstruction* LChunkBuilder::DoRandom(HRandom* instr) {
+ ASSERT(instr->representation().IsDouble());
+ ASSERT(instr->global_object()->representation().IsTagged());
+ LOperand* global_object = UseTempRegister(instr->global_object());
+ LOperand* scratch = TempRegister();
+ LOperand* scratch2 = TempRegister();
+ LOperand* scratch3 = TempRegister();
+ LRandom* result = new(zone()) LRandom(
+ global_object, scratch, scratch2, scratch3);
+ return DefineFixedDouble(result, xmm1);
+}
+
+
LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
ASSERT(instr->left()->representation().IsSmiOrTagged());
ASSERT(instr->right()->representation().IsSmiOrTagged());
V(OuterContext) \
V(Parameter) \
V(Power) \
+ V(Random) \
V(PushArgument) \
V(RegExpLiteral) \
V(Return) \
};
+class LRandom V8_FINAL : public LTemplateInstruction<1, 1, 3> {
+ public:
+ LRandom(LOperand* global_object,
+ LOperand* scratch,
+ LOperand* scratch2,
+ LOperand* scratch3) {
+ inputs_[0] = global_object;
+ temps_[0] = scratch;
+ temps_[1] = scratch2;
+ temps_[2] = scratch3;
+ }
+
+ LOperand* global_object() const { return inputs_[0]; }
+ LOperand* scratch() const { return temps_[0]; }
+ LOperand* scratch2() const { return temps_[1]; }
+ LOperand* scratch3() const { return temps_[2]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(Random, "random")
+ DECLARE_HYDROGEN_ACCESSOR(Random)
+};
+
+
class LArithmeticD V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
LArithmeticD(Token::Value op, LOperand* left, LOperand* right)
// ECMA 262 - 15.8.2.7
function MathCos(x) {
- x = MathAbs(x); // Convert to number and get rid of -0.
- return TrigonometricInterpolation(x, 1);
+ return MathCosImpl(x);
}
// ECMA 262 - 15.8.2.8
}
// ECMA 262 - 15.8.2.14
-var rngstate; // Initialized to a Uint32Array during genesis.
function MathRandom() {
- var r0 = (MathImul(18273, rngstate[0] & 0xFFFF) + (rngstate[0] >>> 16)) | 0;
- rngstate[0] = r0;
- var r1 = (MathImul(36969, rngstate[1] & 0xFFFF) + (rngstate[1] >>> 16)) | 0;
- rngstate[1] = r1;
- var x = ((r0 << 16) + (r1 & 0xFFFF)) | 0;
- // Division by 0x100000000 through multiplication by reciprocal.
- return (x < 0 ? (x + 0x100000000) : x) * 2.3283064365386962890625e-10;
+ return %_RandomHeapNumber();
}
// ECMA 262 - 15.8.2.15
// ECMA 262 - 15.8.2.16
function MathSin(x) {
- x = x * 1; // Convert to number and deal with -0.
- if (%_IsMinusZero(x)) return x;
- return TrigonometricInterpolation(x, 0);
+ return MathSinImpl(x);
}
// ECMA 262 - 15.8.2.17
// ECMA 262 - 15.8.2.18
function MathTan(x) {
- return MathSin(x) / MathCos(x);
+ return MathSinImpl(x) / MathCosImpl(x);
}
// Non-standard extension.
}
-var kInversePiHalf = 0.636619772367581343; // 2 / pi
-var kInversePiHalfS26 = 9.48637384723993156e-9; // 2 / pi / (2^26)
-var kS26 = 1 << 26;
-var kTwoStepThreshold = 1 << 27;
-// pi / 2 rounded up
-var kPiHalf = 1.570796326794896780; // 0x192d4454fb21f93f
-// We use two parts for pi/2 to emulate a higher precision.
-// pi_half_1 only has 26 significant bits for mantissa.
-// Note that pi_half > pi_half_1 + pi_half_2
-var kPiHalf1 = 1.570796325802803040; // 0x00000054fb21f93f
-var kPiHalf2 = 9.920935796805404252e-10; // 0x3326a611460b113e
-
-var kSamples; // Initialized to a number during genesis.
-var kIndexConvert; // Initialized to kSamples / (pi/2) during genesis.
-var kSinTable; // Initialized to a Float64Array during genesis.
-var kCosXIntervalTable; // Initialized to a Float64Array during genesis.
-
-// This implements sine using the following algorithm.
-// 1) Multiplication takes care of to-number conversion.
-// 2) Reduce x to the first quadrant [0, pi/2].
-// Conveniently enough, in case of +/-Infinity, we get NaN.
-// Note that we try to use only 26 instead of 52 significant bits for
-// mantissa to avoid rounding errors when multiplying. For very large
-// input we therefore have additional steps.
-// 3) Replace x by (pi/2-x) if x was in the 2nd or 4th quadrant.
-// 4) Do a table lookup for the closest samples to the left and right of x.
-// 5) Find the derivatives at those sampling points by table lookup:
-// dsin(x)/dx = cos(x) = sin(pi/2-x) for x in [0, pi/2].
-// 6) Use cubic spline interpolation to approximate sin(x).
-// 7) Negate the result if x was in the 3rd or 4th quadrant.
-// 8) Get rid of -0 by adding 0.
-function TrigonometricInterpolation(x, phase) {
- if (x < 0 || x > kPiHalf) {
- var multiple;
- while (x < -kTwoStepThreshold || x > kTwoStepThreshold) {
- // Let's assume this loop does not terminate.
- // All numbers x in each loop forms a set S.
- // (1) abs(x) > 2^27 for all x in S.
- // (2) abs(multiple) != 0 since (2^27 * inverse_pi_half_s26) > 1
- // (3) multiple is rounded down in 2^26 steps, so the rounding error is
- // at most max(ulp, 2^26).
- // (4) so for x > 2^27, we subtract at most (1+pi/4)x and at least
- // (1-pi/4)x
- // (5) The subtraction results in x' so that abs(x') <= abs(x)*pi/4.
- // Note that this difference cannot be simply rounded off.
- // Set S cannot exist since (5) violates (1). Loop must terminate.
- multiple = MathFloor(x * kInversePiHalfS26) * kS26;
- x = x - multiple * kPiHalf1 - multiple * kPiHalf2;
+var MathSinImpl = function(x) {
+ InitTrigonometricFunctions();
+ return MathSinImpl(x);
+}
+
+
+var MathCosImpl = function(x) {
+ InitTrigonometricFunctions();
+ return MathCosImpl(x);
+}
+
+
+var InitTrigonometricFunctions;
+
+
+// Define constants and interpolation functions.
+// Also define the initialization function that populates the lookup table
+// and then wires up the function definitions.
+function SetupTrigonometricFunctions() {
+ var samples = 1800; // Table size. Do not change arbitrarily.
+ var inverse_pi_half = 0.636619772367581343; // 2 / pi
+ var inverse_pi_half_s_26 = 9.48637384723993156e-9; // 2 / pi / (2^26)
+ var s_26 = 1 << 26;
+ var two_step_threshold = 1 << 27;
+ var index_convert = 1145.915590261646418; // samples / (pi / 2)
+ // pi / 2 rounded up
+ var pi_half = 1.570796326794896780; // 0x192d4454fb21f93f
+ // We use two parts for pi/2 to emulate a higher precision.
+ // pi_half_1 only has 26 significant bits for mantissa.
+ // Note that pi_half > pi_half_1 + pi_half_2
+ var pi_half_1 = 1.570796325802803040; // 0x00000054fb21f93f
+ var pi_half_2 = 9.920935796805404252e-10; // 0x3326a611460b113e
+ var table_sin;
+ var table_cos_interval;
+
+ // This implements sine using the following algorithm.
+ // 1) Multiplication takes care of to-number conversion.
+ // 2) Reduce x to the first quadrant [0, pi/2].
+ // Conveniently enough, in case of +/-Infinity, we get NaN.
+ // Note that we try to use only 26 instead of 52 significant bits for
+ // mantissa to avoid rounding errors when multiplying. For very large
+ // input we therefore have additional steps.
+ // 3) Replace x by (pi/2-x) if x was in the 2nd or 4th quadrant.
+ // 4) Do a table lookup for the closest samples to the left and right of x.
+ // 5) Find the derivatives at those sampling points by table lookup:
+ // dsin(x)/dx = cos(x) = sin(pi/2-x) for x in [0, pi/2].
+ // 6) Use cubic spline interpolation to approximate sin(x).
+ // 7) Negate the result if x was in the 3rd or 4th quadrant.
+ // 8) Get rid of -0 by adding 0.
+ var Interpolation = function(x, phase) {
+ if (x < 0 || x > pi_half) {
+ var multiple;
+ while (x < -two_step_threshold || x > two_step_threshold) {
+ // Let's assume this loop does not terminate.
+ // All numbers x in each loop forms a set S.
+ // (1) abs(x) > 2^27 for all x in S.
+ // (2) abs(multiple) != 0 since (2^27 * inverse_pi_half_s26) > 1
+ // (3) multiple is rounded down in 2^26 steps, so the rounding error is
+ // at most max(ulp, 2^26).
+ // (4) so for x > 2^27, we subtract at most (1+pi/4)x and at least
+ // (1-pi/4)x
+ // (5) The subtraction results in x' so that abs(x') <= abs(x)*pi/4.
+ // Note that this difference cannot be simply rounded off.
+ // Set S cannot exist since (5) violates (1). Loop must terminate.
+ multiple = MathFloor(x * inverse_pi_half_s_26) * s_26;
+ x = x - multiple * pi_half_1 - multiple * pi_half_2;
+ }
+ multiple = MathFloor(x * inverse_pi_half);
+ x = x - multiple * pi_half_1 - multiple * pi_half_2;
+ phase += multiple;
}
- multiple = MathFloor(x * kInversePiHalf);
- x = x - multiple * kPiHalf1 - multiple * kPiHalf2;
- phase += multiple;
+ var double_index = x * index_convert;
+ if (phase & 1) double_index = samples - double_index;
+ var index = double_index | 0;
+ var t1 = double_index - index;
+ var t2 = 1 - t1;
+ var y1 = table_sin[index];
+ var y2 = table_sin[index + 1];
+ var dy = y2 - y1;
+ return (t2 * y1 + t1 * y2 +
+ t1 * t2 * ((table_cos_interval[index] - dy) * t2 +
+ (dy - table_cos_interval[index + 1]) * t1))
+ * (1 - (phase & 2)) + 0;
+ }
+
+ var MathSinInterpolation = function(x) {
+ x = x * 1; // Convert to number and deal with -0.
+ if (%_IsMinusZero(x)) return x;
+ return Interpolation(x, 0);
+ }
+
+ // Cosine is sine with a phase offset.
+ var MathCosInterpolation = function(x) {
+ x = MathAbs(x); // Convert to number and get rid of -0.
+ return Interpolation(x, 1);
+ };
+
+ %SetInlineBuiltinFlag(Interpolation);
+ %SetInlineBuiltinFlag(MathSinInterpolation);
+ %SetInlineBuiltinFlag(MathCosInterpolation);
+
+ InitTrigonometricFunctions = function() {
+ table_sin = new global.Float64Array(samples + 2);
+ table_cos_interval = new global.Float64Array(samples + 2);
+ %PopulateTrigonometricTable(table_sin, table_cos_interval, samples);
+ MathSinImpl = MathSinInterpolation;
+ MathCosImpl = MathCosInterpolation;
}
- var double_index = x * kIndexConvert;
- if (phase & 1) double_index = kSamples - double_index;
- var index = double_index | 0;
- var t1 = double_index - index;
- var t2 = 1 - t1;
- var y1 = kSinTable[index];
- var y2 = kSinTable[index + 1];
- var dy = y2 - y1;
- return (t2 * y1 + t1 * y2 +
- t1 * t2 * ((kCosXIntervalTable[index] - dy) * t2 +
- (dy - kCosXIntervalTable[index + 1]) * t1))
- * (1 - (phase & 2)) + 0;
}
+SetupTrigonometricFunctions();
+
+
// -------------------------------------------------------------------
function SetUpMath() {
%SetInlineBuiltinFlag(MathSin);
%SetInlineBuiltinFlag(MathCos);
%SetInlineBuiltinFlag(MathTan);
- %SetInlineBuiltinFlag(TrigonometricInterpolation);
}
SetUpMath();
}
+void FullCodeGenerator::EmitRandomHeapNumber(CallRuntime* expr) {
+ ASSERT(expr->arguments()->length() == 0);
+ Label slow_allocate_heapnumber;
+ Label heapnumber_allocated;
+
+ // Save the new heap number in callee-saved register s0, since
+ // we call out to external C code below.
+ __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
+ __ AllocateHeapNumber(s0, a1, a2, t6, &slow_allocate_heapnumber);
+ __ jmp(&heapnumber_allocated);
+
+ __ bind(&slow_allocate_heapnumber);
+
+ // Allocate a heap number.
+ __ CallRuntime(Runtime::kNumberAlloc, 0);
+ __ mov(s0, v0); // Save result in s0, so it is saved thru CFunc call.
+
+ __ bind(&heapnumber_allocated);
+
+ // Convert 32 random bits in v0 to 0.(32 random bits) in a double
+ // by computing:
+ // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
+ __ PrepareCallCFunction(1, a0);
+ __ lw(a0, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
+ __ lw(a0, FieldMemOperand(a0, GlobalObject::kNativeContextOffset));
+ __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
+
+ // 0x41300000 is the top half of 1.0 x 2^20 as a double.
+ __ li(a1, Operand(0x41300000));
+ // Move 0x41300000xxxxxxxx (x = random bits in v0) to FPU.
+ __ Move(f12, v0, a1);
+ // Move 0x4130000000000000 to FPU.
+ __ Move(f14, zero_reg, a1);
+ // Subtract and store the result in the heap number.
+ __ sub_d(f0, f12, f14);
+ __ sdc1(f0, FieldMemOperand(s0, HeapNumber::kValueOffset));
+ __ mov(v0, s0);
+
+ context()->Plug(v0);
+}
+
+
void FullCodeGenerator::EmitSubString(CallRuntime* expr) {
// Load the arguments on the stack and call the stub.
SubStringStub stub;
}
+void LCodeGen::DoRandom(LRandom* instr) {
+ // Assert that the register size is indeed the size of each seed.
+ static const int kSeedSize = sizeof(uint32_t);
+ STATIC_ASSERT(kPointerSize == kSeedSize);
+
+ // Load native context.
+ Register global_object = ToRegister(instr->global_object());
+ Register native_context = global_object;
+ __ lw(native_context, FieldMemOperand(
+ global_object, GlobalObject::kNativeContextOffset));
+
+ // Load state (FixedArray of the native context's random seeds).
+ static const int kRandomSeedOffset =
+ FixedArray::kHeaderSize + Context::RANDOM_SEED_INDEX * kPointerSize;
+ Register state = native_context;
+ __ lw(state, FieldMemOperand(native_context, kRandomSeedOffset));
+
+ // Load state[0].
+ Register state0 = ToRegister(instr->scratch());
+ __ lw(state0, FieldMemOperand(state, ByteArray::kHeaderSize));
+ // Load state[1].
+ Register state1 = ToRegister(instr->scratch2());
+ __ lw(state1, FieldMemOperand(state, ByteArray::kHeaderSize + kSeedSize));
+
+ // state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16)
+ Register scratch3 = ToRegister(instr->scratch3());
+ Register scratch4 = scratch0();
+ __ And(scratch3, state0, Operand(0xFFFF));
+ __ li(scratch4, Operand(18273));
+ __ Mul(scratch3, scratch3, scratch4);
+ __ srl(state0, state0, 16);
+ __ Addu(state0, scratch3, state0);
+ // Save state[0].
+ __ sw(state0, FieldMemOperand(state, ByteArray::kHeaderSize));
+
+ // state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16)
+ __ And(scratch3, state1, Operand(0xFFFF));
+ __ li(scratch4, Operand(36969));
+ __ Mul(scratch3, scratch3, scratch4);
+ __ srl(state1, state1, 16),
+ __ Addu(state1, scratch3, state1);
+ // Save state[1].
+ __ sw(state1, FieldMemOperand(state, ByteArray::kHeaderSize + kSeedSize));
+
+ // Random bit pattern = (state[0] << 14) + (state[1] & 0x3FFFF)
+ Register random = scratch4;
+ __ And(random, state1, Operand(0x3FFFF));
+ __ sll(state0, state0, 14);
+ __ Addu(random, random, state0);
+
+ // 0x41300000 is the top half of 1.0 x 2^20 as a double.
+ __ li(scratch3, Operand(0x41300000));
+ // Move 0x41300000xxxxxxxx (x = random bits in v0) to FPU.
+ DoubleRegister result = ToDoubleRegister(instr->result());
+ __ Move(result, random, scratch3);
+ // Move 0x4130000000000000 to FPU.
+ DoubleRegister scratch5 = double_scratch0();
+ __ Move(scratch5, zero_reg, scratch3);
+ __ sub_d(result, result, scratch5);
+}
+
+
void LCodeGen::DoMathExp(LMathExp* instr) {
DoubleRegister input = ToDoubleRegister(instr->value());
DoubleRegister result = ToDoubleRegister(instr->result());
}
+LInstruction* LChunkBuilder::DoRandom(HRandom* instr) {
+ ASSERT(instr->representation().IsDouble());
+ ASSERT(instr->global_object()->representation().IsTagged());
+ LOperand* global_object = UseTempRegister(instr->global_object());
+ LOperand* scratch = TempRegister();
+ LOperand* scratch2 = TempRegister();
+ LOperand* scratch3 = TempRegister();
+ LRandom* result = new(zone()) LRandom(
+ global_object, scratch, scratch2, scratch3);
+ return DefineFixedDouble(result, f0);
+}
+
+
LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
ASSERT(instr->left()->representation().IsTagged());
ASSERT(instr->right()->representation().IsTagged());
V(Parameter) \
V(Power) \
V(PushArgument) \
+ V(Random) \
V(RegExpLiteral) \
V(Return) \
V(SeqStringGetChar) \
};
+class LRandom V8_FINAL : public LTemplateInstruction<1, 1, 3> {
+ public:
+ LRandom(LOperand* global_object,
+ LOperand* scratch,
+ LOperand* scratch2,
+ LOperand* scratch3) {
+ inputs_[0] = global_object;
+ temps_[0] = scratch;
+ temps_[1] = scratch2;
+ temps_[2] = scratch3;
+ }
+
+ LOperand* global_object() const { return inputs_[0]; }
+ LOperand* scratch() const { return temps_[0]; }
+ LOperand* scratch2() const { return temps_[1]; }
+ LOperand* scratch3() const { return temps_[2]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(Random, "random")
+ DECLARE_HYDROGEN_ACCESSOR(Random)
+};
+
+
class LArithmeticD V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
LArithmeticD(Token::Value op, LOperand* left, LOperand* right)
V(Math, exp, MathExp) \
V(Math, sqrt, MathSqrt) \
V(Math, pow, MathPow) \
+ V(Math, random, MathRandom) \
V(Math, max, MathMax) \
V(Math, min, MathMin) \
V(Math, imul, MathImul)
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_PopulateTrigonometricTable) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 3);
+ CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sin_table, 0);
+ CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, cos_table, 1);
+ CONVERT_SMI_ARG_CHECKED(samples, 2);
+ RUNTIME_ASSERT(sin_table->type() == kExternalDoubleArray);
+ RUNTIME_ASSERT(cos_table->type() == kExternalDoubleArray);
+ double* sin_buffer = reinterpret_cast<double*>(
+ JSArrayBuffer::cast(sin_table->buffer())->backing_store());
+ double* cos_buffer = reinterpret_cast<double*>(
+ JSArrayBuffer::cast(cos_table->buffer())->backing_store());
+
+ static const double pi_half = 3.1415926535897932 / 2;
+ double interval = pi_half / samples;
+ for (int i = 0; i < samples + 1; i++) {
+ double sample = sin(i * interval);
+ sin_buffer[i] = sample;
+ cos_buffer[samples - i] = sample * interval;
+ }
+
+ // Fill this to catch out of bound accesses when calculating Math.sin(pi/2).
+ sin_buffer[samples + 1] = sin(pi_half + interval);
+ cos_buffer[samples + 1] = cos(pi_half + interval) * interval;
+
+ return isolate->heap()->undefined_value();
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
SealHandleScope shs(isolate);
ASSERT(args.length() == 2);
F(Math_sin, 1, 1) \
F(Math_sqrt, 1, 1) \
F(Math_tan, 1, 1) \
+ F(PopulateTrigonometricTable, 3, 1) \
\
/* Regular expressions */ \
F(RegExpCompile, 3, 1) \
F(OneByteSeqStringSetChar, 3, 1) \
F(TwoByteSeqStringSetChar, 3, 1) \
F(ObjectEquals, 2, 1) \
+ F(RandomHeapNumber, 0, 1) \
F(IsObject, 1, 1) \
F(IsFunction, 1, 1) \
F(IsUndetectableObject, 1, 1) \
RUNTIME_ENTRY,
1,
"Runtime::PerformGC");
+ Add(ExternalReference::random_uint32_function(isolate).address(),
+ RUNTIME_ENTRY,
+ 3,
+ "V8::Random");
Add(ExternalReference::delete_handle_scope_extensions(isolate).address(),
RUNTIME_ENTRY,
4,
+++ /dev/null
-// Copyright 2013 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef V8_TRIG_TABLE_H_
-#define V8_TRIG_TABLE_H_
-
-
-namespace v8 {
-namespace internal {
-
-class TrigonometricLookupTable : public AllStatic {
- public:
- // Casting away const-ness to use as argument for typed array constructor.
- static void* sin_table() {
- return const_cast<double*>(&kSinTable[0]);
- }
-
- static void* cos_x_interval_table() {
- return const_cast<double*>(&kCosXIntervalTable[0]);
- }
-
- static double samples_over_pi_half() { return kSamplesOverPiHalf; }
- static int samples() { return kSamples; }
- static int table_num_bytes() { return kTableSize * sizeof(*kSinTable); }
- static int table_size() { return kTableSize; }
-
- private:
- static const double kSinTable[];
- static const double kCosXIntervalTable[];
- static const int kSamples;
- static const int kTableSize;
- static const double kSamplesOverPiHalf;
-};
-
-} } // namespace v8::internal
-
-#endif // V8_TRIG_TABLE_H_
}
+// Used by JavaScript APIs
+uint32_t V8::Random(Context* context) {
+ ASSERT(context->IsNativeContext());
+ ByteArray* seed = context->random_seed();
+ uint32_t* state = reinterpret_cast<uint32_t*>(seed->GetDataStartAddress());
+
+ // When we get here, the RNG must have been initialized,
+ // see the Genesis constructor in file bootstrapper.cc.
+ ASSERT_NE(0, state[0]);
+ ASSERT_NE(0, state[1]);
+
+ // Mix the bits. Never replaces state[i] with 0 if it is nonzero.
+ state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16);
+ state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16);
+
+ return (state[0] << 14) + (state[1] & 0x3FFFF);
+}
+
+
void V8::AddCallCompletedCallback(CallCompletedCallback callback) {
if (call_completed_callbacks_ == NULL) { // Lazy init.
call_completed_callbacks_ = new List<CallCompletedCallback>();
ReturnAddressLocationResolver resolver);
// Support for entry hooking JITed code.
static void SetFunctionEntryHook(FunctionEntryHook entry_hook);
+ // Random number generation support. Not cryptographically safe.
+ static uint32_t Random(Context* context);
static void AddCallCompletedCallback(CallCompletedCallback callback);
static void RemoveCallCompletedCallback(CallCompletedCallback callback);
}
+void FullCodeGenerator::EmitRandomHeapNumber(CallRuntime* expr) {
+ ASSERT(expr->arguments()->length() == 0);
+
+ Label slow_allocate_heapnumber;
+ Label heapnumber_allocated;
+
+ __ AllocateHeapNumber(rbx, rcx, &slow_allocate_heapnumber);
+ __ jmp(&heapnumber_allocated);
+
+ __ bind(&slow_allocate_heapnumber);
+ // Allocate a heap number.
+ __ CallRuntime(Runtime::kNumberAlloc, 0);
+ __ movq(rbx, rax);
+
+ __ bind(&heapnumber_allocated);
+
+ // Return a random uint32 number in rax.
+ // The fresh HeapNumber is in rbx, which is callee-save on both x64 ABIs.
+ __ PrepareCallCFunction(1);
+ __ movq(arg_reg_1,
+ ContextOperand(context_register(), Context::GLOBAL_OBJECT_INDEX));
+ __ movq(arg_reg_1,
+ FieldOperand(arg_reg_1, GlobalObject::kNativeContextOffset));
+ __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
+
+ // 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)).
+ __ movl(rcx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
+ __ movd(xmm1, rcx);
+ __ movd(xmm0, rax);
+ __ cvtss2sd(xmm1, xmm1);
+ __ xorps(xmm0, xmm1);
+ __ subsd(xmm0, xmm1);
+ __ movsd(FieldOperand(rbx, HeapNumber::kValueOffset), xmm0);
+
+ __ movq(rax, rbx);
+ context()->Plug(rax);
+}
+
+
void FullCodeGenerator::EmitSubString(CallRuntime* expr) {
// Load the arguments on the stack and call the stub.
SubStringStub stub;
}
+void LCodeGen::DoRandom(LRandom* instr) {
+ // Assert that register size is twice the size of each seed.
+ static const int kSeedSize = sizeof(uint32_t);
+ STATIC_ASSERT(kPointerSize == 2 * kSeedSize);
+
+ // Load native context
+ Register global_object = ToRegister(instr->global_object());
+ Register native_context = global_object;
+ __ movq(native_context, FieldOperand(
+ global_object, GlobalObject::kNativeContextOffset));
+
+ // Load state (FixedArray of the native context's random seeds)
+ static const int kRandomSeedOffset =
+ FixedArray::kHeaderSize + Context::RANDOM_SEED_INDEX * kPointerSize;
+ Register state = native_context;
+ __ movq(state, FieldOperand(native_context, kRandomSeedOffset));
+
+ // Load state[0].
+ Register state0 = ToRegister(instr->scratch());
+ __ movl(state0, FieldOperand(state, ByteArray::kHeaderSize));
+ // Load state[1].
+ Register state1 = ToRegister(instr->scratch2());
+ __ movl(state1, FieldOperand(state, ByteArray::kHeaderSize + kSeedSize));
+
+ // state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16)
+ Register scratch3 = ToRegister(instr->scratch3());
+ __ movzxwl(scratch3, state0);
+ __ imull(scratch3, scratch3, Immediate(18273));
+ __ shrl(state0, Immediate(16));
+ __ addl(state0, scratch3);
+ // Save state[0].
+ __ movl(FieldOperand(state, ByteArray::kHeaderSize), state0);
+
+ // state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16)
+ __ movzxwl(scratch3, state1);
+ __ imull(scratch3, scratch3, Immediate(36969));
+ __ shrl(state1, Immediate(16));
+ __ addl(state1, scratch3);
+ // Save state[1].
+ __ movl(FieldOperand(state, ByteArray::kHeaderSize + kSeedSize), state1);
+
+ // Random bit pattern = (state[0] << 14) + (state[1] & 0x3FFFF)
+ Register random = state0;
+ __ shll(random, Immediate(14));
+ __ andl(state1, Immediate(0x3FFFF));
+ __ addl(random, state1);
+
+ // 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)).
+ XMMRegister result = ToDoubleRegister(instr->result());
+ XMMRegister scratch4 = double_scratch0();
+ __ movq(scratch3, V8_INT64_C(0x4130000000000000)); // 1.0 x 2^20 as double
+ __ movq(scratch4, scratch3);
+ __ movd(result, random);
+ __ xorps(result, scratch4);
+ __ subsd(result, scratch4);
+}
+
+
void LCodeGen::DoMathExp(LMathExp* instr) {
XMMRegister input = ToDoubleRegister(instr->value());
XMMRegister result = ToDoubleRegister(instr->result());
}
+LInstruction* LChunkBuilder::DoRandom(HRandom* instr) {
+ ASSERT(instr->representation().IsDouble());
+ ASSERT(instr->global_object()->representation().IsTagged());
+ LOperand* global_object = UseTempRegister(instr->global_object());
+ LOperand* scratch = TempRegister();
+ LOperand* scratch2 = TempRegister();
+ LOperand* scratch3 = TempRegister();
+ LRandom* result = new(zone()) LRandom(
+ global_object, scratch, scratch2, scratch3);
+ return DefineFixedDouble(result, xmm1);
+}
+
+
LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
ASSERT(instr->left()->representation().IsTagged());
ASSERT(instr->right()->representation().IsTagged());
V(Parameter) \
V(Power) \
V(PushArgument) \
+ V(Random) \
V(RegExpLiteral) \
V(Return) \
V(SeqStringGetChar) \
};
+class LRandom V8_FINAL : public LTemplateInstruction<1, 1, 3> {
+ public:
+ LRandom(LOperand* global_object,
+ LOperand* scratch,
+ LOperand* scratch2,
+ LOperand* scratch3) {
+ inputs_[0] = global_object;
+ temps_[0] = scratch;
+ temps_[1] = scratch2;
+ temps_[2] = scratch3;
+ }
+
+ LOperand* global_object() { return inputs_[0]; }
+ LOperand* scratch() const { return temps_[0]; }
+ LOperand* scratch2() const { return temps_[1]; }
+ LOperand* scratch3() const { return temps_[2]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(Random, "random")
+ DECLARE_HYDROGEN_ACCESSOR(Random)
+};
+
+
class LArithmeticD V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
LArithmeticD(Token::Value op, LOperand* left, LOperand* right)
LocalContext context;
Isolate* isolate = GetIsolateFrom(&context);
- int start = CountArrayBuffersInWeakList(isolate->heap());
+ CHECK_EQ(0, CountArrayBuffersInWeakList(isolate->heap()));
{
v8::HandleScope s1(context->GetIsolate());
v8::Handle<v8::ArrayBuffer> ab1 = v8::ArrayBuffer::New(256);
Handle<JSArrayBuffer> iab1 = v8::Utils::OpenHandle(*ab1);
Handle<JSArrayBuffer> iab2 = v8::Utils::OpenHandle(*ab2);
- CHECK_EQ(2, CountArrayBuffersInWeakList(isolate->heap()) - start);
+ CHECK_EQ(2, CountArrayBuffersInWeakList(isolate->heap()));
CHECK(HasArrayBufferInWeakList(isolate->heap(), *iab1));
CHECK(HasArrayBufferInWeakList(isolate->heap(), *iab2));
}
isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
- CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()) - start);
+ CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()));
{
HandleScope scope2(isolate);
Handle<JSArrayBuffer> iab1 = v8::Utils::OpenHandle(*ab1);
}
isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
- CHECK_EQ(0, CountArrayBuffersInWeakList(isolate->heap()) - start);
+ CHECK_EQ(0, CountArrayBuffersInWeakList(isolate->heap()));
}
v8::V8::Initialize();
LocalContext context;
Isolate* isolate = GetIsolateFrom(&context);
- int start = CountArrayBuffersInWeakList(isolate->heap());
for (int i = 1; i <= 3; i++) {
// Create 3 array buffers, make i-th of them garbage,
// validate correct state of array buffer weak list.
- CHECK_EQ(0, CountArrayBuffersInWeakList(isolate->heap()) - start);
+ CHECK_EQ(0, CountArrayBuffersInWeakList(isolate->heap()));
{
v8::HandleScope scope(context->GetIsolate());
v8::Handle<v8::ArrayBuffer> ab3 =
v8::Handle<v8::ArrayBuffer>::Cast(CompileRun("ab3"));
- CHECK_EQ(3, CountArrayBuffersInWeakList(isolate->heap()) - start);
+ CHECK_EQ(3, CountArrayBuffersInWeakList(isolate->heap()));
CHECK(HasArrayBufferInWeakList(isolate->heap(),
*v8::Utils::OpenHandle(*ab1)));
CHECK(HasArrayBufferInWeakList(isolate->heap(),
CompileRun(source.start());
isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
- CHECK_EQ(2, CountArrayBuffersInWeakList(isolate->heap()) - start);
+ CHECK_EQ(2, CountArrayBuffersInWeakList(isolate->heap()));
{
v8::HandleScope s2(context->GetIsolate());
}
isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
- CHECK_EQ(0, CountArrayBuffersInWeakList(isolate->heap()) - start);
+ CHECK_EQ(0, CountArrayBuffersInWeakList(isolate->heap()));
}
}
LocalContext context;
Isolate* isolate = GetIsolateFrom(&context);
v8::HandleScope scope(context->GetIsolate());
- int start = CountArrayBuffersInWeakList(isolate->heap());
CompileRun("var ab = new ArrayBuffer(2048);");
for (int i = 1; i <= 3; i++) {
// Create 3 typed arrays, make i-th of them garbage,
v8::HandleScope s0(context->GetIsolate());
i::ScopedVector<char> source(2048);
- CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()) - start);
+ CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()));
{
v8::HandleScope s1(context->GetIsolate());
v8::Handle<TypedArray>::Cast(CompileRun("ta2"));
v8::Handle<TypedArray> ta3 =
v8::Handle<TypedArray>::Cast(CompileRun("ta3"));
- CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()) - start);
+ CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()));
Handle<JSArrayBuffer> iab = v8::Utils::OpenHandle(*ab);
CHECK_EQ(3, CountViews(*iab));
CHECK(HasViewInWeakList(*iab, *v8::Utils::OpenHandle(*ta1)));
CompileRun(source.start());
isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
- CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()) - start);
+ CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()));
{
v8::HandleScope s2(context->GetIsolate());
CompileRun("ta1 = null; ta2 = null; ta3 = null;");
isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
- CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()) - start);
+ CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()));
{
v8::HandleScope s3(context->GetIsolate());
+++ /dev/null
-#!/usr/bin/env python
-#
-# Copyright 2013 the V8 project authors. All rights reserved.
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following
-# disclaimer in the documentation and/or other materials provided
-# with the distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived
-# from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-# This is a utility for populating the lookup table for the
-# approximation of trigonometric functions.
-
-import sys, math
-
-SAMPLES = 1800
-
-TEMPLATE = """\
-// Copyright 2013 Google Inc. All Rights Reserved.
-
-// This file was generated from a python script.
-
-#include "v8.h"
-#include "trig-table.h"
-
-namespace v8 {
-namespace internal {
-
- const double TrigonometricLookupTable::kSinTable[] =
- { %(sine_table)s };
- const double TrigonometricLookupTable::kCosXIntervalTable[] =
- { %(cosine_table)s };
- const int TrigonometricLookupTable::kSamples = %(samples)i;
- const int TrigonometricLookupTable::kTableSize = %(table_size)i;
- const double TrigonometricLookupTable::kSamplesOverPiHalf =
- %(samples_over_pi_half)s;
-
-} } // v8::internal
-"""
-
-def main():
- pi_half = math.pi / 2
- interval = pi_half / SAMPLES
- sin = []
- cos_times_interval = []
- table_size = SAMPLES + 2
-
- for i in range(0, table_size):
- sample = i * interval
- sin.append(repr(math.sin(sample)))
- cos_times_interval.append(repr(math.cos(sample) * interval))
-
- output_file = sys.argv[1]
- output = open(str(output_file), "w")
- output.write(TEMPLATE % {
- 'sine_table': ','.join(sin),
- 'cosine_table': ','.join(cos_times_interval),
- 'samples': SAMPLES,
- 'table_size': table_size,
- 'samples_over_pi_half': repr(SAMPLES / pi_half)
- })
-
-if __name__ == "__main__":
- main()
-
'sources': [
'<(SHARED_INTERMEDIATE_DIR)/libraries.cc',
'<(SHARED_INTERMEDIATE_DIR)/experimental-libraries.cc',
- '<(SHARED_INTERMEDIATE_DIR)/trig-table.cc',
'<(INTERMEDIATE_DIR)/snapshot.cc',
],
'actions': [
'sources': [
'<(SHARED_INTERMEDIATE_DIR)/libraries.cc',
'<(SHARED_INTERMEDIATE_DIR)/experimental-libraries.cc',
- '<(SHARED_INTERMEDIATE_DIR)/trig-table.cc',
'../../src/snapshot-empty.cc',
],
'conditions': [
}],
]
},
- { 'target_name': 'generate_trig_table',
- 'type': 'none',
- 'conditions': [
- ['want_separate_host_toolset==1', {
- 'toolsets': ['host', 'target'],
- }, {
- 'toolsets': ['target'],
- }],
- ],
- 'actions': [
- {
- 'action_name': 'generate',
- 'inputs': [
- '../../tools/generate-trig-table.py',
- ],
- 'outputs': [
- '<(SHARED_INTERMEDIATE_DIR)/trig-table.cc',
- ],
- 'action': [
- 'python',
- '../../tools/generate-trig-table.py',
- '<@(_outputs)',
- ],
- },
- ]
- },
{
'target_name': 'v8_base.<(v8_target_arch)',
'type': 'static_library',
- 'dependencies': [
- 'generate_trig_table',
- ],
'variables': {
'optimize': 'max',
},