From 9ccf0e527f066ca69e610beb04d9507ee5bf187c Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Mon, 11 Apr 2011 15:33:24 -0700 Subject: [PATCH 01/19] Don't error on ENOTCONN from shutdown() --- lib/http.js | 2 +- lib/net.js | 7 ++++++- test/disabled/GH-670.js | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 test/disabled/GH-670.js diff --git a/lib/http.js b/lib/http.js index 3537b70b79f..d10f58d9ed6 100644 --- a/lib/http.js +++ b/lib/http.js @@ -1185,7 +1185,7 @@ Agent.prototype._establishNewConnection = function() { parser.incoming = null; socket.on('error', function(err) { - debug('AGENT SOCKET ERROR: ' + err.message); + debug('AGENT SOCKET ERROR: ' + err.message + '\n' + err.stack); var req; if (socket._httpMessage) { req = socket._httpMessage; diff --git a/lib/net.js b/lib/net.js index 1be0e49db96..e96e3c6900a 100644 --- a/lib/net.js +++ b/lib/net.js @@ -844,7 +844,12 @@ Socket.prototype._shutdown = function() { try { this._shutdownImpl(); } catch (e) { - this.destroy(e); + if (e.code == 'ENOTCONN') { + // Allowed. + this.destroy(); + } else { + this.destroy(e); + } } } else { // writable but not readable diff --git a/test/disabled/GH-670.js b/test/disabled/GH-670.js new file mode 100644 index 00000000000..0888cb950f5 --- /dev/null +++ b/test/disabled/GH-670.js @@ -0,0 +1,39 @@ +var assert = require('assert'); +var https = require('https'); +var tls = require('tls'); + +var options = { + host: 'github.com', + path: '/kriskowal/tigerblood/', + port: 443 +}; + +var req = https.get(options, function(response) { + var recved = 0; + + response.on('data', function(chunk) { + recved += chunk.length; + console.log('Response data.'); + }); + + response.on('end', function() { + console.log('Response end.'); + // Does not work + loadDom(); + }); + +}); + +req.on('error', function(e) { + console.log('Error on get.'); +}); + +function loadDom() { + // Do a lot of computation to stall the process. + // In the meantime the socket will be disconnected. + for (var i = 0; i < 1e8; i++) { + ; + } + + console.log('Dom loaded.'); +} From 0b1920b202098f80d1425eee186a9e4f4dab8c82 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Mon, 11 Apr 2011 16:07:54 -0700 Subject: [PATCH 02/19] Upgrade v8 to 3.1.8.10 --- deps/v8/src/accessors.cc | 10 +- deps/v8/src/arm/lithium-codegen-arm.cc | 141 +++++++------ deps/v8/src/arm/lithium-codegen-arm.h | 65 +++++- deps/v8/src/deoptimizer.cc | 86 ++------ deps/v8/src/deoptimizer.h | 50 +---- deps/v8/src/frames-inl.h | 19 +- deps/v8/src/frames.cc | 63 +----- deps/v8/src/frames.h | 19 +- deps/v8/src/ia32/lithium-codegen-ia32.cc | 197 ++++++++++-------- deps/v8/src/ia32/lithium-codegen-ia32.h | 70 ++++++- deps/v8/src/ia32/macro-assembler-ia32.h | 4 + deps/v8/src/runtime.cc | 25 ++- deps/v8/src/scopes.cc | 37 +++- deps/v8/src/scopes.h | 28 +-- deps/v8/src/version.cc | 2 +- deps/v8/src/x64/lithium-codegen-x64.cc | 106 ++++++---- deps/v8/src/x64/lithium-codegen-x64.h | 47 ++++- deps/v8/src/x64/macro-assembler-x64.h | 4 + deps/v8/test/mjsunit/regress/regress-78270.js | 37 ++++ 19 files changed, 588 insertions(+), 422 deletions(-) create mode 100644 deps/v8/test/mjsunit/regress/regress-78270.js diff --git a/deps/v8/src/accessors.cc b/deps/v8/src/accessors.cc index 18264254b83..8cbdc09edf8 100644 --- a/deps/v8/src/accessors.cc +++ b/deps/v8/src/accessors.cc @@ -566,8 +566,8 @@ static Address SlotAddress(JavaScriptFrame* frame, int slot_index) { const int offset = JavaScriptFrameConstants::kLocal0Offset; return frame->fp() + offset - (slot_index * kPointerSize); } else { - const int offset = JavaScriptFrameConstants::kReceiverOffset; - return frame->caller_sp() + offset + (slot_index * kPointerSize); + const int offset = JavaScriptFrameConstants::kSavedRegistersOffset; + return frame->fp() + offset - ((slot_index + 1) * kPointerSize); } } @@ -791,14 +791,16 @@ MaybeObject* Accessors::FunctionGetArguments(Object* object, void*) { // Get the number of arguments and construct an arguments object // mirror for the right frame. - const int length = frame->GetProvidedParametersCount(); + const int length = frame->ComputeParametersCount(); Handle arguments = Factory::NewArgumentsObject(function, length); Handle array = Factory::NewFixedArray(length); // Copy the parameters to the arguments object. ASSERT(array->length() == length); - for (int i = 0; i < length; i++) array->set(i, frame->GetParameter(i)); + for (int i = 0; i < length; i++) { + array->set(i, frame->GetParameter(i)); + } arguments->set_elements(*array); // Return the freshly allocated arguments object. diff --git a/deps/v8/src/arm/lithium-codegen-arm.cc b/deps/v8/src/arm/lithium-codegen-arm.cc index c0f5800bf49..1ec2b9842f4 100644 --- a/deps/v8/src/arm/lithium-codegen-arm.cc +++ b/deps/v8/src/arm/lithium-codegen-arm.cc @@ -465,11 +465,19 @@ void LCodeGen::AddToTranslation(Translation* translation, void LCodeGen::CallCode(Handle code, RelocInfo::Mode mode, LInstruction* instr) { + CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT); +} + + +void LCodeGen::CallCodeGeneric(Handle code, + RelocInfo::Mode mode, + LInstruction* instr, + SafepointMode safepoint_mode) { ASSERT(instr != NULL); LPointerMap* pointers = instr->pointer_map(); RecordPosition(pointers->position()); __ Call(code, mode); - RegisterLazyDeoptimization(instr); + RegisterLazyDeoptimization(instr, safepoint_mode); } @@ -482,11 +490,21 @@ void LCodeGen::CallRuntime(Runtime::Function* function, RecordPosition(pointers->position()); __ CallRuntime(function, num_arguments); - RegisterLazyDeoptimization(instr); + RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT); } -void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr) { +void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id, + int argc, + LInstruction* instr) { + __ CallRuntimeSaveDoubles(id); + RecordSafepointWithRegisters( + instr->pointer_map(), argc, Safepoint::kNoDeoptimizationIndex); +} + + +void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr, + SafepointMode safepoint_mode) { // Create the environment to bailout to. If the call has side effects // execution has to continue after the call otherwise execution can continue // from a previous bailout point repeating the call. @@ -498,8 +516,16 @@ void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr) { } RegisterEnvironmentForDeoptimization(deoptimization_environment); - RecordSafepoint(instr->pointer_map(), - deoptimization_environment->deoptimization_index()); + if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) { + RecordSafepoint(instr->pointer_map(), + deoptimization_environment->deoptimization_index()); + } else { + ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); + RecordSafepointWithRegisters( + instr->pointer_map(), + 0, + deoptimization_environment->deoptimization_index()); + } } @@ -631,6 +657,8 @@ void LCodeGen::RecordSafepoint( Safepoint::Kind kind, int arguments, int deoptimization_index) { + ASSERT(expected_safepoint_kind_ == kind); + const ZoneList* operands = pointers->operands(); Safepoint safepoint = safepoints_.DefineSafepoint(masm(), kind, arguments, deoptimization_index); @@ -951,7 +979,7 @@ void LCodeGen::DoDeferredBinaryOpStub(LTemplateInstruction<1, 2, T>* instr, Register left = ToRegister(instr->InputAt(0)); Register right = ToRegister(instr->InputAt(1)); - __ PushSafepointRegistersAndDoubles(); + PushSafepointRegistersScope scope(this, Safepoint::kWithRegistersAndDoubles); // Move left to r1 and right to r0 for the stub call. if (left.is(r1)) { __ Move(r0, right); @@ -973,7 +1001,6 @@ void LCodeGen::DoDeferredBinaryOpStub(LTemplateInstruction<1, 2, T>* instr, Safepoint::kNoDeoptimizationIndex); // Overwrite the stored value of r0 with the result of the stub. __ StoreToSafepointRegistersAndDoublesSlot(r0, r0); - __ PopSafepointRegistersAndDoubles(); } @@ -1369,11 +1396,8 @@ void LCodeGen::EmitGoto(int block, LDeferredCode* deferred_stack_check) { void LCodeGen::DoDeferredStackCheck(LGoto* instr) { - __ PushSafepointRegisters(); - __ CallRuntimeSaveDoubles(Runtime::kStackGuard); - RecordSafepointWithRegisters( - instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); - __ PopSafepointRegisters(); + PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); + CallRuntimeFromDeferred(Runtime::kStackGuard, 0, instr); } @@ -1972,7 +1996,7 @@ void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, flags | InstanceofStub::kReturnTrueFalseObject); InstanceofStub stub(flags); - __ PushSafepointRegisters(); + PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); // Get the temp register reserved by the instruction. This needs to be r4 as // its slot of the pushing of safepoint registers is used to communicate the @@ -1987,12 +2011,13 @@ void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, __ BlockConstPoolFor(kAdditionalDelta); __ mov(temp, Operand(delta * kPointerSize)); __ StoreToSafepointRegisterSlot(temp, temp); - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); + CallCodeGeneric(stub.GetCode(), + RelocInfo::CODE_TARGET, + instr, + RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); // Put the result value into the result register slot and // restore all registers. __ StoreToSafepointRegisterSlot(result, result); - - __ PopSafepointRegisters(); } @@ -2456,7 +2481,7 @@ void LCodeGen::CallKnownFunction(Handle function, __ Call(ip); // Setup deoptimization. - RegisterLazyDeoptimization(instr); + RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT); // Restore context. __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); @@ -2494,44 +2519,43 @@ void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) { // Input is negative. Reverse its sign. // Preserve the value of all registers. - __ PushSafepointRegisters(); + { + PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); - // Registers were saved at the safepoint, so we can use - // many scratch registers. - Register tmp1 = input.is(r1) ? r0 : r1; - Register tmp2 = input.is(r2) ? r0 : r2; - Register tmp3 = input.is(r3) ? r0 : r3; - Register tmp4 = input.is(r4) ? r0 : r4; + // Registers were saved at the safepoint, so we can use + // many scratch registers. + Register tmp1 = input.is(r1) ? r0 : r1; + Register tmp2 = input.is(r2) ? r0 : r2; + Register tmp3 = input.is(r3) ? r0 : r3; + Register tmp4 = input.is(r4) ? r0 : r4; - // exponent: floating point exponent value. + // exponent: floating point exponent value. - Label allocated, slow; - __ LoadRoot(tmp4, Heap::kHeapNumberMapRootIndex); - __ AllocateHeapNumber(tmp1, tmp2, tmp3, tmp4, &slow); - __ b(&allocated); + Label allocated, slow; + __ LoadRoot(tmp4, Heap::kHeapNumberMapRootIndex); + __ AllocateHeapNumber(tmp1, tmp2, tmp3, tmp4, &slow); + __ b(&allocated); - // Slow case: Call the runtime system to do the number allocation. - __ bind(&slow); + // Slow case: Call the runtime system to do the number allocation. + __ bind(&slow); - __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); - RecordSafepointWithRegisters( - instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); - // Set the pointer to the new heap number in tmp. - if (!tmp1.is(r0)) __ mov(tmp1, Operand(r0)); - // Restore input_reg after call to runtime. - __ LoadFromSafepointRegisterSlot(input, input); - __ ldr(exponent, FieldMemOperand(input, HeapNumber::kExponentOffset)); + CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr); + // Set the pointer to the new heap number in tmp. + if (!tmp1.is(r0)) __ mov(tmp1, Operand(r0)); + // Restore input_reg after call to runtime. + __ LoadFromSafepointRegisterSlot(input, input); + __ ldr(exponent, FieldMemOperand(input, HeapNumber::kExponentOffset)); - __ bind(&allocated); - // exponent: floating point exponent value. - // tmp1: allocated heap number. - __ bic(exponent, exponent, Operand(HeapNumber::kSignMask)); - __ str(exponent, FieldMemOperand(tmp1, HeapNumber::kExponentOffset)); - __ ldr(tmp2, FieldMemOperand(input, HeapNumber::kMantissaOffset)); - __ str(tmp2, FieldMemOperand(tmp1, HeapNumber::kMantissaOffset)); + __ bind(&allocated); + // exponent: floating point exponent value. + // tmp1: allocated heap number. + __ bic(exponent, exponent, Operand(HeapNumber::kSignMask)); + __ str(exponent, FieldMemOperand(tmp1, HeapNumber::kExponentOffset)); + __ ldr(tmp2, FieldMemOperand(input, HeapNumber::kMantissaOffset)); + __ str(tmp2, FieldMemOperand(tmp1, HeapNumber::kMantissaOffset)); - __ StoreToSafepointRegisterSlot(tmp1, input); - __ PopSafepointRegisters(); + __ StoreToSafepointRegisterSlot(tmp1, input); + } __ bind(&done); } @@ -2993,7 +3017,7 @@ void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) { // contained in the register pointer map. __ mov(result, Operand(0)); - __ PushSafepointRegisters(); + PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); __ push(string); // Push the index as a smi. This is safe because of the checks in // DoStringCharCodeAt above. @@ -3006,15 +3030,12 @@ void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) { __ SmiTag(index); __ push(index); } - __ CallRuntimeSaveDoubles(Runtime::kStringCharCodeAt); - RecordSafepointWithRegisters( - instr->pointer_map(), 2, Safepoint::kNoDeoptimizationIndex); + CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2, instr); if (FLAG_debug_code) { __ AbortIfNotSmi(r0); } __ SmiUntag(r0); __ StoreToSafepointRegisterSlot(r0, result); - __ PopSafepointRegisters(); } @@ -3070,7 +3091,7 @@ void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) { SwVfpRegister flt_scratch = s0; // Preserve the value of all registers. - __ PushSafepointRegisters(); + PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); // There was overflow, so bits 30 and 31 of the original integer // disagree. Try to allocate a heap number in new space and store @@ -3095,9 +3116,7 @@ void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) { // integer value. __ mov(ip, Operand(0)); __ StoreToSafepointRegisterSlot(ip, reg); - __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); - RecordSafepointWithRegisters( - instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); + CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr); if (!reg.is(r0)) __ mov(reg, r0); // Done. Put the value in dbl_scratch into the value of the allocated heap @@ -3106,7 +3125,6 @@ void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) { __ sub(ip, reg, Operand(kHeapObjectTag)); __ vstr(dbl_scratch, ip, HeapNumber::kValueOffset); __ StoreToSafepointRegisterSlot(reg, reg); - __ PopSafepointRegisters(); } @@ -3146,12 +3164,9 @@ void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) { Register reg = ToRegister(instr->result()); __ mov(reg, Operand(0)); - __ PushSafepointRegisters(); - __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); - RecordSafepointWithRegisters( - instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); + PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); + CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr); __ StoreToSafepointRegisterSlot(r0, reg); - __ PopSafepointRegisters(); } diff --git a/deps/v8/src/arm/lithium-codegen-arm.h b/deps/v8/src/arm/lithium-codegen-arm.h index a26f6311e26..393b6423e3d 100644 --- a/deps/v8/src/arm/lithium-codegen-arm.h +++ b/deps/v8/src/arm/lithium-codegen-arm.h @@ -57,7 +57,8 @@ class LCodeGen BASE_EMBEDDED { status_(UNUSED), deferred_(8), osr_pc_offset_(-1), - resolver_(this) { + resolver_(this), + expected_safepoint_kind_(Safepoint::kSimple) { PopulateDeoptimizationLiteralsWithInlinedFunctions(); } @@ -167,12 +168,24 @@ class LCodeGen BASE_EMBEDDED { bool GenerateDeferredCode(); bool GenerateSafepointTable(); + enum SafepointMode { + RECORD_SIMPLE_SAFEPOINT, + RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS + }; + void CallCode(Handle code, RelocInfo::Mode mode, LInstruction* instr); + + void CallCodeGeneric(Handle code, + RelocInfo::Mode mode, + LInstruction* instr, + SafepointMode safepoint_mode); + void CallRuntime(Runtime::Function* function, int num_arguments, LInstruction* instr); + void CallRuntime(Runtime::FunctionId id, int num_arguments, LInstruction* instr) { @@ -180,6 +193,10 @@ class LCodeGen BASE_EMBEDDED { CallRuntime(function, num_arguments, instr); } + void CallRuntimeFromDeferred(Runtime::FunctionId id, + int argc, + LInstruction* instr); + // Generate a direct call to a known function. Expects the function // to be in edi. void CallKnownFunction(Handle function, @@ -188,7 +205,9 @@ class LCodeGen BASE_EMBEDDED { void LoadHeapObject(Register result, Handle object); - void RegisterLazyDeoptimization(LInstruction* instr); + void RegisterLazyDeoptimization(LInstruction* instr, + SafepointMode safepoint_mode); + void RegisterEnvironmentForDeoptimization(LEnvironment* environment); void DeoptimizeIf(Condition cc, LEnvironment* environment); @@ -275,6 +294,48 @@ class LCodeGen BASE_EMBEDDED { // Compiler from a set of parallel moves to a sequential list of moves. LGapResolver resolver_; + Safepoint::Kind expected_safepoint_kind_; + + class PushSafepointRegistersScope BASE_EMBEDDED { + public: + PushSafepointRegistersScope(LCodeGen* codegen, + Safepoint::Kind kind) + : codegen_(codegen) { + ASSERT(codegen_->expected_safepoint_kind_ == Safepoint::kSimple); + codegen_->expected_safepoint_kind_ = kind; + + switch (codegen_->expected_safepoint_kind_) { + case Safepoint::kWithRegisters: + codegen_->masm_->PushSafepointRegisters(); + break; + case Safepoint::kWithRegistersAndDoubles: + codegen_->masm_->PushSafepointRegistersAndDoubles(); + break; + default: + UNREACHABLE(); + } + } + + ~PushSafepointRegistersScope() { + Safepoint::Kind kind = codegen_->expected_safepoint_kind_; + ASSERT((kind & Safepoint::kWithRegisters) != 0); + switch (kind) { + case Safepoint::kWithRegisters: + codegen_->masm_->PopSafepointRegisters(); + break; + case Safepoint::kWithRegistersAndDoubles: + codegen_->masm_->PopSafepointRegistersAndDoubles(); + break; + default: + UNREACHABLE(); + } + codegen_->expected_safepoint_kind_ = Safepoint::kSimple; + } + + private: + LCodeGen* codegen_; + }; + friend class LDeferredCode; friend class LEnvironment; friend class SafepointGenerator; diff --git a/deps/v8/src/deoptimizer.cc b/deps/v8/src/deoptimizer.cc index af2f42e4663..9db812b3e34 100644 --- a/deps/v8/src/deoptimizer.cc +++ b/deps/v8/src/deoptimizer.cc @@ -196,8 +196,7 @@ Deoptimizer::Deoptimizer(JSFunction* function, fp_to_sp_delta_(fp_to_sp_delta), output_count_(0), output_(NULL), - integer32_values_(NULL), - double_values_(NULL) { + deferred_heap_numbers_(0) { if (FLAG_trace_deopt && type != OSR) { PrintF("**** DEOPT: "); function->PrintName(); @@ -236,8 +235,6 @@ Deoptimizer::Deoptimizer(JSFunction* function, Deoptimizer::~Deoptimizer() { ASSERT(input_ == NULL && output_ == NULL); - delete[] integer32_values_; - delete[] double_values_; } @@ -382,13 +379,8 @@ void Deoptimizer::DoComputeOutputFrames() { int count = iterator.Next(); ASSERT(output_ == NULL); output_ = new FrameDescription*[count]; - // Per-frame lists of untagged and unboxed int32 and double values. - integer32_values_ = new List[count]; - double_values_ = new List[count]; for (int i = 0; i < count; ++i) { output_[i] = NULL; - integer32_values_[i].Initialize(0); - double_values_[i].Initialize(0); } output_count_ = count; @@ -416,37 +408,19 @@ void Deoptimizer::DoComputeOutputFrames() { } -void Deoptimizer::InsertHeapNumberValues(int index, JavaScriptFrame* frame) { - // We need to adjust the stack index by one for the top-most frame. - int extra_slot_count = (index == output_count() - 1) ? 1 : 0; - List* ints = &integer32_values_[index]; - for (int i = 0; i < ints->length(); i++) { - ValueDescriptionInteger32 value = ints->at(i); - double val = static_cast(value.int32_value()); - InsertHeapNumberValue(frame, value.stack_index(), val, extra_slot_count); +void Deoptimizer::MaterializeHeapNumbers() { + for (int i = 0; i < deferred_heap_numbers_.length(); i++) { + HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i]; + Handle num = Factory::NewNumber(d.value()); + if (FLAG_trace_deopt) { + PrintF("Materializing a new heap number %p [%e] in slot %p\n", + reinterpret_cast(*num), + d.value(), + d.slot_address()); + } + + Memory::Object_at(d.slot_address()) = *num; } - - // Iterate over double values and convert them to a heap number. - List* doubles = &double_values_[index]; - for (int i = 0; i < doubles->length(); ++i) { - ValueDescriptionDouble value = doubles->at(i); - InsertHeapNumberValue(frame, value.stack_index(), value.double_value(), - extra_slot_count); - } -} - - -void Deoptimizer::InsertHeapNumberValue(JavaScriptFrame* frame, - int stack_index, - double val, - int extra_slot_count) { - // Add one to the TOS index to take the 'state' pushed before jumping - // to the stub that calls Runtime::NotifyDeoptimized into account. - int tos_index = stack_index + extra_slot_count; - int index = (frame->ComputeExpressionsCount() - 1) - tos_index; - if (FLAG_trace_deopt) PrintF("Allocating a new heap number: %e\n", val); - Handle num = Factory::NewNumber(val); - frame->SetExpression(index, *num); } @@ -492,7 +466,6 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, int input_reg = iterator->Next(); intptr_t value = input_->GetRegister(input_reg); bool is_smi = Smi::IsValid(value); - unsigned output_index = output_offset / kPointerSize; if (FLAG_trace_deopt) { PrintF( " 0x%08" V8PRIxPTR ": [top + %d] <- %" V8PRIdPTR " ; %s (%s)\n", @@ -509,9 +482,8 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, } else { // We save the untagged value on the side and store a GC-safe // temporary placeholder in the frame. - AddInteger32Value(frame_index, - output_index, - static_cast(value)); + AddDoubleValue(output_[frame_index]->GetTop() + output_offset, + static_cast(static_cast(value))); output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder); } return; @@ -520,7 +492,6 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, case Translation::DOUBLE_REGISTER: { int input_reg = iterator->Next(); double value = input_->GetDoubleRegister(input_reg); - unsigned output_index = output_offset / kPointerSize; if (FLAG_trace_deopt) { PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- %e ; %s\n", output_[frame_index]->GetTop() + output_offset, @@ -530,7 +501,7 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, } // We save the untagged value on the side and store a GC-safe // temporary placeholder in the frame. - AddDoubleValue(frame_index, output_index, value); + AddDoubleValue(output_[frame_index]->GetTop() + output_offset, value); output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder); return; } @@ -558,7 +529,6 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, input_->GetOffsetFromSlotIndex(this, input_slot_index); intptr_t value = input_->GetFrameSlot(input_offset); bool is_smi = Smi::IsValid(value); - unsigned output_index = output_offset / kPointerSize; if (FLAG_trace_deopt) { PrintF(" 0x%08" V8PRIxPTR ": ", output_[frame_index]->GetTop() + output_offset); @@ -575,9 +545,8 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, } else { // We save the untagged value on the side and store a GC-safe // temporary placeholder in the frame. - AddInteger32Value(frame_index, - output_index, - static_cast(value)); + AddDoubleValue(output_[frame_index]->GetTop() + output_offset, + static_cast(static_cast(value))); output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder); } return; @@ -588,7 +557,6 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, unsigned input_offset = input_->GetOffsetFromSlotIndex(this, input_slot_index); double value = input_->GetDoubleFrameSlot(input_offset); - unsigned output_index = output_offset / kPointerSize; if (FLAG_trace_deopt) { PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- %e ; [esp + %d]\n", output_[frame_index]->GetTop() + output_offset, @@ -598,7 +566,7 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, } // We save the untagged value on the side and store a GC-safe // temporary placeholder in the frame. - AddDoubleValue(frame_index, output_index, value); + AddDoubleValue(output_[frame_index]->GetTop() + output_offset, value); output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder); return; } @@ -901,19 +869,11 @@ Object* Deoptimizer::ComputeLiteral(int index) const { } -void Deoptimizer::AddInteger32Value(int frame_index, - int slot_index, - int32_t value) { - ValueDescriptionInteger32 value_desc(slot_index, value); - integer32_values_[frame_index].Add(value_desc); -} - - -void Deoptimizer::AddDoubleValue(int frame_index, - int slot_index, +void Deoptimizer::AddDoubleValue(intptr_t slot_address, double value) { - ValueDescriptionDouble value_desc(slot_index, value); - double_values_[frame_index].Add(value_desc); + HeapNumberMaterializationDescriptor value_desc( + reinterpret_cast
(slot_address), value); + deferred_heap_numbers_.Add(value_desc); } diff --git a/deps/v8/src/deoptimizer.h b/deps/v8/src/deoptimizer.h index 90495c97684..f4cd409be21 100644 --- a/deps/v8/src/deoptimizer.h +++ b/deps/v8/src/deoptimizer.h @@ -42,38 +42,17 @@ class TranslationIterator; class DeoptimizingCodeListNode; -class ValueDescription BASE_EMBEDDED { +class HeapNumberMaterializationDescriptor BASE_EMBEDDED { public: - explicit ValueDescription(int index) : stack_index_(index) { } - int stack_index() const { return stack_index_; } + HeapNumberMaterializationDescriptor(Address slot_address, double val) + : slot_address_(slot_address), val_(val) { } + + Address slot_address() const { return slot_address_; } + double value() const { return val_; } private: - // Offset relative to the top of the stack. - int stack_index_; -}; - - -class ValueDescriptionInteger32: public ValueDescription { - public: - ValueDescriptionInteger32(int index, int32_t value) - : ValueDescription(index), int32_value_(value) { } - int32_t int32_value() const { return int32_value_; } - - private: - // Raw value. - int32_t int32_value_; -}; - - -class ValueDescriptionDouble: public ValueDescription { - public: - ValueDescriptionDouble(int index, double value) - : ValueDescription(index), double_value_(value) { } - double double_value() const { return double_value_; } - - private: - // Raw value. - double double_value_; + Address slot_address_; + double val_; }; @@ -164,7 +143,7 @@ class Deoptimizer : public Malloced { ~Deoptimizer(); - void InsertHeapNumberValues(int index, JavaScriptFrame* frame); + void MaterializeHeapNumbers(); static void ComputeOutputFrames(Deoptimizer* deoptimizer); @@ -253,13 +232,7 @@ class Deoptimizer : public Malloced { Object* ComputeLiteral(int index) const; - void InsertHeapNumberValue(JavaScriptFrame* frame, - int stack_index, - double val, - int extra_slot_count); - - void AddInteger32Value(int frame_index, int slot_index, int32_t value); - void AddDoubleValue(int frame_index, int slot_index, double value); + void AddDoubleValue(intptr_t slot_address, double value); static LargeObjectChunk* CreateCode(BailoutType type); static void GenerateDeoptimizationEntries( @@ -295,8 +268,7 @@ class Deoptimizer : public Malloced { // Array of output frame descriptions. FrameDescription** output_; - List* integer32_values_; - List* double_values_; + List deferred_heap_numbers_; static int table_entry_size_; diff --git a/deps/v8/src/frames-inl.h b/deps/v8/src/frames-inl.h index 78bb646c78d..9430cad0d78 100644 --- a/deps/v8/src/frames-inl.h +++ b/deps/v8/src/frames-inl.h @@ -136,15 +136,26 @@ inline bool StandardFrame::IsConstructFrame(Address fp) { } +Address JavaScriptFrame::GetParameterSlot(int index) const { + int param_count = ComputeParametersCount(); + ASSERT(-1 <= index && index < param_count); + int parameter_offset = (param_count - index - 1) * kPointerSize; + return caller_sp() + parameter_offset; +} + + +Object* JavaScriptFrame::GetParameter(int index) const { + return Memory::Object_at(GetParameterSlot(index)); +} + + inline Object* JavaScriptFrame::receiver() const { - const int offset = JavaScriptFrameConstants::kReceiverOffset; - return Memory::Object_at(caller_sp() + offset); + return GetParameter(-1); } inline void JavaScriptFrame::set_receiver(Object* value) { - const int offset = JavaScriptFrameConstants::kReceiverOffset; - Memory::Object_at(caller_sp() + offset) = value; + Memory::Object_at(GetParameterSlot(-1)) = value; } diff --git a/deps/v8/src/frames.cc b/deps/v8/src/frames.cc index 24ea8dde2d8..e94fdd84e55 100644 --- a/deps/v8/src/frames.cc +++ b/deps/v8/src/frames.cc @@ -540,9 +540,7 @@ void OptimizedFrame::Iterate(ObjectVisitor* v) const { pc(), &safepoint_entry, &stack_slots); unsigned slot_space = stack_slots * kPointerSize; - // Visit the outgoing parameters. This is usually dealt with by the - // callee, but while GC'ing we artificially lower the number of - // arguments to zero and let the caller deal with it. + // Visit the outgoing parameters. Object** parameters_base = &Memory::Object_at(sp()); Object** parameters_limit = &Memory::Object_at( fp() + JavaScriptFrameConstants::kFunctionOffset - slot_space); @@ -596,21 +594,6 @@ void OptimizedFrame::Iterate(ObjectVisitor* v) const { // Visit the return address in the callee and incoming arguments. IteratePc(v, pc_address(), code); - IterateArguments(v); -} - - -Object* JavaScriptFrame::GetParameter(int index) const { - ASSERT(index >= 0 && index < ComputeParametersCount()); - const int offset = JavaScriptFrameConstants::kParam0Offset; - return Memory::Object_at(caller_sp() + offset - (index * kPointerSize)); -} - - -int JavaScriptFrame::ComputeParametersCount() const { - Address base = caller_sp() + JavaScriptFrameConstants::kReceiverOffset; - Address limit = fp() + JavaScriptFrameConstants::kSavedRegistersOffset; - return static_cast((base - limit) / kPointerSize); } @@ -630,32 +613,17 @@ Code* JavaScriptFrame::unchecked_code() const { } -int JavaScriptFrame::GetProvidedParametersCount() const { - return ComputeParametersCount(); +int JavaScriptFrame::GetNumberOfIncomingArguments() const { + ASSERT(!SafeStackFrameIterator::is_active() && + Heap::gc_state() == Heap::NOT_IN_GC); + + JSFunction* function = JSFunction::cast(this->function()); + return function->shared()->formal_parameter_count(); } Address JavaScriptFrame::GetCallerStackPointer() const { - int arguments; - if (Heap::gc_state() != Heap::NOT_IN_GC || - SafeStackFrameIterator::is_active()) { - // If the we are currently iterating the safe stack the - // arguments for frames are traversed as if they were - // expression stack elements of the calling frame. The reason for - // this rather strange decision is that we cannot access the - // function during mark-compact GCs when objects may have been marked. - // In fact accessing heap objects (like function->shared() below) - // at all during GC is problematic. - arguments = 0; - } else { - // Compute the number of arguments by getting the number of formal - // parameters of the function. We must remember to take the - // receiver into account (+1). - JSFunction* function = JSFunction::cast(this->function()); - arguments = function->shared()->formal_parameter_count() + 1; - } - const int offset = StandardFrameConstants::kCallerSPOffset; - return fp() + offset + (arguments * kPointerSize); + return fp() + StandardFrameConstants::kCallerSPOffset; } @@ -833,9 +801,7 @@ void OptimizedFrame::GetFunctions(List* functions) { Address ArgumentsAdaptorFrame::GetCallerStackPointer() const { - const int arguments = Smi::cast(GetExpression(0))->value(); - const int offset = StandardFrameConstants::kCallerSPOffset; - return fp() + offset + (arguments + 1) * kPointerSize; + return fp() + StandardFrameConstants::kCallerSPOffset; } @@ -1074,17 +1040,6 @@ void StandardFrame::IterateExpressions(ObjectVisitor* v) const { void JavaScriptFrame::Iterate(ObjectVisitor* v) const { IterateExpressions(v); IteratePc(v, pc_address(), code()); - IterateArguments(v); -} - - -void JavaScriptFrame::IterateArguments(ObjectVisitor* v) const { - // Traverse callee-saved registers, receiver, and parameters. - const int kBaseOffset = JavaScriptFrameConstants::kSavedRegistersOffset; - const int kLimitOffset = JavaScriptFrameConstants::kReceiverOffset; - Object** base = &Memory::Object_at(fp() + kBaseOffset); - Object** limit = &Memory::Object_at(caller_sp() + kLimitOffset) + 1; - v->VisitPointers(base, limit); } diff --git a/deps/v8/src/frames.h b/deps/v8/src/frames.h index 53787090622..03e5e671b72 100644 --- a/deps/v8/src/frames.h +++ b/deps/v8/src/frames.h @@ -449,14 +449,11 @@ class JavaScriptFrame: public StandardFrame { inline void set_receiver(Object* value); // Access the parameters. - Object* GetParameter(int index) const; - int ComputeParametersCount() const; - - // Temporary way of getting access to the number of parameters - // passed on the stack by the caller. Once argument adaptor frames - // has been introduced on ARM, this number will always match the - // computed parameters count. - int GetProvidedParametersCount() const; + inline Address GetParameterSlot(int index) const; + inline Object* GetParameter(int index) const; + inline int ComputeParametersCount() const { + return GetNumberOfIncomingArguments(); + } // Check if this frame is a constructor frame invoked through 'new'. bool IsConstructor() const; @@ -494,6 +491,8 @@ class JavaScriptFrame: public StandardFrame { virtual Address GetCallerStackPointer() const; + virtual int GetNumberOfIncomingArguments() const; + // Garbage collection support. Iterates over incoming arguments, // receiver, and any callee-saved registers. void IterateArguments(ObjectVisitor* v) const; @@ -554,6 +553,10 @@ class ArgumentsAdaptorFrame: public JavaScriptFrame { explicit ArgumentsAdaptorFrame(StackFrameIterator* iterator) : JavaScriptFrame(iterator) { } + virtual int GetNumberOfIncomingArguments() const { + return Smi::cast(GetExpression(0))->value(); + } + virtual Address GetCallerStackPointer() const; private: diff --git a/deps/v8/src/ia32/lithium-codegen-ia32.cc b/deps/v8/src/ia32/lithium-codegen-ia32.cc index 2b7712c4397..a1be11d8380 100644 --- a/deps/v8/src/ia32/lithium-codegen-ia32.cc +++ b/deps/v8/src/ia32/lithium-codegen-ia32.cc @@ -418,20 +418,21 @@ void LCodeGen::AddToTranslation(Translation* translation, } -void LCodeGen::CallCode(Handle code, - RelocInfo::Mode mode, - LInstruction* instr, - bool adjusted) { +void LCodeGen::CallCodeGeneric(Handle code, + RelocInfo::Mode mode, + LInstruction* instr, + ContextMode context_mode, + SafepointMode safepoint_mode) { ASSERT(instr != NULL); LPointerMap* pointers = instr->pointer_map(); RecordPosition(pointers->position()); - if (!adjusted) { + if (context_mode == RESTORE_CONTEXT) { __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); } __ call(code, mode); - RegisterLazyDeoptimization(instr); + RegisterLazyDeoptimization(instr, safepoint_mode); // Signal that we don't inline smi code before these stubs in the // optimizing code generator. @@ -442,25 +443,44 @@ void LCodeGen::CallCode(Handle code, } +void LCodeGen::CallCode(Handle code, + RelocInfo::Mode mode, + LInstruction* instr, + ContextMode context_mode) { + CallCodeGeneric(code, mode, instr, context_mode, RECORD_SIMPLE_SAFEPOINT); +} + + void LCodeGen::CallRuntime(Runtime::Function* fun, int argc, LInstruction* instr, - bool adjusted) { + ContextMode context_mode) { ASSERT(instr != NULL); ASSERT(instr->HasPointerMap()); LPointerMap* pointers = instr->pointer_map(); RecordPosition(pointers->position()); - if (!adjusted) { + if (context_mode == RESTORE_CONTEXT) { __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); } __ CallRuntime(fun, argc); - RegisterLazyDeoptimization(instr); + RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT); } -void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr) { +void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id, + int argc, + LInstruction* instr) { + __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); + __ CallRuntimeSaveDoubles(id); + RecordSafepointWithRegisters( + instr->pointer_map(), argc, Safepoint::kNoDeoptimizationIndex); +} + + +void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr, + SafepointMode safepoint_mode) { // Create the environment to bailout to. If the call has side effects // execution has to continue after the call otherwise execution can continue // from a previous bailout point repeating the call. @@ -472,8 +492,16 @@ void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr) { } RegisterEnvironmentForDeoptimization(deoptimization_environment); - RecordSafepoint(instr->pointer_map(), - deoptimization_environment->deoptimization_index()); + if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) { + RecordSafepoint(instr->pointer_map(), + deoptimization_environment->deoptimization_index()); + } else { + ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); + RecordSafepointWithRegisters( + instr->pointer_map(), + 0, + deoptimization_environment->deoptimization_index()); + } } @@ -622,6 +650,7 @@ void LCodeGen::RecordSafepoint( Safepoint::Kind kind, int arguments, int deoptimization_index) { + ASSERT(kind == expected_safepoint_kind_); const ZoneList* operands = pointers->operands(); Safepoint safepoint = safepoints_.DefineSafepoint(masm(), kind, arguments, deoptimization_index); @@ -707,48 +736,48 @@ void LCodeGen::DoCallStub(LCallStub* instr) { switch (instr->hydrogen()->major_key()) { case CodeStub::RegExpConstructResult: { RegExpConstructResultStub stub; - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED); break; } case CodeStub::RegExpExec: { RegExpExecStub stub; - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED); break; } case CodeStub::SubString: { SubStringStub stub; - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED); break; } case CodeStub::StringCharAt: { StringCharAtStub stub; - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED); break; } case CodeStub::MathPow: { MathPowStub stub; - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED); break; } case CodeStub::NumberToString: { NumberToStringStub stub; - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED); break; } case CodeStub::StringAdd: { StringAddStub stub(NO_STRING_ADD_FLAGS); - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED); break; } case CodeStub::StringCompare: { StringCompareStub stub; - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED); break; } case CodeStub::TranscendentalCache: { TranscendentalCacheStub stub(instr->transcendental_type(), TranscendentalCacheStub::TAGGED); - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED); break; } default: @@ -1098,7 +1127,7 @@ void LCodeGen::DoBitNotI(LBitNotI* instr) { void LCodeGen::DoThrow(LThrow* instr) { __ push(ToOperand(instr->InputAt(0))); - CallRuntime(Runtime::kThrow, 1, instr, false); + CallRuntime(Runtime::kThrow, 1, instr, RESTORE_CONTEXT); if (FLAG_debug_code) { Comment("Unreachable code."); @@ -1170,7 +1199,7 @@ void LCodeGen::DoArithmeticT(LArithmeticT* instr) { ASSERT(ToRegister(instr->result()).is(eax)); TypeRecordingBinaryOpStub stub(instr->op(), NO_OVERWRITE); - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false); + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT); } @@ -1282,12 +1311,8 @@ void LCodeGen::EmitGoto(int block, LDeferredCode* deferred_stack_check) { void LCodeGen::DoDeferredStackCheck(LGoto* instr) { - __ pushad(); - __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); - __ CallRuntimeSaveDoubles(Runtime::kStackGuard); - RecordSafepointWithRegisters( - instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); - __ popad(); + PushSafepointRegistersScope scope(this); + CallRuntimeFromDeferred(Runtime::kStackGuard, 0, instr); } void LCodeGen::DoGoto(LGoto* instr) { @@ -1776,7 +1801,7 @@ void LCodeGen::DoInstanceOf(LInstanceOf* instr) { // Object and function are in fixed registers defined by the stub. ASSERT(ToRegister(instr->context()).is(esi)); InstanceofStub stub(InstanceofStub::kArgsInRegisters); - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED); NearLabel true_value, done; __ test(eax, Operand(eax)); @@ -1795,7 +1820,7 @@ void LCodeGen::DoInstanceOfAndBranch(LInstanceOfAndBranch* instr) { int false_block = chunk_->LookupDestination(instr->false_block_id()); InstanceofStub stub(InstanceofStub::kArgsInRegisters); - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED); __ test(eax, Operand(eax)); EmitBranch(true_block, false_block, zero); } @@ -1867,7 +1892,7 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, Label* map_check) { - __ PushSafepointRegisters(); + PushSafepointRegistersScope scope(this); InstanceofStub::Flags flags = InstanceofStub::kNoFlags; flags = static_cast( @@ -1878,11 +1903,12 @@ void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, flags | InstanceofStub::kReturnTrueFalseObject); InstanceofStub stub(flags); - // Get the temp register reserved by the instruction. This needs to be edi as - // its slot of the pushing of safepoint registers is used to communicate the - // offset to the location of the map check. + // Get the temp register reserved by the instruction. This needs to be a + // register which is pushed last by PushSafepointRegisters as top of the + // stack is used to pass the offset to the location of the map check to + // the stub. Register temp = ToRegister(instr->TempAt(0)); - ASSERT(temp.is(edi)); + ASSERT(MacroAssembler::SafepointRegisterStackIndex(temp) == 0); __ mov(InstanceofStub::right(), Immediate(instr->function())); static const int kAdditionalDelta = 16; int delta = masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta; @@ -1890,10 +1916,13 @@ void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, __ bind(&before_push_delta); __ mov(temp, Immediate(delta)); __ StoreToSafepointRegisterSlot(temp, temp); - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false); + CallCodeGeneric(stub.GetCode(), + RelocInfo::CODE_TARGET, + instr, + RESTORE_CONTEXT, + RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); // Put the result value into the eax slot and restore all registers. __ StoreToSafepointRegisterSlot(eax, eax); - __ PopSafepointRegisters(); } @@ -1921,7 +1950,7 @@ void LCodeGen::DoCmpT(LCmpT* instr) { Token::Value op = instr->op(); Handle ic = CompareIC::GetUninitialized(op); - CallCode(ic, RelocInfo::CODE_TARGET, instr, false); + CallCode(ic, RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT); Condition condition = ComputeCompareCondition(op); if (op == Token::GT || op == Token::LTE) { @@ -1944,7 +1973,7 @@ void LCodeGen::DoCmpTAndBranch(LCmpTAndBranch* instr) { int false_block = chunk_->LookupDestination(instr->false_block_id()); Handle ic = CompareIC::GetUninitialized(op); - CallCode(ic, RelocInfo::CODE_TARGET, instr, false); + CallCode(ic, RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT); // The compare stub expects compare condition and the input operands // reversed for GT and LTE. @@ -2039,7 +2068,7 @@ void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { __ mov(ecx, instr->name()); Handle ic(Builtins::builtin(Builtins::LoadIC_Initialize)); - CallCode(ic, RelocInfo::CODE_TARGET, instr); + CallCode(ic, RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED); } @@ -2163,7 +2192,7 @@ void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { ASSERT(ToRegister(instr->key()).is(eax)); Handle ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); - CallCode(ic, RelocInfo::CODE_TARGET, instr); + CallCode(ic, RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED); } @@ -2351,7 +2380,7 @@ void LCodeGen::CallKnownFunction(Handle function, } // Setup deoptimization. - RegisterLazyDeoptimization(instr); + RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT); } @@ -2373,7 +2402,7 @@ void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) { Register tmp2 = tmp.is(ecx) ? edx : input_reg.is(ecx) ? edx : ecx; // Preserve the value of all registers. - __ PushSafepointRegisters(); + PushSafepointRegistersScope scope(this); Label negative; __ mov(tmp, FieldOperand(input_reg, HeapNumber::kExponentOffset)); @@ -2394,10 +2423,8 @@ void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) { // Slow case: Call the runtime system to do the number allocation. __ bind(&slow); - __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); - __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); - RecordSafepointWithRegisters( - instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); + CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr); + // Set the pointer to the new heap number in tmp. if (!tmp.is(eax)) __ mov(tmp, eax); @@ -2413,7 +2440,6 @@ void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) { __ StoreToSafepointRegisterSlot(input_reg, tmp); __ bind(&done); - __ PopSafepointRegisters(); } @@ -2601,7 +2627,7 @@ void LCodeGen::DoMathLog(LUnaryMathOperation* instr) { ASSERT(ToDoubleRegister(instr->result()).is(xmm1)); TranscendentalCacheStub stub(TranscendentalCache::LOG, TranscendentalCacheStub::UNTAGGED); - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false); + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT); } @@ -2609,7 +2635,7 @@ void LCodeGen::DoMathCos(LUnaryMathOperation* instr) { ASSERT(ToDoubleRegister(instr->result()).is(xmm1)); TranscendentalCacheStub stub(TranscendentalCache::COS, TranscendentalCacheStub::UNTAGGED); - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false); + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT); } @@ -2617,7 +2643,7 @@ void LCodeGen::DoMathSin(LUnaryMathOperation* instr) { ASSERT(ToDoubleRegister(instr->result()).is(xmm1)); TranscendentalCacheStub stub(TranscendentalCache::SIN, TranscendentalCacheStub::UNTAGGED); - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false); + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT); } @@ -2661,7 +2687,7 @@ void LCodeGen::DoCallKeyed(LCallKeyed* instr) { int arity = instr->arity(); Handle ic = StubCache::ComputeKeyedCallInitialize(arity, NOT_IN_LOOP); - CallCode(ic, RelocInfo::CODE_TARGET, instr); + CallCode(ic, RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED); } @@ -2672,7 +2698,7 @@ void LCodeGen::DoCallNamed(LCallNamed* instr) { int arity = instr->arity(); Handle ic = StubCache::ComputeCallInitialize(arity, NOT_IN_LOOP); __ mov(ecx, instr->name()); - CallCode(ic, RelocInfo::CODE_TARGET, instr); + CallCode(ic, RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED); } @@ -2682,7 +2708,7 @@ void LCodeGen::DoCallFunction(LCallFunction* instr) { int arity = instr->arity(); CallFunctionStub stub(arity, NOT_IN_LOOP, RECEIVER_MIGHT_BE_VALUE); - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED); __ Drop(1); } @@ -2694,7 +2720,7 @@ void LCodeGen::DoCallGlobal(LCallGlobal* instr) { int arity = instr->arity(); Handle ic = StubCache::ComputeCallInitialize(arity, NOT_IN_LOOP); __ mov(ecx, instr->name()); - CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr); + CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr, CONTEXT_ADJUSTED); } @@ -2712,12 +2738,12 @@ void LCodeGen::DoCallNew(LCallNew* instr) { Handle builtin(Builtins::builtin(Builtins::JSConstructCall)); __ Set(eax, Immediate(instr->arity())); - CallCode(builtin, RelocInfo::CONSTRUCT_CALL, instr); + CallCode(builtin, RelocInfo::CONSTRUCT_CALL, instr, CONTEXT_ADJUSTED); } void LCodeGen::DoCallRuntime(LCallRuntime* instr) { - CallRuntime(instr->function(), instr->arity(), instr, false); + CallRuntime(instr->function(), instr->arity(), instr, RESTORE_CONTEXT); } @@ -2760,7 +2786,7 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { Handle ic(Builtins::builtin( info_->is_strict() ? Builtins::StoreIC_Initialize_Strict : Builtins::StoreIC_Initialize)); - CallCode(ic, RelocInfo::CODE_TARGET, instr); + CallCode(ic, RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED); } @@ -2830,7 +2856,7 @@ void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { Handle ic(Builtins::builtin( info_->is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict : Builtins::KeyedStoreIC_Initialize)); - CallCode(ic, RelocInfo::CODE_TARGET, instr); + CallCode(ic, RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED); } @@ -2948,7 +2974,7 @@ void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) { // contained in the register pointer map. __ Set(result, Immediate(0)); - __ PushSafepointRegisters(); + PushSafepointRegistersScope scope(this); __ push(string); // Push the index as a smi. This is safe because of the checks in // DoStringCharCodeAt above. @@ -2961,16 +2987,12 @@ void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) { __ SmiTag(index); __ push(index); } - __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); - __ CallRuntimeSaveDoubles(Runtime::kStringCharCodeAt); - RecordSafepointWithRegisters( - instr->pointer_map(), 2, Safepoint::kNoDeoptimizationIndex); + CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2, instr); if (FLAG_debug_code) { __ AbortIfNotSmi(eax); } __ SmiUntag(eax); __ StoreToSafepointRegisterSlot(result, eax); - __ PopSafepointRegisters(); } @@ -3017,7 +3039,7 @@ void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) { Register tmp = reg.is(eax) ? ecx : eax; // Preserve the value of all registers. - __ PushSafepointRegisters(); + PushSafepointRegistersScope scope(this); // There was overflow, so bits 30 and 31 of the original integer // disagree. Try to allocate a heap number in new space and store @@ -3039,10 +3061,7 @@ void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) { // integer value. __ StoreToSafepointRegisterSlot(reg, Immediate(0)); - __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); - __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); - RecordSafepointWithRegisters( - instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); + CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr); if (!reg.is(eax)) __ mov(reg, eax); // Done. Put the value in xmm0 into the value of the allocated heap @@ -3050,7 +3069,6 @@ void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) { __ bind(&done); __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), xmm0); __ StoreToSafepointRegisterSlot(reg, reg); - __ PopSafepointRegisters(); } @@ -3086,13 +3104,9 @@ void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) { Register reg = ToRegister(instr->result()); __ Set(reg, Immediate(0)); - __ PushSafepointRegisters(); - __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); - __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); - RecordSafepointWithRegisters( - instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); + PushSafepointRegistersScope scope(this); + CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr); __ StoreToSafepointRegisterSlot(reg, eax); - __ PopSafepointRegisters(); } @@ -3503,16 +3517,16 @@ void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) { FastCloneShallowArrayStub::Mode mode = FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS; FastCloneShallowArrayStub stub(mode, length); - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false); + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT); } else if (instr->hydrogen()->depth() > 1) { - CallRuntime(Runtime::kCreateArrayLiteral, 3, instr, false); + CallRuntime(Runtime::kCreateArrayLiteral, 3, instr, RESTORE_CONTEXT); } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) { - CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr, false); + CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr, RESTORE_CONTEXT); } else { FastCloneShallowArrayStub::Mode mode = FastCloneShallowArrayStub::CLONE_ELEMENTS; FastCloneShallowArrayStub stub(mode, length); - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false); + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT); } } @@ -3528,9 +3542,12 @@ void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) { // Pick the right runtime function to call. if (instr->hydrogen()->depth() > 1) { - CallRuntime(Runtime::kCreateObjectLiteral, 4, instr); + CallRuntime(Runtime::kCreateObjectLiteral, 4, instr, CONTEXT_ADJUSTED); } else { - CallRuntime(Runtime::kCreateObjectLiteralShallow, 4, instr); + CallRuntime(Runtime::kCreateObjectLiteralShallow, + 4, + instr, + CONTEXT_ADJUSTED); } } @@ -3556,7 +3573,7 @@ void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) { __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index()))); __ push(Immediate(instr->hydrogen()->pattern())); __ push(Immediate(instr->hydrogen()->flags())); - CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr, false); + CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr, RESTORE_CONTEXT); __ mov(ebx, eax); __ bind(&materialized); @@ -3568,7 +3585,7 @@ void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) { __ bind(&runtime_allocate); __ push(ebx); __ push(Immediate(Smi::FromInt(size))); - CallRuntime(Runtime::kAllocateInNewSpace, 1, instr, false); + CallRuntime(Runtime::kAllocateInNewSpace, 1, instr, RESTORE_CONTEXT); __ pop(ebx); __ bind(&allocated); @@ -3595,14 +3612,14 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { if (shared_info->num_literals() == 0 && !pretenure) { FastNewClosureStub stub; __ push(Immediate(shared_info)); - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false); + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT); } else { __ push(Operand(ebp, StandardFrameConstants::kContextOffset)); __ push(Immediate(shared_info)); __ push(Immediate(pretenure ? Factory::true_value() : Factory::false_value())); - CallRuntime(Runtime::kNewClosure, 3, instr, false); + CallRuntime(Runtime::kNewClosure, 3, instr, RESTORE_CONTEXT); } } @@ -3614,7 +3631,7 @@ void LCodeGen::DoTypeof(LTypeof* instr) { } else { __ push(ToOperand(input)); } - CallRuntime(Runtime::kTypeof, 1, instr, false); + CallRuntime(Runtime::kTypeof, 1, instr, RESTORE_CONTEXT); } @@ -3825,7 +3842,7 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) { __ j(above_equal, &done); StackCheckStub stub; - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false); + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT); __ bind(&done); } diff --git a/deps/v8/src/ia32/lithium-codegen-ia32.h b/deps/v8/src/ia32/lithium-codegen-ia32.h index 5ba4bc4352b..681ea77e5bc 100644 --- a/deps/v8/src/ia32/lithium-codegen-ia32.h +++ b/deps/v8/src/ia32/lithium-codegen-ia32.h @@ -61,7 +61,8 @@ class LCodeGen BASE_EMBEDDED { deferred_(8), osr_pc_offset_(-1), deoptimization_reloc_size(), - resolver_(this) { + resolver_(this), + expected_safepoint_kind_(Safepoint::kSimple) { PopulateDeoptimizationLiteralsWithInlinedFunctions(); } @@ -159,16 +160,44 @@ class LCodeGen BASE_EMBEDDED { bool GenerateRelocPadding(); bool GenerateSafepointTable(); - void CallCode(Handle code, RelocInfo::Mode mode, LInstruction* instr, - bool adjusted = true); - void CallRuntime(Runtime::Function* fun, int argc, LInstruction* instr, - bool adjusted = true); - void CallRuntime(Runtime::FunctionId id, int argc, LInstruction* instr, - bool adjusted = true) { + enum ContextMode { + RESTORE_CONTEXT, + CONTEXT_ADJUSTED + }; + + enum SafepointMode { + RECORD_SIMPLE_SAFEPOINT, + RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS + }; + + void CallCode(Handle code, + RelocInfo::Mode mode, + LInstruction* instr, + ContextMode context_mode); + + void CallCodeGeneric(Handle code, + RelocInfo::Mode mode, + LInstruction* instr, + ContextMode context_mode, + SafepointMode safepoint_mode); + + void CallRuntime(Runtime::Function* fun, + int argc, + LInstruction* instr, + ContextMode context_mode); + + void CallRuntime(Runtime::FunctionId id, + int argc, + LInstruction* instr, + ContextMode context_mode) { Runtime::Function* function = Runtime::FunctionForId(id); - CallRuntime(function, argc, instr, adjusted); + CallRuntime(function, argc, instr, context_mode); } + void CallRuntimeFromDeferred(Runtime::FunctionId id, + int argc, + LInstruction* instr); + // Generate a direct call to a known function. Expects the function // to be in edi. void CallKnownFunction(Handle function, @@ -177,7 +206,9 @@ class LCodeGen BASE_EMBEDDED { void LoadHeapObject(Register result, Handle object); - void RegisterLazyDeoptimization(LInstruction* instr); + void RegisterLazyDeoptimization(LInstruction* instr, + SafepointMode safepoint_mode); + void RegisterEnvironmentForDeoptimization(LEnvironment* environment); void DeoptimizeIf(Condition cc, LEnvironment* environment); @@ -272,6 +303,27 @@ class LCodeGen BASE_EMBEDDED { // Compiler from a set of parallel moves to a sequential list of moves. LGapResolver resolver_; + Safepoint::Kind expected_safepoint_kind_; + + class PushSafepointRegistersScope BASE_EMBEDDED { + public: + explicit PushSafepointRegistersScope(LCodeGen* codegen) + : codegen_(codegen) { + ASSERT(codegen_->expected_safepoint_kind_ == Safepoint::kSimple); + codegen_->masm_->PushSafepointRegisters(); + codegen_->expected_safepoint_kind_ = Safepoint::kWithRegisters; + } + + ~PushSafepointRegistersScope() { + ASSERT(codegen_->expected_safepoint_kind_ == Safepoint::kWithRegisters); + codegen_->masm_->PopSafepointRegisters(); + codegen_->expected_safepoint_kind_ = Safepoint::kSimple; + } + + private: + LCodeGen* codegen_; + }; + friend class LDeferredCode; friend class LEnvironment; friend class SafepointGenerator; diff --git a/deps/v8/src/ia32/macro-assembler-ia32.h b/deps/v8/src/ia32/macro-assembler-ia32.h index 62bb0f36343..580aad1a5e2 100644 --- a/deps/v8/src/ia32/macro-assembler-ia32.h +++ b/deps/v8/src/ia32/macro-assembler-ia32.h @@ -635,6 +635,10 @@ class MacroAssembler: public Assembler { Register scratch2, Label* on_not_flat_ascii_strings); + static int SafepointRegisterStackIndex(Register reg) { + return SafepointRegisterStackIndex(reg.code()); + } + private: bool generating_stub_; bool allow_stub_calls_; diff --git a/deps/v8/src/runtime.cc b/deps/v8/src/runtime.cc index 0c15f60f306..4fe0e82b329 100644 --- a/deps/v8/src/runtime.cc +++ b/deps/v8/src/runtime.cc @@ -4332,7 +4332,7 @@ static MaybeObject* Runtime_GetArgumentsProperty(Arguments args) { JavaScriptFrame* frame = it.frame(); // Get the actual number of provided arguments. - const uint32_t n = frame->GetProvidedParametersCount(); + const uint32_t n = frame->ComputeParametersCount(); // Try to convert the key to an index. If successful and within // index return the the argument from the frame. @@ -6887,7 +6887,7 @@ static MaybeObject* Runtime_NewObjectFromBound(Arguments args) { ASSERT(!frame->is_optimized()); it.AdvanceToArgumentsFrame(); frame = it.frame(); - int argc = frame->GetProvidedParametersCount(); + int argc = frame->ComputeParametersCount(); // Prepend bound arguments to caller's arguments. int total_argc = bound_argc + argc; @@ -7092,14 +7092,13 @@ static MaybeObject* Runtime_NotifyDeoptimized(Arguments args) { ASSERT(Heap::IsAllocationAllowed()); int frames = deoptimizer->output_count(); + deoptimizer->MaterializeHeapNumbers(); + delete deoptimizer; + JavaScriptFrameIterator it; JavaScriptFrame* frame = NULL; - for (int i = 0; i < frames; i++) { - if (i != 0) it.Advance(); - frame = it.frame(); - deoptimizer->InsertHeapNumberValues(frames - i - 1, frame); - } - delete deoptimizer; + for (int i = 0; i < frames - 1; i++) it.Advance(); + frame = it.frame(); RUNTIME_ASSERT(frame->function()->IsJSFunction()); Handle function(JSFunction::cast(frame->function())); @@ -7720,7 +7719,7 @@ static void PrintTransition(Object* result) { // supplied parameters, not all parameters required) PrintF("(this="); PrintObject(frame->receiver()); - const int length = frame->GetProvidedParametersCount(); + const int length = frame->ComputeParametersCount(); for (int i = 0; i < length; i++) { PrintF(", "); PrintObject(frame->GetParameter(i)); @@ -9223,8 +9222,8 @@ static MaybeObject* Runtime_GetFrameDetails(Arguments args) { // Find the number of arguments to fill. At least fill the number of // parameters for the function and fill more if more parameters are provided. int argument_count = info.number_of_parameters(); - if (argument_count < it.frame()->GetProvidedParametersCount()) { - argument_count = it.frame()->GetProvidedParametersCount(); + if (argument_count < it.frame()->ComputeParametersCount()) { + argument_count = it.frame()->ComputeParametersCount(); } // Calculate the size of the result. @@ -9281,7 +9280,7 @@ static MaybeObject* Runtime_GetFrameDetails(Arguments args) { // TODO(3141533): We should be able to get the actual parameter // value for optimized frames. if (!is_optimized_frame && - (i < it.frame()->GetProvidedParametersCount())) { + (i < it.frame()->ComputeParametersCount())) { details->set(details_index++, it.frame()->GetParameter(i)); } else { details->set(details_index++, Heap::undefined_value()); @@ -10161,7 +10160,7 @@ static Handle GetArgumentsObject(JavaScriptFrame* frame, } } - const int length = frame->GetProvidedParametersCount(); + const int length = frame->ComputeParametersCount(); Handle arguments = Factory::NewArgumentsObject(function, length); Handle array = Factory::NewFixedArray(length); diff --git a/deps/v8/src/scopes.cc b/deps/v8/src/scopes.cc index a89bf9638c7..6a720f5f005 100644 --- a/deps/v8/src/scopes.cc +++ b/deps/v8/src/scopes.cc @@ -118,7 +118,7 @@ Scope::Scope(Type type) params_(0), unresolved_(0), decls_(0) { - SetDefaults(type, NULL, NULL); + SetDefaults(type, NULL, Handle::null()); ASSERT(!resolved()); } @@ -130,7 +130,7 @@ Scope::Scope(Scope* outer_scope, Type type) params_(4), unresolved_(16), decls_(4) { - SetDefaults(type, outer_scope, NULL); + SetDefaults(type, outer_scope, Handle::null()); // At some point we might want to provide outer scopes to // eval scopes (by walking the stack and reading the scope info). // In that case, the ASSERT below needs to be adjusted. @@ -140,14 +140,14 @@ Scope::Scope(Scope* outer_scope, Type type) } -Scope::Scope(Scope* inner_scope, SerializedScopeInfo* scope_info) +Scope::Scope(Scope* inner_scope, Handle scope_info) : inner_scopes_(4), variables_(), temps_(4), params_(4), unresolved_(16), decls_(4) { - ASSERT(scope_info != NULL); + ASSERT(!scope_info.is_null()); SetDefaults(FUNCTION_SCOPE, NULL, scope_info); ASSERT(resolved()); if (scope_info->HasHeapAllocatedLocals()) { @@ -176,6 +176,31 @@ Scope::Scope(Scope* inner_scope, SerializedScopeInfo* scope_info) } +void Scope::SetDefaults(Type type, + Scope* outer_scope, + Handle scope_info) { + outer_scope_ = outer_scope; + type_ = type; + scope_name_ = Factory::empty_symbol(); + dynamics_ = NULL; + receiver_ = NULL; + function_ = NULL; + arguments_ = NULL; + arguments_shadow_ = NULL; + illegal_redecl_ = NULL; + scope_inside_with_ = false; + scope_contains_with_ = false; + scope_calls_eval_ = false; + outer_scope_calls_eval_ = false; + inner_scope_calls_eval_ = false; + outer_scope_is_eval_scope_ = false; + force_eager_compilation_ = false; + num_stack_slots_ = 0; + num_heap_slots_ = 0; + scope_info_ = scope_info; +} + + Scope* Scope::DeserializeScopeChain(CompilationInfo* info, Scope* global_scope) { ASSERT(!info->closure().is_null()); @@ -188,8 +213,8 @@ Scope* Scope::DeserializeScopeChain(CompilationInfo* info, JSFunction* current = *info->closure(); do { current = current->context()->closure(); - SerializedScopeInfo* scope_info = current->shared()->scope_info(); - if (scope_info != SerializedScopeInfo::Empty()) { + Handle scope_info(current->shared()->scope_info()); + if (*scope_info != SerializedScopeInfo::Empty()) { scope = new Scope(scope, scope_info); if (innermost_scope == NULL) innermost_scope = scope; } else { diff --git a/deps/v8/src/scopes.h b/deps/v8/src/scopes.h index 140ff199429..4a48a4c453b 100644 --- a/deps/v8/src/scopes.h +++ b/deps/v8/src/scopes.h @@ -370,8 +370,8 @@ class Scope: public ZoneObject { int num_heap_slots_; // Serialized scopes support. - SerializedScopeInfo* scope_info_; - bool resolved() { return scope_info_ != NULL; } + Handle scope_info_; + bool resolved() { return !scope_info_.is_null(); } // Create a non-local variable with a given name. // These variables are looked up dynamically at runtime. @@ -406,7 +406,7 @@ class Scope: public ZoneObject { void AllocateVariablesRecursively(); private: - Scope(Scope* inner_scope, SerializedScopeInfo* scope_info); + Scope(Scope* inner_scope, Handle scope_info); void AddInnerScope(Scope* inner_scope) { if (inner_scope != NULL) { @@ -417,27 +417,7 @@ class Scope: public ZoneObject { void SetDefaults(Type type, Scope* outer_scope, - SerializedScopeInfo* scope_info) { - outer_scope_ = outer_scope; - type_ = type; - scope_name_ = Factory::empty_symbol(); - dynamics_ = NULL; - receiver_ = NULL; - function_ = NULL; - arguments_ = NULL; - arguments_shadow_ = NULL; - illegal_redecl_ = NULL; - scope_inside_with_ = false; - scope_contains_with_ = false; - scope_calls_eval_ = false; - outer_scope_calls_eval_ = false; - inner_scope_calls_eval_ = false; - outer_scope_is_eval_scope_ = false; - force_eager_compilation_ = false; - num_stack_slots_ = 0; - num_heap_slots_ = 0; - scope_info_ = scope_info; - } + Handle scope_info); }; diff --git a/deps/v8/src/version.cc b/deps/v8/src/version.cc index 7647f4e2f12..39328dcb7e5 100644 --- a/deps/v8/src/version.cc +++ b/deps/v8/src/version.cc @@ -35,7 +35,7 @@ #define MAJOR_VERSION 3 #define MINOR_VERSION 1 #define BUILD_NUMBER 8 -#define PATCH_LEVEL 8 +#define PATCH_LEVEL 10 #define CANDIDATE_VERSION false // Define SONAME to have the SCons build the put a specific SONAME into the diff --git a/deps/v8/src/x64/lithium-codegen-x64.cc b/deps/v8/src/x64/lithium-codegen-x64.cc index 5bc0275909a..48844a5bfec 100644 --- a/deps/v8/src/x64/lithium-codegen-x64.cc +++ b/deps/v8/src/x64/lithium-codegen-x64.cc @@ -429,14 +429,16 @@ void LCodeGen::AddToTranslation(Translation* translation, } -void LCodeGen::CallCode(Handle code, - RelocInfo::Mode mode, - LInstruction* instr) { +void LCodeGen::CallCodeGeneric(Handle code, + RelocInfo::Mode mode, + LInstruction* instr, + SafepointMode safepoint_mode, + int argc) { ASSERT(instr != NULL); LPointerMap* pointers = instr->pointer_map(); RecordPosition(pointers->position()); __ call(code, mode); - RegisterLazyDeoptimization(instr); + RegisterLazyDeoptimization(instr, safepoint_mode, argc); // Signal that we don't inline smi code before these stubs in the // optimizing code generator. @@ -447,6 +449,13 @@ void LCodeGen::CallCode(Handle code, } +void LCodeGen::CallCode(Handle code, + RelocInfo::Mode mode, + LInstruction* instr) { + CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT, 0); +} + + void LCodeGen::CallRuntime(Runtime::Function* function, int num_arguments, LInstruction* instr) { @@ -456,11 +465,23 @@ void LCodeGen::CallRuntime(Runtime::Function* function, RecordPosition(pointers->position()); __ CallRuntime(function, num_arguments); - RegisterLazyDeoptimization(instr); + RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT, 0); } -void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr) { +void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id, + int argc, + LInstruction* instr) { + __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); + __ CallRuntimeSaveDoubles(id); + RecordSafepointWithRegisters( + instr->pointer_map(), argc, Safepoint::kNoDeoptimizationIndex); +} + + +void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr, + SafepointMode safepoint_mode, + int argc) { // Create the environment to bailout to. If the call has side effects // execution has to continue after the call otherwise execution can continue // from a previous bailout point repeating the call. @@ -472,8 +493,17 @@ void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr) { } RegisterEnvironmentForDeoptimization(deoptimization_environment); - RecordSafepoint(instr->pointer_map(), - deoptimization_environment->deoptimization_index()); + if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) { + ASSERT(argc == 0); + RecordSafepoint(instr->pointer_map(), + deoptimization_environment->deoptimization_index()); + } else { + ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS); + RecordSafepointWithRegisters( + instr->pointer_map(), + argc, + deoptimization_environment->deoptimization_index()); + } } @@ -598,6 +628,8 @@ void LCodeGen::RecordSafepoint( Safepoint::Kind kind, int arguments, int deoptimization_index) { + ASSERT(kind == expected_safepoint_kind_); + const ZoneList* operands = pointers->operands(); Safepoint safepoint = safepoints_.DefineSafepoint(masm(), @@ -1260,11 +1292,8 @@ void LCodeGen::EmitGoto(int block, LDeferredCode* deferred_stack_check) { void LCodeGen::DoDeferredStackCheck(LGoto* instr) { - __ Pushad(); - __ CallRuntimeSaveDoubles(Runtime::kStackGuard); - RecordSafepointWithRegisters( - instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); - __ Popad(); + PushSafepointRegistersScope scope(this); + CallRuntimeFromDeferred(Runtime::kStackGuard, 0, instr); } @@ -1827,16 +1856,21 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { - __ PushSafepointRegisters(); + { + PushSafepointRegistersScope scope(this); - InstanceofStub stub(InstanceofStub::kNoFlags); + InstanceofStub stub(InstanceofStub::kNoFlags); - __ push(ToRegister(instr->InputAt(0))); - __ Push(instr->function()); - __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); - __ movq(kScratchRegister, rax); - __ PopSafepointRegisters(); + __ push(ToRegister(instr->InputAt(0))); + __ Push(instr->function()); + __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); + CallCodeGeneric(stub.GetCode(), + RelocInfo::CODE_TARGET, + instr, + RECORD_SAFEPOINT_WITH_REGISTERS, + 2); + __ movq(kScratchRegister, rax); + } __ testq(kScratchRegister, kScratchRegister); Label load_false; Label done; @@ -2292,7 +2326,7 @@ void LCodeGen::CallKnownFunction(Handle function, } // Setup deoptimization. - RegisterLazyDeoptimization(instr); + RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT, 0); // Restore context. __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); @@ -2317,7 +2351,7 @@ void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) { Register tmp2 = tmp.is(rcx) ? rdx : input_reg.is(rcx) ? rdx : rcx; // Preserve the value of all registers. - __ PushSafepointRegisters(); + PushSafepointRegistersScope scope(this); Label negative; __ movl(tmp, FieldOperand(input_reg, HeapNumber::kExponentOffset)); @@ -2338,9 +2372,7 @@ void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) { // Slow case: Call the runtime system to do the number allocation. __ bind(&slow); - __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); - RecordSafepointWithRegisters( - instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); + CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr); // Set the pointer to the new heap number in tmp. if (!tmp.is(rax)) { __ movq(tmp, rax); @@ -2357,7 +2389,6 @@ void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) { __ StoreToSafepointRegisterSlot(input_reg, tmp); __ bind(&done); - __ PopSafepointRegisters(); } @@ -2884,7 +2915,7 @@ void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) { // contained in the register pointer map. __ Set(result, 0); - __ PushSafepointRegisters(); + PushSafepointRegistersScope scope(this); __ push(string); // Push the index as a smi. This is safe because of the checks in // DoStringCharCodeAt above. @@ -2897,16 +2928,12 @@ void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) { __ Integer32ToSmi(index, index); __ push(index); } - __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); - __ CallRuntimeSaveDoubles(Runtime::kStringCharCodeAt); - RecordSafepointWithRegisters( - instr->pointer_map(), 2, Safepoint::kNoDeoptimizationIndex); + CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2, instr); if (FLAG_debug_code) { __ AbortIfNotSmi(rax); } __ SmiToInteger32(rax, rax); __ StoreToSafepointRegisterSlot(result, rax); - __ PopSafepointRegisters(); } @@ -2971,13 +2998,12 @@ void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) { Register reg = ToRegister(instr->result()); __ Move(reg, Smi::FromInt(0)); - __ PushSafepointRegisters(); - __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); - RecordSafepointWithRegisters( - instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); - // Ensure that value in rax survives popping registers. - __ movq(kScratchRegister, rax); - __ PopSafepointRegisters(); + { + PushSafepointRegistersScope scope(this); + CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr); + // Ensure that value in rax survives popping registers. + __ movq(kScratchRegister, rax); + } __ movq(reg, kScratchRegister); } diff --git a/deps/v8/src/x64/lithium-codegen-x64.h b/deps/v8/src/x64/lithium-codegen-x64.h index 420556a585d..88832faf793 100644 --- a/deps/v8/src/x64/lithium-codegen-x64.h +++ b/deps/v8/src/x64/lithium-codegen-x64.h @@ -60,7 +60,8 @@ class LCodeGen BASE_EMBEDDED { status_(UNUSED), deferred_(8), osr_pc_offset_(-1), - resolver_(this) { + resolver_(this), + expected_safepoint_kind_(Safepoint::kSimple) { PopulateDeoptimizationLiteralsWithInlinedFunctions(); } @@ -151,12 +152,26 @@ class LCodeGen BASE_EMBEDDED { bool GenerateJumpTable(); bool GenerateSafepointTable(); + enum SafepointMode { + RECORD_SIMPLE_SAFEPOINT, + RECORD_SAFEPOINT_WITH_REGISTERS + }; + + void CallCodeGeneric(Handle code, + RelocInfo::Mode mode, + LInstruction* instr, + SafepointMode safepoint_mode, + int argc); + + void CallCode(Handle code, RelocInfo::Mode mode, LInstruction* instr); + void CallRuntime(Runtime::Function* function, int num_arguments, LInstruction* instr); + void CallRuntime(Runtime::FunctionId id, int num_arguments, LInstruction* instr) { @@ -164,6 +179,11 @@ class LCodeGen BASE_EMBEDDED { CallRuntime(function, num_arguments, instr); } + void CallRuntimeFromDeferred(Runtime::FunctionId id, + int argc, + LInstruction* instr); + + // Generate a direct call to a known function. Expects the function // to be in edi. void CallKnownFunction(Handle function, @@ -172,7 +192,9 @@ class LCodeGen BASE_EMBEDDED { void LoadHeapObject(Register result, Handle object); - void RegisterLazyDeoptimization(LInstruction* instr); + void RegisterLazyDeoptimization(LInstruction* instr, + SafepointMode safepoint_mode, + int argc); void RegisterEnvironmentForDeoptimization(LEnvironment* environment); void DeoptimizeIf(Condition cc, LEnvironment* environment); @@ -268,6 +290,27 @@ class LCodeGen BASE_EMBEDDED { // Compiler from a set of parallel moves to a sequential list of moves. LGapResolver resolver_; + Safepoint::Kind expected_safepoint_kind_; + + class PushSafepointRegistersScope BASE_EMBEDDED { + public: + explicit PushSafepointRegistersScope(LCodeGen* codegen) + : codegen_(codegen) { + ASSERT(codegen_->expected_safepoint_kind_ == Safepoint::kSimple); + codegen_->masm_->PushSafepointRegisters(); + codegen_->expected_safepoint_kind_ = Safepoint::kWithRegisters; + } + + ~PushSafepointRegistersScope() { + ASSERT(codegen_->expected_safepoint_kind_ == Safepoint::kWithRegisters); + codegen_->masm_->PopSafepointRegisters(); + codegen_->expected_safepoint_kind_ = Safepoint::kSimple; + } + + private: + LCodeGen* codegen_; + }; + friend class LDeferredCode; friend class LEnvironment; friend class SafepointGenerator; diff --git a/deps/v8/src/x64/macro-assembler-x64.h b/deps/v8/src/x64/macro-assembler-x64.h index 4cf59c4e89c..9557940a9a7 100644 --- a/deps/v8/src/x64/macro-assembler-x64.h +++ b/deps/v8/src/x64/macro-assembler-x64.h @@ -976,6 +976,10 @@ class MacroAssembler: public Assembler { void set_allow_stub_calls(bool value) { allow_stub_calls_ = value; } bool allow_stub_calls() { return allow_stub_calls_; } + static int SafepointRegisterStackIndex(Register reg) { + return SafepointRegisterStackIndex(reg.code()); + } + private: // Order general registers are pushed by Pushad. // rax, rcx, rdx, rbx, rsi, rdi, r8, r9, r11, r12, r14. diff --git a/deps/v8/test/mjsunit/regress/regress-78270.js b/deps/v8/test/mjsunit/regress/regress-78270.js new file mode 100644 index 00000000000..b9ce286feb8 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-78270.js @@ -0,0 +1,37 @@ +// Copyright 2011 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. + +for (var i = 0; i < 10000; i++) { + try { + var object = { }; + function g(f0) { + var f0 = (object instanceof encodeURI)('foo'); + } + g(75); + } catch (g) { + } +} From d2298d225ca61cd5eb9b78b0a5e9c4b27b66d4aa Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Mon, 11 Apr 2011 16:48:18 -0700 Subject: [PATCH 03/19] Add documentation around module.exports and scope of global objects Closes GH-852. --- doc/api/globals.markdown | 11 +++++++++- doc/api/modules.markdown | 45 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/doc/api/globals.markdown b/doc/api/globals.markdown index 3a561a349ec..fb971cbb0ee 100644 --- a/doc/api/globals.markdown +++ b/doc/api/globals.markdown @@ -1,6 +1,7 @@ ## Global Objects -These object are available in the global scope and can be accessed from anywhere. +These object are available in all modules. Some of these objects aren't +actually in the global scope but in the module scope - this will be noted. ### global @@ -18,6 +19,8 @@ The process object. See the [process object](process.html#process) section. ### require() To require modules. See the [Modules](modules.html#modules) section. +`require` isn't actually a global but rather local to each module. + ### require.resolve() @@ -44,6 +47,8 @@ Example: running `node example.js` from `/Users/mjr` console.log(__filename); // /Users/mjr/example.js +`__filename` isn't actually a global but rather local to each module. + ### __dirname The dirname of the script being executed. @@ -53,6 +58,8 @@ Example: running `node example.js` from `/Users/mjr` console.log(__dirname); // /Users/mjr +`__dirname` isn't actually a global but rather local to each module. + ### module @@ -66,3 +73,5 @@ for more information. ### clearInterval(t) The timer functions are global variables. See the [timers](timers.html) section. + +`module` isn't actually a global but rather local to each module. diff --git a/doc/api/modules.markdown b/doc/api/modules.markdown index 68c36c02486..07ff31fe54d 100644 --- a/doc/api/modules.markdown +++ b/doc/api/modules.markdown @@ -139,6 +139,51 @@ Modules are cached after the first time they are loaded. This means (among other things) that every call to `require('foo')` will get exactly the same object returned, if it would resolve to the same file. +### module.exports + +The `exports` object is created by the Module system. Sometimes this is not +acceptable, many want their module to be an instance of some class. To do this +assign the desired export object to `module.exports`. For example suppose we +were making a module called `a.js` + + var EventEmitter = require('events').EventEmitter; + + module.exports = new EventEmitter(); + + // Do some work, and after some time emit + // the 'ready' event from the module itself. + setTimeout(function() { + module.exports.emit('ready'); + }, 1000); + +Then in another file we could do + + var a = require('./a'); + a.on('ready', function() { + console.log('module a is ready'); + }); + + +Note that assignment to `module.exports` must be done immediately. It cannot be +done in any callbacks. This does not work: + +x.js: + + setTimeout(function() { + module.exports = { a: "hello" }; + }, 0); + +y.js + + var x = require('./x'); + console.log(x.a); + + + + + + + ### All Together... To get the exact filename that will be loaded when `require()` is called, use From 752bbd6b426d4be9fc8a352c7bec0f89839828d7 Mon Sep 17 00:00:00 2001 From: Scott McWhirter Date: Sun, 27 Mar 2011 03:14:34 -0700 Subject: [PATCH 04/19] Add os.cpus() support for sunos --- src/platform.h | 10 +++++ src/platform_sunos.cc | 98 ++++++++++++++++++++++++++++++++++++++++++- wscript | 4 +- 3 files changed, 110 insertions(+), 2 deletions(-) diff --git a/src/platform.h b/src/platform.h index db2c32cadb7..3227a3d6662 100644 --- a/src/platform.h +++ b/src/platform.h @@ -23,6 +23,9 @@ #define NODE_PLATFORM_H_ #include +#ifdef __sun +#include +#endif namespace node { @@ -39,6 +42,13 @@ class Platform { static double GetTotalMemory(); static double GetUptime(); static int GetLoadAvg(v8::Local *loads); + static v8::Handle GetInterfaceAddresses(); + private: + static double GetUptimeImpl(); + static double prog_start_time; +#ifdef __sun + static v8::Handle data_named(kstat_named_t *); +#endif }; diff --git a/src/platform_sunos.cc b/src/platform_sunos.cc index dc9617e047b..d2020662d7b 100644 --- a/src/platform_sunos.cc +++ b/src/platform_sunos.cc @@ -27,6 +27,10 @@ #include /* getexecname() */ #include /* strncpy() */ +#include +#include +#include +#include #if (!defined(_LP64)) && (_FILE_OFFSET_BITS - 0 == 64) #define PROCFS_FILE_OFFSET_BITS_HACK 1 @@ -112,10 +116,102 @@ int Platform::GetExecutablePath(char* buffer, size_t* size) { int Platform::GetCPUInfo(Local *cpus) { - // http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/cmd/psrinfo/psrinfo.pl + HandleScope scope; + Local cpuinfo; + Local cputimes; + + kstat_ctl_t *kc; + kstat_t *ksp; + kstat_named_t *knp; + + kc = kstat_open(); + if ((kc = kstat_open()) == NULL) + throw "could not open kstat"; + + *cpus = Array::New(); + + int lookup_instance = 0; + while (ksp = kstat_lookup(kc, "cpu_info", lookup_instance, NULL)){ + cpuinfo = Object::New(); + cputimes = Object::New(); + + if (kstat_read(kc, ksp, NULL) == -1) { + /* + * It is deeply annoying, but some kstats can return errors + * under otherwise routine conditions. (ACPI is one + * offender; there are surely others.) To prevent these + * fouled kstats from completely ruining our day, we assign + * an "error" member to the return value that consists of + * the strerror(). + */ + cpuinfo->Set(String::New("error"), String::New(strerror(errno))); + } else { + knp = (kstat_named_t *) kstat_data_lookup(ksp, "clock_MHz"); + cpuinfo->Set(String::New("speed"), data_named(knp)); + knp = (kstat_named_t *) kstat_data_lookup(ksp, "brand"); + cpuinfo->Set(String::New("model"), data_named(knp)); + (*cpus)->Set(lookup_instance, cpuinfo); + } + + lookup_instance++; + } + + lookup_instance = 0; + while (ksp = kstat_lookup(kc, "cpu", lookup_instance, "sys")){ + cpuinfo = (*cpus)->Get(lookup_instance)->ToObject(); + cputimes = Object::New(); + + if (kstat_read(kc, ksp, NULL) == -1) { + cputimes->Set(String::New("error"), String::New(strerror(errno))); + } else { + knp = (kstat_named_t *) kstat_data_lookup(ksp, "cpu_ticks_kernel"); + cputimes->Set(String::New("system"), data_named(knp)); + knp = (kstat_named_t *) kstat_data_lookup(ksp, "cpu_ticks_user"); + cputimes->Set(String::New("user"), data_named(knp)); + knp = (kstat_named_t *) kstat_data_lookup(ksp, "cpu_ticks_idle"); + cputimes->Set(String::New("idle"), data_named(knp)); + knp = (kstat_named_t *) kstat_data_lookup(ksp, "intr"); + cputimes->Set(String::New("intr"), data_named(knp)); + + cpuinfo->Set(String::New("times"), cputimes); + } + + lookup_instance++; + } + + kstat_close(kc); + return 0; } +Handle Platform::data_named(kstat_named_t *knp) { + Handle val; + + switch (knp->data_type) { + case KSTAT_DATA_CHAR: + val = Number::New(knp->value.c[0]); + break; + case KSTAT_DATA_INT32: + val = Number::New(knp->value.i32); + break; + case KSTAT_DATA_UINT32: + val = Number::New(knp->value.ui32); + break; + case KSTAT_DATA_INT64: + val = Number::New(knp->value.i64); + break; + case KSTAT_DATA_UINT64: + val = Number::New(knp->value.ui64); + break; + case KSTAT_DATA_STRING: + val = String::New(KSTAT_NAMED_STR_PTR(knp)); + break; + default: + throw (String::New("unrecognized data type")); + } + + return (val); +} double Platform::GetFreeMemory() { return 0.0; diff --git a/wscript b/wscript index 7692e83f4ed..756b530cf8c 100644 --- a/wscript +++ b/wscript @@ -359,6 +359,8 @@ def configure(conf): conf.fatal("Cannot find socket library") if not conf.check(lib='nsl', uselib_store="NSL"): conf.fatal("Cannot find nsl library") + if not conf.check(lib='kstat', uselib_store="KSTAT"): + conf.fatal("Cannot find kstat library") conf.sub_config('deps/libeio') @@ -802,7 +804,7 @@ def build(bld): node = bld.new_task_gen("cxx", product_type) node.name = "node" node.target = "node" - node.uselib = 'RT EV OPENSSL CARES EXECINFO DL KVM SOCKET NSL UTIL OPROFILE' + node.uselib = 'RT EV OPENSSL CARES EXECINFO DL KVM SOCKET NSL KSTAT UTIL OPROFILE' node.add_objects = 'eio http_parser' if product_type_is_lib: node.install_path = '${LIBDIR}' From d953856d87f2b12740332940011f9fd0e2cb41a2 Mon Sep 17 00:00:00 2001 From: Scott McWhirter Date: Sun, 27 Mar 2011 04:31:55 -0700 Subject: [PATCH 05/19] Remove extra kstat_open --- src/platform_sunos.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/platform_sunos.cc b/src/platform_sunos.cc index d2020662d7b..ab5de74aa71 100644 --- a/src/platform_sunos.cc +++ b/src/platform_sunos.cc @@ -124,7 +124,6 @@ int Platform::GetCPUInfo(Local *cpus) { kstat_t *ksp; kstat_named_t *knp; - kc = kstat_open(); if ((kc = kstat_open()) == NULL) throw "could not open kstat"; From ca028f4b37d764533ecf59601af3c393d44cc446 Mon Sep 17 00:00:00 2001 From: koichik Date: Wed, 30 Mar 2011 22:06:41 +0900 Subject: [PATCH 06/19] Fix docs: There were 2 descriptions of 'request' event. --- doc/api/http.markdown | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/doc/api/http.markdown b/doc/api/http.markdown index cf1bd5d8c87..10a0f9d29b5 100644 --- a/doc/api/http.markdown +++ b/doc/api/http.markdown @@ -31,6 +31,8 @@ This is an `EventEmitter` with the following events: `function (request, response) { }` +Emitted each time there is request. Note that there may be multiple requests +per connection (in the case of keep-alive connections). `request` is an instance of `http.ServerRequest` and `response` is an instance of `http.ServerResponse` @@ -48,13 +50,6 @@ This is an `EventEmitter` with the following events: Emitted when the server closes. -### Event: 'request' - -`function (request, response) {}` - -Emitted each time there is request. Note that there may be multiple requests -per connection (in the case of keep-alive connections). - ### Event: 'checkContinue' `function (request, response) {}` From 682b66c0c1d8e04f6d589845047aa0b50fc80129 Mon Sep 17 00:00:00 2001 From: koichik Date: Wed, 30 Mar 2011 22:17:00 +0900 Subject: [PATCH 07/19] Auto completion of built-in debugger suggests prefix match rather than partial match. --- lib/_debugger.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/_debugger.js b/lib/_debugger.js index f155ca2e71c..859dc2c1af0 100644 --- a/lib/_debugger.js +++ b/lib/_debugger.js @@ -652,7 +652,7 @@ Interface.prototype.complete = function(line) { line = line.replace(/^\s*/, ''); for (var i = 0; i < commands.length; i++) { - if (commands[i].indexOf(line) >= 0) { + if (commands[i].indexOf(line) === 0) { matches.push(commands[i]); } } From 0f47f63746df1e059ff2d99f0ce0123582952213 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Mon, 11 Apr 2011 17:30:33 -0700 Subject: [PATCH 08/19] Fix doc - no setBodyEnocoding anymore Thanks Frederic. Closes GH-859. --- doc/api/http.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api/http.markdown b/doc/api/http.markdown index 10a0f9d29b5..500347dd7e2 100644 --- a/doc/api/http.markdown +++ b/doc/api/http.markdown @@ -136,7 +136,7 @@ Emitted when a piece of the message body is received. Example: A chunk of the body is given as the single argument. The transfer-encoding has been decoded. The body chunk is a string. The body encoding is set with -`request.setBodyEncoding()`. +`request.setEncoding()`. ### Event: 'end' From 83727a4c86e7e7fe1b698bb22b8ab2a7f119d67d Mon Sep 17 00:00:00 2001 From: Abe Fettig Date: Thu, 31 Mar 2011 17:02:14 -0400 Subject: [PATCH 09/19] Fix bug where http response.readable was never set to false Closes GH-867. --- lib/http.js | 1 + test/simple/test-http-response-readable.js | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 test/simple/test-http-response-readable.js diff --git a/lib/http.js b/lib/http.js index d10f58d9ed6..1e7512d5425 100644 --- a/lib/http.js +++ b/lib/http.js @@ -129,6 +129,7 @@ var parsers = new FreeList('parsers', 1000, function() { } if (!parser.incoming.upgrade) { // For upgraded connections, also emit this after parser.execute + parser.incoming.readable = false; parser.incoming.emit('end'); } }; diff --git a/test/simple/test-http-response-readable.js b/test/simple/test-http-response-readable.js new file mode 100644 index 00000000000..d0adfe364c7 --- /dev/null +++ b/test/simple/test-http-response-readable.js @@ -0,0 +1,19 @@ +var common = require('../common'); +var assert = require('assert'); +var http = require('http'); + +var testServer = new http.Server(function(req, res) { + res.writeHead(200); + res.end('Hello world'); +}); + +testServer.listen(common.PORT, function() { + http.get({ port: common.PORT }, function(res) { + assert.equal(res.readable, true, 'res.readable initially true'); + res.on('end', function() { + assert.equal(res.readable, false, 'res.readable set to false after end'); + testServer.close(); + }); + }); +}); + From 9b3b37e498dfed0181a58b278eb508e1b9cf0f33 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Tue, 12 Apr 2011 15:20:58 -0700 Subject: [PATCH 10/19] Add docs about Buffer._charsWritten Fixes GH-907. --- doc/api/buffers.markdown | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/api/buffers.markdown b/doc/api/buffers.markdown index 30c3f03d25f..ab746e4e17c 100644 --- a/doc/api/buffers.markdown +++ b/doc/api/buffers.markdown @@ -55,6 +55,10 @@ Example: write a utf8 string into a buffer, then print it len = buf.write('\u00bd + \u00bc = \u00be', 0); console.log(len + " bytes: " + buf.toString('utf8', 0, len)); +The number of characters written (which may be different than the number of +bytes written) is set in `Buffer._charsWritten` and will be overwritten the +next time `buf.write()` is called. + ### buffer.toString(encoding, start=0, end=buffer.length) From 81cbd42cf51902083148a575d3a52cae2851732b Mon Sep 17 00:00:00 2001 From: Jakub Lekstan Date: Thu, 31 Mar 2011 16:55:26 +0200 Subject: [PATCH 11/19] Fixes the circular reference in vm modules. Fixes the circular reference problem. Closes GH-822. --- src/node_script.cc | 1 + .../test-vm-create-context-circular-reference.js | 12 ++++++++++++ 2 files changed, 13 insertions(+) create mode 100644 test/simple/test-vm-create-context-circular-reference.js diff --git a/src/node_script.cc b/src/node_script.cc index 49446ccbb3b..ce7761d0c26 100644 --- a/src/node_script.cc +++ b/src/node_script.cc @@ -221,6 +221,7 @@ Handle WrappedScript::CreateContext(const Arguments& args) { for (uint32_t i = 0; i < keys->Length(); i++) { Handle key = keys->Get(Integer::New(i))->ToString(); Handle value = sandbox->Get(key); + if(value == sandbox) { value = context; } context->Set(key, value); } } diff --git a/test/simple/test-vm-create-context-circular-reference.js b/test/simple/test-vm-create-context-circular-reference.js new file mode 100644 index 00000000000..9e3311c13cb --- /dev/null +++ b/test/simple/test-vm-create-context-circular-reference.js @@ -0,0 +1,12 @@ +var common = require('../common'); +var assert = require('assert'); +var vm = require('vm'); + +var sbx = {}; +sbx.window = sbx; + +sbx = vm.createContext(sbx); + +sbx.test = 123; + +assert.equal(sbx.window.window.window.window.window.test, 123); \ No newline at end of file From af96447016a5a3811e703685bc4d46ecdbbcc032 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Wed, 13 Apr 2011 01:26:57 -0700 Subject: [PATCH 12/19] Modify text about buffer.write and partial chars Fixes GH-913. --- doc/api/buffers.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/api/buffers.markdown b/doc/api/buffers.markdown index ab746e4e17c..6438d672112 100644 --- a/doc/api/buffers.markdown +++ b/doc/api/buffers.markdown @@ -46,8 +46,8 @@ Allocates a new buffer containing the given `str`. Writes `string` to the buffer at `offset` using the given encoding. Returns number of octets written. If `buffer` did not contain enough space to fit -the entire string, it will write a partial amount of the string. In the case -of `'utf8'` encoding, the method will not write partial characters. +the entire string, it will write a partial amount of the string. +The method will not write partial characters. Example: write a utf8 string into a buffer, then print it From 301f53c2aa998fae3bd43d41b2730560a06d7601 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Geisendo=CC=88rfer?= Date: Tue, 5 Apr 2011 23:37:40 +0200 Subject: [PATCH 13/19] Allow omission of end option for range reads Problem: Sometimes it is useful to read a file from a certain position to it's end. The current implementation was already perfectly capable of this, but decided to throw an error when the user tried to omit the end option. The only way to do this, was to pass {end: Infinity}. Solution: Automatically assume {end: Infinity} when omitted, and remove the previous exception thrown. Also updated the docs. closes #801. --- doc/api/fs.markdown | 2 +- lib/fs.js | 11 ++++++----- test/simple/test-fs-read-stream.js | 24 ++++++++++++------------ 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/doc/api/fs.markdown b/doc/api/fs.markdown index 6d7cd783647..506883bbfe5 100644 --- a/doc/api/fs.markdown +++ b/doc/api/fs.markdown @@ -367,7 +367,7 @@ Returns a new ReadStream object (See `Readable Stream`). `options` can include `start` and `end` values to read a range of bytes from the file instead of the entire file. Both `start` and `end` are inclusive and -start at 0. When used, both the limits must be specified always. +start at 0. An example to read the last 10 bytes of a file which is 100 bytes long: diff --git a/lib/fs.js b/lib/fs.js index 0f2318d5845..ab169fb9abb 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -799,11 +799,12 @@ var ReadStream = fs.ReadStream = function(path, options) { if (this.encoding) this.setEncoding(this.encoding); - if (this.start !== undefined || this.end !== undefined) { - if (this.start === undefined || this.end === undefined) { - this.emit('error', new Error('Both start and end are needed ' + - 'for range streaming.')); - } else if (this.start > this.end) { + if (this.start !== undefined) { + if (this.end === undefined) { + this.end = Infinity; + } + + if (this.start > this.end) { this.emit('error', new Error('start must be <= end')); } else { this._firstRead = true; diff --git a/test/simple/test-fs-read-stream.js b/test/simple/test-fs-read-stream.js index 188c95d52db..5362389fde1 100644 --- a/test/simple/test-fs-read-stream.js +++ b/test/simple/test-fs-read-stream.js @@ -121,19 +121,19 @@ file4.addListener('end', function(data) { assert.equal(contentRead, 'yz'); }); -try { - fs.createReadStream(rangeFile, {start: 10, end: 2}); - assert.fail('Creating a ReadStream with incorrect range limits must throw.'); -} catch (e) { - assert.equal(e.message, 'start must be <= end'); -} +var file5 = fs.createReadStream(rangeFile, {bufferSize: 1, start: 1}); +file5.data = ''; +file5.addListener('data', function(data) { + file5.data += data.toString('utf-8'); +}); +file5.addListener('end', function() { + assert.equal(file5.data, 'yz\n'); +}); -try { - fs.createReadStream(rangeFile, {start: 2}); - assert.fail('Creating a ReadStream with a only one range limits must throw.'); -} catch (e) { - assert.equal(e.message, 'Both start and end are needed for range streaming.'); -} + +assert.throws(function() { + fs.createReadStream(rangeFile, {start: 10, end: 2}); +}, /start must be <= end/); var stream = fs.createReadStream(rangeFile, { start: 0, end: 0 }); stream.data = ''; From 9533e879f0d3cfaf5de90825813237b330e64ee5 Mon Sep 17 00:00:00 2001 From: koichik Date: Thu, 14 Apr 2011 01:17:18 +0900 Subject: [PATCH 14/19] Fix Buffer.write() with UCS-2 should not be write partial char closes #916. --- src/node_buffer.cc | 6 +++++- test/simple/test-buffer.js | 9 +++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index b46abe1e3d4..75bac2a2808 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -495,7 +495,7 @@ Handle Buffer::Ucs2Write(const Arguments &args) { size_t max_length = args[2]->IsUndefined() ? buffer->length_ - offset : args[2]->Uint32Value(); - max_length = MIN(buffer->length_ - offset, max_length); + max_length = MIN(buffer->length_ - offset, max_length) / 2; uint16_t* p = (uint16_t*)(buffer->data_ + offset); @@ -503,6 +503,10 @@ Handle Buffer::Ucs2Write(const Arguments &args) { 0, max_length, String::HINT_MANY_WRITES_EXPECTED); + + constructor_template->GetFunction()->Set(chars_written_sym, + Integer::New(written)); + return scope.Close(Integer::New(written * 2)); } diff --git a/test/simple/test-buffer.js b/test/simple/test-buffer.js index ac822b2b607..0edb64277be 100644 --- a/test/simple/test-buffer.js +++ b/test/simple/test-buffer.js @@ -256,6 +256,15 @@ console.error('f.length: %d (should be 12)', f.length); assert.deepEqual(f, new Buffer([63, 4, 64, 4, 56, 4, 50, 4, 53, 4, 66, 4])); assert.equal(f.toString('ucs2'), 'привет'); +var f = new Buffer([0, 0, 0, 0, 0]); +assert.equal(f.length, 5); +var size = f.write('あいうえお', 'ucs2'); +console.error('bytes written to buffer: %d (should be 4)', size); +console.error('chars written to buffer: %d (should be 2)', Buffer._charsWritten); +assert.equal(size, 4); +assert.equal(Buffer._charsWritten, 2); +assert.deepEqual(f, new Buffer([0x42, 0x30, 0x44, 0x30, 0x00])); + var arrayIsh = {0: 0, 1: 1, 2: 2, 3: 3, length: 4}; var g = new Buffer(arrayIsh); From 296ff04cdc9c680f35e71ddecea4dde9c7ae1c92 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Wed, 13 Apr 2011 12:49:11 -0700 Subject: [PATCH 15/19] Test to demonstrate #892 --- test/fixtures/GH-892-request.js | 48 +++++++++++++ test/simple/test-regress-GH-892.js | 105 +++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 test/fixtures/GH-892-request.js create mode 100644 test/simple/test-regress-GH-892.js diff --git a/test/fixtures/GH-892-request.js b/test/fixtures/GH-892-request.js new file mode 100644 index 00000000000..e205d05da6b --- /dev/null +++ b/test/fixtures/GH-892-request.js @@ -0,0 +1,48 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +// Called by test/simple/test-regress-GH-892.js + +var https = require('https'); +var fs = require('fs'); +var assert = require('assert'); + +var PORT = parseInt(process.argv[2]); +var bytesExpected = parseInt(process.argv[3]); + +var gotResponse = false; + +var options = { + method: 'POST', + port: PORT +}; + +var req = https.request(options, function(res) { + assert.equal(200, res.statusCode); + gotResponse = true; + console.error("DONE"); +}); + +req.end(new Buffer(bytesExpected)); + +process.on('exit', function() { + assert.ok(gotResponse); +}); diff --git a/test/simple/test-regress-GH-892.js b/test/simple/test-regress-GH-892.js new file mode 100644 index 00000000000..be1b07b7a25 --- /dev/null +++ b/test/simple/test-regress-GH-892.js @@ -0,0 +1,105 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +// Uploading a big file via HTTPS causes node to drop out of the event loop. +// https://github.com/joyent/node/issues/892 +// In this test we set up an HTTPS in this process and launch a subprocess +// to POST a 32mb file to us. A bug in the pause/resume functionality of the +// TLS server causes the child process to exit cleanly before having sent +// the entire buffer. +var common = require('../common'); +var assert = require('assert'); +var spawn = require('child_process').spawn; +var https = require('https'); +var fs = require('fs'); + +var PORT = 8000 + + +var bytesExpected = 1024 * 1024 * 32; +var gotResponse = false; + +var started = false; + +var childScript = require('path').join(common.fixturesDir, 'GH-892-request.js'); + +function makeRequest() { + if (started) return; + started = true; + + var stderrBuffer = ''; + + var child = spawn(process.execPath, + [ childScript, common.PORT, bytesExpected ]); + + child.on('exit', function(code) { + assert.ok(/DONE/.test(stderrBuffer)); + assert.equal(0, code); + }); + + // The following two lines forward the stdio from the child + // to parent process for debugging. + child.stderr.pipe(process.stderr); + child.stdout.pipe(process.stdout); + + + // Buffer the stderr so that we can check that it got 'DONE' + child.stderr.setEncoding('ascii'); + child.stderr.on('data', function(d) { + stderrBuffer += d; + }); +} + + +var serverOptions = { + key: fs.readFileSync(common.fixturesDir + '/keys/agent1-key.pem'), + cert: fs.readFileSync(common.fixturesDir + '/keys/agent1-cert.pem') +}; + +var uploadCount = 0; + +var server = https.Server(serverOptions, function(req, res) { + // Close the server immediately. This test is only doing a single upload. + // We need to make sure the server isn't keeping the event loop alive + // while the upload is in progress. + server.close(); + + req.on('data', function(d) { + process.stderr.write('.'); + uploadCount += d.length; + }); + + req.on('end', function() { + assert.equal(bytesExpected, uploadCount); + res.writeHead(200, {'content-type': 'text/plain'}); + res.end('successful upload\n'); + }); +}); + +server.listen(common.PORT, function() { + console.log("expecting %d bytes", bytesExpected); + makeRequest(); +}); + +process.on('exit', function() { + console.error("got %d bytes", uploadCount); + assert.equal(uploadCount, bytesExpected); +}); From e8cf98c841c8aa80975fa2bd96187f49a6cbb760 Mon Sep 17 00:00:00 2001 From: Scott McWhirter Date: Sun, 27 Mar 2011 03:14:34 -0700 Subject: [PATCH 16/19] Add os.cpus() and os.uptime() support for sunos --- src/platform.h | 6 -- src/platform_sunos.cc | 177 ++++++++++++++++++++++++----------------- test/simple/test-os.js | 34 ++++++-- 3 files changed, 129 insertions(+), 88 deletions(-) diff --git a/src/platform.h b/src/platform.h index 3227a3d6662..5aad8e5e2cc 100644 --- a/src/platform.h +++ b/src/platform.h @@ -43,12 +43,6 @@ class Platform { static double GetUptime(); static int GetLoadAvg(v8::Local *loads); static v8::Handle GetInterfaceAddresses(); - private: - static double GetUptimeImpl(); - static double prog_start_time; -#ifdef __sun - static v8::Handle data_named(kstat_named_t *); -#endif }; diff --git a/src/platform_sunos.cc b/src/platform_sunos.cc index ab5de74aa71..236d912a79b 100644 --- a/src/platform_sunos.cc +++ b/src/platform_sunos.cc @@ -50,6 +50,7 @@ namespace node { using namespace v8; + char** Platform::SetupArgs(int argc, char *argv[]) { return argv; } @@ -112,78 +113,7 @@ int Platform::GetExecutablePath(char* buffer, size_t* size) { } -// TODO: libkstat provides all this info. Need to link it though. - - -int Platform::GetCPUInfo(Local *cpus) { - HandleScope scope; - Local cpuinfo; - Local cputimes; - - kstat_ctl_t *kc; - kstat_t *ksp; - kstat_named_t *knp; - - if ((kc = kstat_open()) == NULL) - throw "could not open kstat"; - - *cpus = Array::New(); - - int lookup_instance = 0; - while (ksp = kstat_lookup(kc, "cpu_info", lookup_instance, NULL)){ - cpuinfo = Object::New(); - cputimes = Object::New(); - - if (kstat_read(kc, ksp, NULL) == -1) { - /* - * It is deeply annoying, but some kstats can return errors - * under otherwise routine conditions. (ACPI is one - * offender; there are surely others.) To prevent these - * fouled kstats from completely ruining our day, we assign - * an "error" member to the return value that consists of - * the strerror(). - */ - cpuinfo->Set(String::New("error"), String::New(strerror(errno))); - } else { - knp = (kstat_named_t *) kstat_data_lookup(ksp, "clock_MHz"); - cpuinfo->Set(String::New("speed"), data_named(knp)); - knp = (kstat_named_t *) kstat_data_lookup(ksp, "brand"); - cpuinfo->Set(String::New("model"), data_named(knp)); - (*cpus)->Set(lookup_instance, cpuinfo); - } - - lookup_instance++; - } - - lookup_instance = 0; - while (ksp = kstat_lookup(kc, "cpu", lookup_instance, "sys")){ - cpuinfo = (*cpus)->Get(lookup_instance)->ToObject(); - cputimes = Object::New(); - - if (kstat_read(kc, ksp, NULL) == -1) { - cputimes->Set(String::New("error"), String::New(strerror(errno))); - } else { - knp = (kstat_named_t *) kstat_data_lookup(ksp, "cpu_ticks_kernel"); - cputimes->Set(String::New("system"), data_named(knp)); - knp = (kstat_named_t *) kstat_data_lookup(ksp, "cpu_ticks_user"); - cputimes->Set(String::New("user"), data_named(knp)); - knp = (kstat_named_t *) kstat_data_lookup(ksp, "cpu_ticks_idle"); - cputimes->Set(String::New("idle"), data_named(knp)); - knp = (kstat_named_t *) kstat_data_lookup(ksp, "intr"); - cputimes->Set(String::New("intr"), data_named(knp)); - - cpuinfo->Set(String::New("times"), cputimes); - } - - lookup_instance++; - } - - kstat_close(kc); - - return 0; -} - -Handle Platform::data_named(kstat_named_t *knp) { +static Handle data_named(kstat_named_t *knp) { Handle val; switch (knp->data_type) { @@ -212,6 +142,78 @@ Handle Platform::data_named(kstat_named_t *knp) { return (val); } + +int Platform::GetCPUInfo(Local *cpus) { + HandleScope scope; + Local cpuinfo; + Local cputimes; + + int lookup_instance; + kstat_ctl_t *kc; + kstat_t *ksp; + kstat_named_t *knp; + + if ((kc = kstat_open()) == NULL) + throw "could not open kstat"; + + *cpus = Array::New(); + + lookup_instance = 0; + while (ksp = kstat_lookup(kc, "cpu_info", lookup_instance, NULL)) { + cpuinfo = Object::New(); + + if (kstat_read(kc, ksp, NULL) == -1) { + /* + * It is deeply annoying, but some kstats can return errors + * under otherwise routine conditions. (ACPI is one + * offender; there are surely others.) To prevent these + * fouled kstats from completely ruining our day, we assign + * an "error" member to the return value that consists of + * the strerror(). + */ + cpuinfo->Set(String::New("error"), String::New(strerror(errno))); + (*cpus)->Set(lookup_instance, cpuinfo); + } else { + knp = (kstat_named_t *) kstat_data_lookup(ksp, "clock_MHz"); + cpuinfo->Set(String::New("speed"), data_named(knp)); + knp = (kstat_named_t *) kstat_data_lookup(ksp, "brand"); + cpuinfo->Set(String::New("model"), data_named(knp)); + (*cpus)->Set(lookup_instance, cpuinfo); + } + + lookup_instance++; + } + + lookup_instance = 0; + while (ksp = kstat_lookup(kc, "cpu", lookup_instance, "sys")){ + cpuinfo = (*cpus)->Get(lookup_instance)->ToObject(); + cputimes = Object::New(); + + if (kstat_read(kc, ksp, NULL) == -1) { + cputimes->Set(String::New("error"), String::New(strerror(errno))); + cpuinfo->Set(String::New("times"), cpuinfo); + } else { + knp = (kstat_named_t *) kstat_data_lookup(ksp, "cpu_ticks_kernel"); + cputimes->Set(String::New("system"), data_named(knp)); + knp = (kstat_named_t *) kstat_data_lookup(ksp, "cpu_ticks_user"); + cputimes->Set(String::New("user"), data_named(knp)); + knp = (kstat_named_t *) kstat_data_lookup(ksp, "cpu_ticks_idle"); + cputimes->Set(String::New("idle"), data_named(knp)); + knp = (kstat_named_t *) kstat_data_lookup(ksp, "intr"); + cputimes->Set(String::New("irq"), data_named(knp)); + + cpuinfo->Set(String::New("times"), cputimes); + } + + lookup_instance++; + } + + kstat_close(kc); + + return 0; +} + + double Platform::GetFreeMemory() { return 0.0; } @@ -223,8 +225,29 @@ double Platform::GetTotalMemory() { double Platform::GetUptime() { - // http://munin-monitoring.org/attachment/ticket/419/uptime - return 0.0; + kstat_ctl_t *kc; + kstat_t *ksp; + kstat_named_t *knp; + + long hz = sysconf(_SC_CLK_TCK); + ulong_t clk_intr; + + if ((kc = kstat_open()) == NULL) { + throw "could not open kstat"; + } + + ksp = kstat_lookup(kc, "unix", 0, "system_misc"); + + if (kstat_read(kc, ksp, NULL) == -1) { + throw "unable to read kstat"; + } else { + knp = (kstat_named_t *) kstat_data_lookup(ksp, "clk_intr"); + clk_intr = knp->value.ul; + } + + kstat_close(kc); + + return static_cast(clk_intr / hz); } @@ -233,5 +256,11 @@ int Platform::GetLoadAvg(Local *loads) { } +Handle Platform::GetInterfaceAddresses() { + HandleScope scope; + return scope.Close(Object::New()); +} + + } // namespace node diff --git a/test/simple/test-os.js b/test/simple/test-os.js index 5903f8f6b18..54961fb58ef 100644 --- a/test/simple/test-os.js +++ b/test/simple/test-os.js @@ -23,11 +23,29 @@ var common = require('../common'); var assert = require('assert'); var os = require('os'); -assert.ok(os.hostname().length > 0); -assert.ok(os.loadavg().length > 0); -assert.ok(os.uptime() > 0); -assert.ok(os.freemem() > 0); -assert.ok(os.totalmem() > 0); -assert.ok(os.cpus().length > 0); -assert.ok(os.type().length > 0); -assert.ok(os.release().length > 0); \ No newline at end of file +var hostname = os.hostname() +console.log("hostname = %s", hostname); +assert.ok(hostname.length > 0); + +var uptime = os.uptime(); +console.log("uptime = %d", uptime); +assert.ok(uptime > 0); + +var cpus = os.cpus(); +console.log("cpus = ", cpus); +assert.ok(cpus.length > 0); + +var type = os.type(); +console.log("type = ", type); +assert.ok(type.length > 0); + +var release = os.release(); +console.log("release = ", release); +assert.ok(release > 0); + +if (process.platform != 'sunos') { + // not implemeneted yet + assert.ok(os.loadavg().length > 0); + assert.ok(os.freemem() > 0); + assert.ok(os.totalmem() > 0); +} From 2f984515619d7c303aa484dee7e243b454b663f6 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Wed, 13 Apr 2011 17:30:12 -0700 Subject: [PATCH 17/19] Revert "Add os.cpus() and os.uptime() support for sunos" Cherry-pick fail. Breaks linux. Will land again shortly. This reverts commit e8cf98c841c8aa80975fa2bd96187f49a6cbb760. This reverts commit d953856d87f2b12740332940011f9fd0e2cb41a2. This reverts commit 752bbd6b426d4be9fc8a352c7bec0f89839828d7. --- src/platform.h | 4 -- src/platform_sunos.cc | 132 ++--------------------------------------- test/simple/test-os.js | 34 +++-------- wscript | 4 +- 4 files changed, 13 insertions(+), 161 deletions(-) diff --git a/src/platform.h b/src/platform.h index 5aad8e5e2cc..db2c32cadb7 100644 --- a/src/platform.h +++ b/src/platform.h @@ -23,9 +23,6 @@ #define NODE_PLATFORM_H_ #include -#ifdef __sun -#include -#endif namespace node { @@ -42,7 +39,6 @@ class Platform { static double GetTotalMemory(); static double GetUptime(); static int GetLoadAvg(v8::Local *loads); - static v8::Handle GetInterfaceAddresses(); }; diff --git a/src/platform_sunos.cc b/src/platform_sunos.cc index 236d912a79b..dc9617e047b 100644 --- a/src/platform_sunos.cc +++ b/src/platform_sunos.cc @@ -27,10 +27,6 @@ #include /* getexecname() */ #include /* strncpy() */ -#include -#include -#include -#include #if (!defined(_LP64)) && (_FILE_OFFSET_BITS - 0 == 64) #define PROCFS_FILE_OFFSET_BITS_HACK 1 @@ -50,7 +46,6 @@ namespace node { using namespace v8; - char** Platform::SetupArgs(int argc, char *argv[]) { return argv; } @@ -113,103 +108,11 @@ int Platform::GetExecutablePath(char* buffer, size_t* size) { } -static Handle data_named(kstat_named_t *knp) { - Handle val; - - switch (knp->data_type) { - case KSTAT_DATA_CHAR: - val = Number::New(knp->value.c[0]); - break; - case KSTAT_DATA_INT32: - val = Number::New(knp->value.i32); - break; - case KSTAT_DATA_UINT32: - val = Number::New(knp->value.ui32); - break; - case KSTAT_DATA_INT64: - val = Number::New(knp->value.i64); - break; - case KSTAT_DATA_UINT64: - val = Number::New(knp->value.ui64); - break; - case KSTAT_DATA_STRING: - val = String::New(KSTAT_NAMED_STR_PTR(knp)); - break; - default: - throw (String::New("unrecognized data type")); - } - - return (val); -} +// TODO: libkstat provides all this info. Need to link it though. int Platform::GetCPUInfo(Local *cpus) { - HandleScope scope; - Local cpuinfo; - Local cputimes; - - int lookup_instance; - kstat_ctl_t *kc; - kstat_t *ksp; - kstat_named_t *knp; - - if ((kc = kstat_open()) == NULL) - throw "could not open kstat"; - - *cpus = Array::New(); - - lookup_instance = 0; - while (ksp = kstat_lookup(kc, "cpu_info", lookup_instance, NULL)) { - cpuinfo = Object::New(); - - if (kstat_read(kc, ksp, NULL) == -1) { - /* - * It is deeply annoying, but some kstats can return errors - * under otherwise routine conditions. (ACPI is one - * offender; there are surely others.) To prevent these - * fouled kstats from completely ruining our day, we assign - * an "error" member to the return value that consists of - * the strerror(). - */ - cpuinfo->Set(String::New("error"), String::New(strerror(errno))); - (*cpus)->Set(lookup_instance, cpuinfo); - } else { - knp = (kstat_named_t *) kstat_data_lookup(ksp, "clock_MHz"); - cpuinfo->Set(String::New("speed"), data_named(knp)); - knp = (kstat_named_t *) kstat_data_lookup(ksp, "brand"); - cpuinfo->Set(String::New("model"), data_named(knp)); - (*cpus)->Set(lookup_instance, cpuinfo); - } - - lookup_instance++; - } - - lookup_instance = 0; - while (ksp = kstat_lookup(kc, "cpu", lookup_instance, "sys")){ - cpuinfo = (*cpus)->Get(lookup_instance)->ToObject(); - cputimes = Object::New(); - - if (kstat_read(kc, ksp, NULL) == -1) { - cputimes->Set(String::New("error"), String::New(strerror(errno))); - cpuinfo->Set(String::New("times"), cpuinfo); - } else { - knp = (kstat_named_t *) kstat_data_lookup(ksp, "cpu_ticks_kernel"); - cputimes->Set(String::New("system"), data_named(knp)); - knp = (kstat_named_t *) kstat_data_lookup(ksp, "cpu_ticks_user"); - cputimes->Set(String::New("user"), data_named(knp)); - knp = (kstat_named_t *) kstat_data_lookup(ksp, "cpu_ticks_idle"); - cputimes->Set(String::New("idle"), data_named(knp)); - knp = (kstat_named_t *) kstat_data_lookup(ksp, "intr"); - cputimes->Set(String::New("irq"), data_named(knp)); - - cpuinfo->Set(String::New("times"), cputimes); - } - - lookup_instance++; - } - - kstat_close(kc); - + // http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/cmd/psrinfo/psrinfo.pl return 0; } @@ -225,29 +128,8 @@ double Platform::GetTotalMemory() { double Platform::GetUptime() { - kstat_ctl_t *kc; - kstat_t *ksp; - kstat_named_t *knp; - - long hz = sysconf(_SC_CLK_TCK); - ulong_t clk_intr; - - if ((kc = kstat_open()) == NULL) { - throw "could not open kstat"; - } - - ksp = kstat_lookup(kc, "unix", 0, "system_misc"); - - if (kstat_read(kc, ksp, NULL) == -1) { - throw "unable to read kstat"; - } else { - knp = (kstat_named_t *) kstat_data_lookup(ksp, "clk_intr"); - clk_intr = knp->value.ul; - } - - kstat_close(kc); - - return static_cast(clk_intr / hz); + // http://munin-monitoring.org/attachment/ticket/419/uptime + return 0.0; } @@ -256,11 +138,5 @@ int Platform::GetLoadAvg(Local *loads) { } -Handle Platform::GetInterfaceAddresses() { - HandleScope scope; - return scope.Close(Object::New()); -} - - } // namespace node diff --git a/test/simple/test-os.js b/test/simple/test-os.js index 54961fb58ef..5903f8f6b18 100644 --- a/test/simple/test-os.js +++ b/test/simple/test-os.js @@ -23,29 +23,11 @@ var common = require('../common'); var assert = require('assert'); var os = require('os'); -var hostname = os.hostname() -console.log("hostname = %s", hostname); -assert.ok(hostname.length > 0); - -var uptime = os.uptime(); -console.log("uptime = %d", uptime); -assert.ok(uptime > 0); - -var cpus = os.cpus(); -console.log("cpus = ", cpus); -assert.ok(cpus.length > 0); - -var type = os.type(); -console.log("type = ", type); -assert.ok(type.length > 0); - -var release = os.release(); -console.log("release = ", release); -assert.ok(release > 0); - -if (process.platform != 'sunos') { - // not implemeneted yet - assert.ok(os.loadavg().length > 0); - assert.ok(os.freemem() > 0); - assert.ok(os.totalmem() > 0); -} +assert.ok(os.hostname().length > 0); +assert.ok(os.loadavg().length > 0); +assert.ok(os.uptime() > 0); +assert.ok(os.freemem() > 0); +assert.ok(os.totalmem() > 0); +assert.ok(os.cpus().length > 0); +assert.ok(os.type().length > 0); +assert.ok(os.release().length > 0); \ No newline at end of file diff --git a/wscript b/wscript index 756b530cf8c..7692e83f4ed 100644 --- a/wscript +++ b/wscript @@ -359,8 +359,6 @@ def configure(conf): conf.fatal("Cannot find socket library") if not conf.check(lib='nsl', uselib_store="NSL"): conf.fatal("Cannot find nsl library") - if not conf.check(lib='kstat', uselib_store="KSTAT"): - conf.fatal("Cannot find kstat library") conf.sub_config('deps/libeio') @@ -804,7 +802,7 @@ def build(bld): node = bld.new_task_gen("cxx", product_type) node.name = "node" node.target = "node" - node.uselib = 'RT EV OPENSSL CARES EXECINFO DL KVM SOCKET NSL KSTAT UTIL OPROFILE' + node.uselib = 'RT EV OPENSSL CARES EXECINFO DL KVM SOCKET NSL UTIL OPROFILE' node.add_objects = 'eio http_parser' if product_type_is_lib: node.install_path = '${LIBDIR}' From 90348a616d36922f87fac3c47fa026651c0fbbd8 Mon Sep 17 00:00:00 2001 From: Scott McWhirter Date: Sun, 27 Mar 2011 03:14:34 -0700 Subject: [PATCH 18/19] Add os.cpus() and os.uptime() support for sunos --- src/platform_sunos.cc | 127 +++++++++++++++++++++++++++++++++++++++-- test/simple/test-os.js | 34 ++++++++--- wscript | 4 +- 3 files changed, 150 insertions(+), 15 deletions(-) diff --git a/src/platform_sunos.cc b/src/platform_sunos.cc index dc9617e047b..002b373a5a7 100644 --- a/src/platform_sunos.cc +++ b/src/platform_sunos.cc @@ -27,6 +27,10 @@ #include /* getexecname() */ #include /* strncpy() */ +#include +#include +#include +#include #if (!defined(_LP64)) && (_FILE_OFFSET_BITS - 0 == 64) #define PROCFS_FILE_OFFSET_BITS_HACK 1 @@ -46,6 +50,7 @@ namespace node { using namespace v8; + char** Platform::SetupArgs(int argc, char *argv[]) { return argv; } @@ -108,11 +113,103 @@ int Platform::GetExecutablePath(char* buffer, size_t* size) { } -// TODO: libkstat provides all this info. Need to link it though. +static Handle data_named(kstat_named_t *knp) { + Handle val; + + switch (knp->data_type) { + case KSTAT_DATA_CHAR: + val = Number::New(knp->value.c[0]); + break; + case KSTAT_DATA_INT32: + val = Number::New(knp->value.i32); + break; + case KSTAT_DATA_UINT32: + val = Number::New(knp->value.ui32); + break; + case KSTAT_DATA_INT64: + val = Number::New(knp->value.i64); + break; + case KSTAT_DATA_UINT64: + val = Number::New(knp->value.ui64); + break; + case KSTAT_DATA_STRING: + val = String::New(KSTAT_NAMED_STR_PTR(knp)); + break; + default: + throw (String::New("unrecognized data type")); + } + + return (val); +} int Platform::GetCPUInfo(Local *cpus) { - // http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/cmd/psrinfo/psrinfo.pl + HandleScope scope; + Local cpuinfo; + Local cputimes; + + int lookup_instance; + kstat_ctl_t *kc; + kstat_t *ksp; + kstat_named_t *knp; + + if ((kc = kstat_open()) == NULL) + throw "could not open kstat"; + + *cpus = Array::New(); + + lookup_instance = 0; + while (ksp = kstat_lookup(kc, "cpu_info", lookup_instance, NULL)){ + cpuinfo = Object::New(); + + if (kstat_read(kc, ksp, NULL) == -1) { + /* + * It is deeply annoying, but some kstats can return errors + * under otherwise routine conditions. (ACPI is one + * offender; there are surely others.) To prevent these + * fouled kstats from completely ruining our day, we assign + * an "error" member to the return value that consists of + * the strerror(). + */ + cpuinfo->Set(String::New("error"), String::New(strerror(errno))); + (*cpus)->Set(lookup_instance, cpuinfo); + } else { + knp = (kstat_named_t *) kstat_data_lookup(ksp, "clock_MHz"); + cpuinfo->Set(String::New("speed"), data_named(knp)); + knp = (kstat_named_t *) kstat_data_lookup(ksp, "brand"); + cpuinfo->Set(String::New("model"), data_named(knp)); + (*cpus)->Set(lookup_instance, cpuinfo); + } + + lookup_instance++; + } + + lookup_instance = 0; + while (ksp = kstat_lookup(kc, "cpu", lookup_instance, "sys")){ + cpuinfo = (*cpus)->Get(lookup_instance)->ToObject(); + cputimes = Object::New(); + + if (kstat_read(kc, ksp, NULL) == -1) { + cputimes->Set(String::New("error"), String::New(strerror(errno))); + cpuinfo->Set(String::New("times"), cpuinfo); + } else { + knp = (kstat_named_t *) kstat_data_lookup(ksp, "cpu_ticks_kernel"); + cputimes->Set(String::New("system"), data_named(knp)); + knp = (kstat_named_t *) kstat_data_lookup(ksp, "cpu_ticks_user"); + cputimes->Set(String::New("user"), data_named(knp)); + knp = (kstat_named_t *) kstat_data_lookup(ksp, "cpu_ticks_idle"); + cputimes->Set(String::New("idle"), data_named(knp)); + knp = (kstat_named_t *) kstat_data_lookup(ksp, "intr"); + cputimes->Set(String::New("irq"), data_named(knp)); + + cpuinfo->Set(String::New("times"), cputimes); + } + + lookup_instance++; + } + + kstat_close(kc); + return 0; } @@ -126,12 +223,30 @@ double Platform::GetTotalMemory() { return 0.0; } - double Platform::GetUptime() { - // http://munin-monitoring.org/attachment/ticket/419/uptime - return 0.0; -} + kstat_ctl_t *kc; + kstat_t *ksp; + kstat_named_t *knp; + long hz = sysconf(_SC_CLK_TCK); + ulong_t clk_intr; + + if ((kc = kstat_open()) == NULL) + throw "could not open kstat"; + + ksp = kstat_lookup(kc, "unix", 0, "system_misc"); + + if (kstat_read(kc, ksp, NULL) == -1) { + throw "unable to read kstat"; + } else { + knp = (kstat_named_t *) kstat_data_lookup(ksp, "clk_intr"); + clk_intr = knp->value.ul; + } + + kstat_close(kc); + + return static_cast( clk_intr / hz ); +} int Platform::GetLoadAvg(Local *loads) { return 0; diff --git a/test/simple/test-os.js b/test/simple/test-os.js index 5903f8f6b18..b43d3391398 100644 --- a/test/simple/test-os.js +++ b/test/simple/test-os.js @@ -23,11 +23,29 @@ var common = require('../common'); var assert = require('assert'); var os = require('os'); -assert.ok(os.hostname().length > 0); -assert.ok(os.loadavg().length > 0); -assert.ok(os.uptime() > 0); -assert.ok(os.freemem() > 0); -assert.ok(os.totalmem() > 0); -assert.ok(os.cpus().length > 0); -assert.ok(os.type().length > 0); -assert.ok(os.release().length > 0); \ No newline at end of file +var hostname = os.hostname() +console.log("hostname = %s", hostname); +assert.ok(hostname.length > 0); + +var uptime = os.uptime(); +console.log("uptime = %d", uptime); +assert.ok(uptime > 0); + +var cpus = os.cpus(); +console.log("cpus = ", cpus); +assert.ok(cpus.length > 0); + +var type = os.type(); +console.log("type = ", type); +assert.ok(type.length > 0); + +var release = os.release(); +console.log("release = ", release); +assert.ok(release.length > 0); + +if (process.platform != 'sunos') { + // not implemeneted yet + assert.ok(os.loadavg().length > 0); + assert.ok(os.freemem() > 0); + assert.ok(os.totalmem() > 0); +} diff --git a/wscript b/wscript index 7692e83f4ed..756b530cf8c 100644 --- a/wscript +++ b/wscript @@ -359,6 +359,8 @@ def configure(conf): conf.fatal("Cannot find socket library") if not conf.check(lib='nsl', uselib_store="NSL"): conf.fatal("Cannot find nsl library") + if not conf.check(lib='kstat', uselib_store="KSTAT"): + conf.fatal("Cannot find kstat library") conf.sub_config('deps/libeio') @@ -802,7 +804,7 @@ def build(bld): node = bld.new_task_gen("cxx", product_type) node.name = "node" node.target = "node" - node.uselib = 'RT EV OPENSSL CARES EXECINFO DL KVM SOCKET NSL UTIL OPROFILE' + node.uselib = 'RT EV OPENSSL CARES EXECINFO DL KVM SOCKET NSL KSTAT UTIL OPROFILE' node.add_objects = 'eio http_parser' if product_type_is_lib: node.install_path = '${LIBDIR}' From d0e84b0088a865ed59afd4854b40a3eaf864928b Mon Sep 17 00:00:00 2001 From: Theo Schlossnagle Date: Sat, 2 Apr 2011 00:53:07 -0400 Subject: [PATCH 19/19] Pass secureProtocol through on tls.Server creation The secureProtocol option to building the SSL context was not being properly passed through in the credentials in the tls code. This is fixed. --- lib/tls.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/tls.js b/lib/tls.js index 96af640b5d4..547e9395c68 100644 --- a/lib/tls.js +++ b/lib/tls.js @@ -723,6 +723,7 @@ function Server(/* [options], listener */) { key: self.key, cert: self.cert, ca: self.ca, + secureProtocol: self.secureProtocol, crl: self.crl }); //creds.context.setCiphers('RC4-SHA:AES128-SHA:AES256-SHA'); @@ -792,6 +793,7 @@ Server.prototype.setOptions = function(options) { if (options.key) this.key = options.key; if (options.cert) this.cert = options.cert; if (options.ca) this.ca = options.ca; + if (options.secureProtocol) this.secureProtocol = options.secureProtocol; if (options.crl) this.crl = options.crl; };