Merge branch 'v0.4'
Conflicts: src/platform_sunos.cc test/simple/test-os.js
This commit is contained in:
commit
598792ba91
10
deps/v8/src/accessors.cc
vendored
10
deps/v8/src/accessors.cc
vendored
@ -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
vendored
141
deps/v8/src/arm/lithium-codegen-arm.cc
vendored
@ -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
vendored
65
deps/v8/src/arm/lithium-codegen-arm.h
vendored
@ -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;
|
||||
|
86
deps/v8/src/deoptimizer.cc
vendored
86
deps/v8/src/deoptimizer.cc
vendored
@ -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,37 +408,19 @@ void Deoptimizer::DoComputeOutputFrames() {
|
||||
}
|
||||
|
||||
|
||||
void Deoptimizer::InsertHeapNumberValues(int index, JavaScriptFrame* frame) {
|
||||
// We need to adjust the stack index by one for the top-most frame.
|
||||
int extra_slot_count = (index == output_count() - 1) ? 1 : 0;
|
||||
List<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());
|
||||
}
|
||||
|
||||
Memory::Object_at(d.slot_address()) = *num;
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
50
deps/v8/src/deoptimizer.h
vendored
50
deps/v8/src/deoptimizer.h
vendored
@ -42,38 +42,17 @@ class TranslationIterator;
|
||||
class DeoptimizingCodeListNode;
|
||||
|
||||
|
||||
class ValueDescription BASE_EMBEDDED {
|
||||
class HeapNumberMaterializationDescriptor BASE_EMBEDDED {
|
||||
public:
|
||||
explicit ValueDescription(int index) : stack_index_(index) { }
|
||||
int stack_index() const { return stack_index_; }
|
||||
HeapNumberMaterializationDescriptor(Address slot_address, double val)
|
||||
: slot_address_(slot_address), val_(val) { }
|
||||
|
||||
Address slot_address() const { return slot_address_; }
|
||||
double value() const { return val_; }
|
||||
|
||||
private:
|
||||
// Offset relative to the top of the stack.
|
||||
int stack_index_;
|
||||
};
|
||||
|
||||
|
||||
class ValueDescriptionInteger32: public ValueDescription {
|
||||
public:
|
||||
ValueDescriptionInteger32(int index, int32_t value)
|
||||
: ValueDescription(index), int32_value_(value) { }
|
||||
int32_t int32_value() const { return int32_value_; }
|
||||
|
||||
private:
|
||||
// Raw value.
|
||||
int32_t int32_value_;
|
||||
};
|
||||
|
||||
|
||||
class ValueDescriptionDouble: public ValueDescription {
|
||||
public:
|
||||
ValueDescriptionDouble(int index, double value)
|
||||
: ValueDescription(index), double_value_(value) { }
|
||||
double double_value() const { return double_value_; }
|
||||
|
||||
private:
|
||||
// Raw value.
|
||||
double double_value_;
|
||||
Address slot_address_;
|
||||
double val_;
|
||||
};
|
||||
|
||||
|
||||
@ -164,7 +143,7 @@ class Deoptimizer : public Malloced {
|
||||
|
||||
~Deoptimizer();
|
||||
|
||||
void InsertHeapNumberValues(int index, JavaScriptFrame* frame);
|
||||
void MaterializeHeapNumbers();
|
||||
|
||||
static void ComputeOutputFrames(Deoptimizer* deoptimizer);
|
||||
|
||||
@ -253,13 +232,7 @@ class Deoptimizer : public Malloced {
|
||||
|
||||
Object* ComputeLiteral(int index) const;
|
||||
|
||||
void InsertHeapNumberValue(JavaScriptFrame* frame,
|
||||
int stack_index,
|
||||
double val,
|
||||
int extra_slot_count);
|
||||
|
||||
void AddInteger32Value(int frame_index, int slot_index, int32_t value);
|
||||
void AddDoubleValue(int frame_index, int slot_index, double value);
|
||||
void AddDoubleValue(intptr_t slot_address, double value);
|
||||
|
||||
static LargeObjectChunk* CreateCode(BailoutType type);
|
||||
static void GenerateDeoptimizationEntries(
|
||||
@ -295,8 +268,7 @@ class Deoptimizer : public Malloced {
|
||||
// Array of output frame descriptions.
|
||||
FrameDescription** output_;
|
||||
|
||||
List<ValueDescriptionInteger32>* integer32_values_;
|
||||
List<ValueDescriptionDouble>* double_values_;
|
||||
List<HeapNumberMaterializationDescriptor> deferred_heap_numbers_;
|
||||
|
||||
static int table_entry_size_;
|
||||
|
||||
|
19
deps/v8/src/frames-inl.h
vendored
19
deps/v8/src/frames-inl.h
vendored
@ -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
vendored
63
deps/v8/src/frames.cc
vendored
@ -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
vendored
19
deps/v8/src/frames.h
vendored
@ -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
vendored
197
deps/v8/src/ia32/lithium-codegen-ia32.cc
vendored
@ -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::RegisterLazyDeoptimization(LInstruction* instr) {
|
||||
void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
|
||||
int argc,
|
||||
LInstruction* instr) {
|
||||
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
||||
__ CallRuntimeSaveDoubles(id);
|
||||
RecordSafepointWithRegisters(
|
||||
instr->pointer_map(), argc, Safepoint::kNoDeoptimizationIndex);
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr,
|
||||
SafepointMode safepoint_mode) {
|
||||
// Create the environment to bailout to. If the call has side effects
|
||||
// execution has to continue after the call otherwise execution can continue
|
||||
// from a previous bailout point repeating the call.
|
||||
@ -472,8 +492,16 @@ void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr) {
|
||||
}
|
||||
|
||||
RegisterEnvironmentForDeoptimization(deoptimization_environment);
|
||||
RecordSafepoint(instr->pointer_map(),
|
||||
deoptimization_environment->deoptimization_index());
|
||||
if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
|
||||
RecordSafepoint(instr->pointer_map(),
|
||||
deoptimization_environment->deoptimization_index());
|
||||
} else {
|
||||
ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
|
||||
RecordSafepointWithRegisters(
|
||||
instr->pointer_map(),
|
||||
0,
|
||||
deoptimization_environment->deoptimization_index());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -622,6 +650,7 @@ void LCodeGen::RecordSafepoint(
|
||||
Safepoint::Kind kind,
|
||||
int arguments,
|
||||
int deoptimization_index) {
|
||||
ASSERT(kind == expected_safepoint_kind_);
|
||||
const ZoneList<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
vendored
70
deps/v8/src/ia32/lithium-codegen-ia32.h
vendored
@ -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
vendored
4
deps/v8/src/ia32/macro-assembler-ia32.h
vendored
@ -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
vendored
25
deps/v8/src/runtime.cc
vendored
@ -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
vendored
37
deps/v8/src/scopes.cc
vendored
@ -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
vendored
28
deps/v8/src/scopes.h
vendored
@ -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
vendored
2
deps/v8/src/version.cc
vendored
@ -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
vendored
106
deps/v8/src/x64/lithium-codegen-x64.cc
vendored
@ -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::RegisterLazyDeoptimization(LInstruction* instr) {
|
||||
void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
|
||||
int argc,
|
||||
LInstruction* instr) {
|
||||
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
|
||||
__ CallRuntimeSaveDoubles(id);
|
||||
RecordSafepointWithRegisters(
|
||||
instr->pointer_map(), argc, Safepoint::kNoDeoptimizationIndex);
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr,
|
||||
SafepointMode safepoint_mode,
|
||||
int argc) {
|
||||
// Create the environment to bailout to. If the call has side effects
|
||||
// execution has to continue after the call otherwise execution can continue
|
||||
// from a previous bailout point repeating the call.
|
||||
@ -472,8 +493,17 @@ void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr) {
|
||||
}
|
||||
|
||||
RegisterEnvironmentForDeoptimization(deoptimization_environment);
|
||||
RecordSafepoint(instr->pointer_map(),
|
||||
deoptimization_environment->deoptimization_index());
|
||||
if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
|
||||
ASSERT(argc == 0);
|
||||
RecordSafepoint(instr->pointer_map(),
|
||||
deoptimization_environment->deoptimization_index());
|
||||
} else {
|
||||
ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS);
|
||||
RecordSafepointWithRegisters(
|
||||
instr->pointer_map(),
|
||||
argc,
|
||||
deoptimization_environment->deoptimization_index());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -598,6 +628,8 @@ void LCodeGen::RecordSafepoint(
|
||||
Safepoint::Kind kind,
|
||||
int arguments,
|
||||
int deoptimization_index) {
|
||||
ASSERT(kind == expected_safepoint_kind_);
|
||||
|
||||
const ZoneList<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
vendored
47
deps/v8/src/x64/lithium-codegen-x64.h
vendored
@ -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
vendored
4
deps/v8/src/x64/macro-assembler-x64.h
vendored
@ -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
vendored
Normal file
37
deps/v8/test/mjsunit/regress/regress-78270.js
vendored
Normal file
@ -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) {
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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'
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
Normal file
39
test/disabled/GH-670.js
Normal file
@ -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
vendored
Normal file
48
test/fixtures/GH-892-request.js
vendored
Normal file
@ -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);
|
||||
});
|
@ -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);
|
||||
|
@ -121,19 +121,19 @@ file4.addListener('end', function(data) {
|
||||
assert.equal(contentRead, 'yz');
|
||||
});
|
||||
|
||||
try {
|
||||
fs.createReadStream(rangeFile, {start: 10, end: 2});
|
||||
assert.fail('Creating a ReadStream with incorrect range limits must throw.');
|
||||
} catch (e) {
|
||||
assert.equal(e.message, 'start must be <= end');
|
||||
}
|
||||
var file5 = fs.createReadStream(rangeFile, {bufferSize: 1, start: 1});
|
||||
file5.data = '';
|
||||
file5.addListener('data', function(data) {
|
||||
file5.data += data.toString('utf-8');
|
||||
});
|
||||
file5.addListener('end', function() {
|
||||
assert.equal(file5.data, 'yz\n');
|
||||
});
|
||||
|
||||
try {
|
||||
fs.createReadStream(rangeFile, {start: 2});
|
||||
assert.fail('Creating a ReadStream with a only one range limits must throw.');
|
||||
} catch (e) {
|
||||
assert.equal(e.message, 'Both start and end are needed for range streaming.');
|
||||
}
|
||||
|
||||
assert.throws(function() {
|
||||
fs.createReadStream(rangeFile, {start: 10, end: 2});
|
||||
}, /start must be <= end/);
|
||||
|
||||
var stream = fs.createReadStream(rangeFile, { start: 0, end: 0 });
|
||||
stream.data = '';
|
||||
|
19
test/simple/test-http-response-readable.js
Normal file
19
test/simple/test-http-response-readable.js
Normal file
@ -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();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -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
Normal file
105
test/simple/test-regress-GH-892.js
Normal file
@ -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
Normal file
12
test/simple/test-vm-create-context-circular-reference.js
Normal file
@ -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
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…
x
Reference in New Issue
Block a user