Browse Source

Merge branch 'v0.4'

Conflicts:
	src/platform_sunos.cc
	test/simple/test-os.js
v0.7.4-release
Ryan Dahl 14 years ago
parent
commit
598792ba91
  1. 10
      deps/v8/src/accessors.cc
  2. 141
      deps/v8/src/arm/lithium-codegen-arm.cc
  3. 65
      deps/v8/src/arm/lithium-codegen-arm.h
  4. 84
      deps/v8/src/deoptimizer.cc
  5. 48
      deps/v8/src/deoptimizer.h
  6. 19
      deps/v8/src/frames-inl.h
  7. 63
      deps/v8/src/frames.cc
  8. 19
      deps/v8/src/frames.h
  9. 197
      deps/v8/src/ia32/lithium-codegen-ia32.cc
  10. 70
      deps/v8/src/ia32/lithium-codegen-ia32.h
  11. 4
      deps/v8/src/ia32/macro-assembler-ia32.h
  12. 25
      deps/v8/src/runtime.cc
  13. 37
      deps/v8/src/scopes.cc
  14. 28
      deps/v8/src/scopes.h
  15. 2
      deps/v8/src/version.cc
  16. 106
      deps/v8/src/x64/lithium-codegen-x64.cc
  17. 47
      deps/v8/src/x64/lithium-codegen-x64.h
  18. 4
      deps/v8/src/x64/macro-assembler-x64.h
  19. 37
      deps/v8/test/mjsunit/regress/regress-78270.js
  20. 8
      doc/api/buffers.markdown
  21. 2
      doc/api/fs.markdown
  22. 11
      doc/api/globals.markdown
  23. 11
      doc/api/http.markdown
  24. 45
      doc/api/modules.markdown
  25. 2
      lib/_debugger.js
  26. 11
      lib/fs.js
  27. 3
      lib/http.js
  28. 7
      lib/net.js
  29. 2
      lib/tls.js
  30. 6
      src/node_buffer.cc
  31. 1
      src/node_script.cc
  32. 126
      src/platform_sunos.cc
  33. 39
      test/disabled/GH-670.js
  34. 48
      test/fixtures/GH-892-request.js
  35. 9
      test/simple/test-buffer.js
  36. 24
      test/simple/test-fs-read-stream.js
  37. 19
      test/simple/test-http-response-readable.js
  38. 35
      test/simple/test-os.js
  39. 105
      test/simple/test-regress-GH-892.js
  40. 12
      test/simple/test-vm-create-context-circular-reference.js
  41. 4
      wscript

10
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<JSObject> arguments = Factory::NewArgumentsObject(function,
length);
Handle<FixedArray> 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.

141
deps/v8/src/arm/lithium-codegen-arm.cc

@ -465,11 +465,19 @@ void LCodeGen::AddToTranslation(Translation* translation,
void LCodeGen::CallCode(Handle<Code> code,
RelocInfo::Mode mode,
LInstruction* instr) {
CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT);
}
void LCodeGen::CallCodeGeneric(Handle<Code> 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<LOperand*>* 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<JSFunction> 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();
}

65
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> code,
RelocInfo::Mode mode,
LInstruction* instr);
void CallCodeGeneric(Handle<Code> 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<JSFunction> function,
@ -188,7 +205,9 @@ class LCodeGen BASE_EMBEDDED {
void LoadHeapObject(Register result, Handle<HeapObject> 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;

84
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<ValueDescriptionInteger32>[count];
double_values_ = new List<ValueDescriptionDouble>[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,40 +408,22 @@ 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<ValueDescriptionInteger32>* ints = &integer32_values_[index];
for (int i = 0; i < ints->length(); i++) {
ValueDescriptionInteger32 value = ints->at(i);
double val = static_cast<double>(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<Object> num = Factory::NewNumber(d.value());
if (FLAG_trace_deopt) {
PrintF("Materializing a new heap number %p [%e] in slot %p\n",
reinterpret_cast<void*>(*num),
d.value(),
d.slot_address());
}
// Iterate over double values and convert them to a heap number.
List<ValueDescriptionDouble>* 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);
Memory::Object_at(d.slot_address()) = *num;
}
}
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<Object> num = Factory::NewNumber(val);
frame->SetExpression(index, *num);
}
void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
int frame_index,
unsigned output_offset) {
@ -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<int32_t>(value));
AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
static_cast<double>(static_cast<int32_t>(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<int32_t>(value));
AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
static_cast<double>(static_cast<int32_t>(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<Address>(slot_address), value);
deferred_heap_numbers_.Add(value_desc);
}

48
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_; }
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_;
};
HeapNumberMaterializationDescriptor(Address slot_address, double val)
: slot_address_(slot_address), val_(val) { }
class ValueDescriptionDouble: public ValueDescription {
public:
ValueDescriptionDouble(int index, double value)
: ValueDescription(index), double_value_(value) { }
double double_value() const { return double_value_; }
Address slot_address() const { return slot_address_; }
double value() const { return val_; }
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<ValueDescriptionInteger32>* integer32_values_;
List<ValueDescriptionDouble>* double_values_;
List<HeapNumberMaterializationDescriptor> deferred_heap_numbers_;
static int table_entry_size_;

19
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;
}

63
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<int>((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<JSFunction*>* 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);
}

19
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:

197
deps/v8/src/ia32/lithium-codegen-ia32.cc

@ -418,20 +418,21 @@ void LCodeGen::AddToTranslation(Translation* translation,
}
void LCodeGen::CallCode(Handle<Code> code,
RelocInfo::Mode mode,
LInstruction* instr,
bool adjusted) {
void LCodeGen::CallCodeGeneric(Handle<Code> 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> code,
}
void LCodeGen::CallCode(Handle<Code> 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::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) {
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<LOperand*>* 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<InstanceofStub::Flags>(
@ -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<Code> 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<Code> 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<Code> 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<Code> 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<JSFunction> 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<Code> 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<Code> 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<Code> 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<Code> 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<Code> 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<Code> 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);
}

70
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> 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> code,
RelocInfo::Mode mode,
LInstruction* instr,
ContextMode context_mode);
void CallCodeGeneric(Handle<Code> 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<JSFunction> function,
@ -177,7 +206,9 @@ class LCodeGen BASE_EMBEDDED {
void LoadHeapObject(Register result, Handle<HeapObject> 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;

4
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_;

25
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<JSFunction> 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<Object> GetArgumentsObject(JavaScriptFrame* frame,
}
}
const int length = frame->GetProvidedParametersCount();
const int length = frame->ComputeParametersCount();
Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
Handle<FixedArray> array = Factory::NewFixedArray(length);

37
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<SerializedScopeInfo>::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<SerializedScopeInfo>::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<SerializedScopeInfo> 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<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;
}
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<SerializedScopeInfo> 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 {

28
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<SerializedScopeInfo> 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<SerializedScopeInfo> 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<SerializedScopeInfo> scope_info);
};

2
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

106
deps/v8/src/x64/lithium-codegen-x64.cc

@ -429,14 +429,16 @@ void LCodeGen::AddToTranslation(Translation* translation,
}
void LCodeGen::CallCode(Handle<Code> code,
RelocInfo::Mode mode,
LInstruction* instr) {
void LCodeGen::CallCodeGeneric(Handle<Code> 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> code,
}
void LCodeGen::CallCode(Handle<Code> 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::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) {
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<LOperand*>* 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<JSFunction> 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);
}

47
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> code,
RelocInfo::Mode mode,
LInstruction* instr,
SafepointMode safepoint_mode,
int argc);
void CallCode(Handle<Code> 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<JSFunction> function,
@ -172,7 +192,9 @@ class LCodeGen BASE_EMBEDDED {
void LoadHeapObject(Register result, Handle<HeapObject> 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;

4
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.

37
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) {
}
}

8
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)

2
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:

11
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.

11
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'

45
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

2
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]);
}
}

11
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;

3
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;

7
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

2
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;
};

6
src/node_buffer.cc

@ -497,7 +497,7 @@ Handle<Value> 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<Value> 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));
}

1
src/node_script.cc

@ -224,6 +224,7 @@ Handle<Value> WrappedScript::CreateContext(const Arguments& args) {
for (uint32_t i = 0; i < keys->Length(); i++) {
Handle<String> key = keys->Get(Integer::New(i))->ToString();
Handle<Value> value = sandbox->Get(key);
if(value == sandbox) { value = context; }
context->Set(key, value);
}
}

126
src/platform_sunos.cc

@ -27,6 +27,10 @@
#include <stdlib.h> /* getexecname() */
#include <strings.h> /* strncpy() */
#include <kstat.h>
#include <errno.h>
#include <inttypes.h>
#include <sys/types.h>
#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<Value> data_named(kstat_named_t *knp) {
Handle<Value> 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<Array> *cpus) {
// http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/cmd/psrinfo/psrinfo.pl
HandleScope scope;
Local<Object> cpuinfo;
Local<Object> 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<double>( clk_intr / hz );
}
int Platform::GetLoadAvg(Local<Array> *loads) {
return 0;

39
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.');
}

48
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);
});

9
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);

24
test/simple/test-fs-read-stream.js

@ -121,19 +121,19 @@ file4.addListener('end', function(data) {
assert.equal(contentRead, 'yz');
});
try {
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');
});
assert.throws(function() {
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');
}
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.');
}
}, /start must be <= end/);
var stream = fs.createReadStream(rangeFile, { start: 0, end: 0 });
stream.data = '';

19
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();
});
});
});

35
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();

105
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);
});

12
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);

4
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}'

Loading…
Cancel
Save