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) { + } +} diff --git a/doc/api/buffers.markdown b/doc/api/buffers.markdown index abff9834d87..88d59b20fbe 100644 --- a/doc/api/buffers.markdown +++ b/doc/api/buffers.markdown @@ -48,8 +48,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 @@ -57,6 +57,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) diff --git a/doc/api/fs.markdown b/doc/api/fs.markdown index 13d6964287a..a092aa2b3c9 100644 --- a/doc/api/fs.markdown +++ b/doc/api/fs.markdown @@ -379,7 +379,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/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/http.markdown b/doc/api/http.markdown index cf1bd5d8c87..500347dd7e2 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) {}` @@ -141,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' 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 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]); } } diff --git a/lib/fs.js b/lib/fs.js index efcc7a8431a..89dc2142b3e 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -838,11 +838,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/lib/http.js b/lib/http.js index 4bbe124f109..a4447289a34 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'); } }; @@ -1185,7 +1186,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 da7dcc83bfb..52aaefa4d64 100644 --- a/lib/net.js +++ b/lib/net.js @@ -847,7 +847,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/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; }; diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 8a786e00132..63db6107e05 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -497,7 +497,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); @@ -505,6 +505,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/src/node_script.cc b/src/node_script.cc index f8fefb67e65..6b82636a626 100644 --- a/src/node_script.cc +++ b/src/node_script.cc @@ -224,6 +224,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/src/platform_sunos.cc b/src/platform_sunos.cc index 59bf2e76986..0262bdc8d5c 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 @@ -110,11 +114,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; } @@ -128,12 +224,30 @@ double Platform::GetTotalMemory() { return 0.0; } - double Platform::GetUptimeImpl() { - // 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/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.'); +} 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-buffer.js b/test/simple/test-buffer.js index 11a2634d7f2..fb925323fbd 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); 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 = ''; 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(); + }); + }); +}); + diff --git a/test/simple/test-os.js b/test/simple/test-os.js index b09073c641e..f4641ae1cd2 100644 --- a/test/simple/test-os.js +++ b/test/simple/test-os.js @@ -23,14 +23,33 @@ 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); + +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); +} var interfaces = os.getNetworkInterfaces(); 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); +}); 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 diff --git a/wscript b/wscript index e8c1ce3d4b4..16956b75f49 100644 --- a/wscript +++ b/wscript @@ -376,6 +376,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') @@ -819,7 +821,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}'