Version 3.19.9
Implemented Load IC support for loading properties from primitive values to avoid perpetual soft deopts. (Chromium issue 242512)
Implemented Freeing of PerThreadAssertData when possible to avoid memory leak. (Chromium issue 246567)
Removed V8_USE_OLD_STYLE_PERSISTENT_HANDLE_VISITORS.
Performance and stability improvements on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@14954 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index aa533bf..8cb4725 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -142,6 +142,28 @@
}
+static void InitializeInternalArrayConstructorDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor,
+ int constant_stack_parameter_count) {
+ // register state
+ // eax -- number of arguments
+ // edi -- constructor function
+ static Register registers[] = { edi };
+ descriptor->register_param_count_ = 1;
+
+ if (constant_stack_parameter_count != 0) {
+ // stack param count needs (constructor pointer, and single argument)
+ descriptor->stack_parameter_count_ = &eax;
+ }
+ descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count;
+ descriptor->register_params_ = registers;
+ descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
+ descriptor->deoptimization_handler_ =
+ FUNCTION_ADDR(InternalArrayConstructor_StubFailure);
+}
+
+
void ArrayNoArgumentConstructorStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
@@ -163,6 +185,27 @@
}
+void InternalArrayNoArgumentConstructorStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ InitializeInternalArrayConstructorDescriptor(isolate, descriptor, 0);
+}
+
+
+void InternalArraySingleArgumentConstructorStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ InitializeInternalArrayConstructorDescriptor(isolate, descriptor, 1);
+}
+
+
+void InternalArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ InitializeInternalArrayConstructorDescriptor(isolate, descriptor, -1);
+}
+
+
void CompareNilICStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
@@ -566,12 +609,6 @@
// Expects operands in edx, eax.
static void LoadSSE2Smis(MacroAssembler* masm, Register scratch);
- // Checks that the two floating point numbers loaded into xmm0 and xmm1
- // have int32 values.
- static void CheckSSE2OperandsAreInt32(MacroAssembler* masm,
- Label* non_int32,
- Register scratch);
-
// Checks that |operand| has an int32 value. If |int32_result| is different
// from |scratch|, it will contain that int32 value.
static void CheckSSE2OperandIsInt32(MacroAssembler* masm,
@@ -1470,7 +1507,7 @@
void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
- Label call_runtime;
+ Label right_arg_changed, call_runtime;
switch (op_) {
case Token::ADD:
@@ -1491,6 +1528,13 @@
UNREACHABLE();
}
+ if (op_ == Token::MOD && has_fixed_right_arg_) {
+ // It is guaranteed that the value will fit into a Smi, because if it
+ // didn't, we wouldn't be here, see BinaryOp_Patch.
+ __ cmp(eax, Immediate(Smi::FromInt(fixed_right_arg_value())));
+ __ j(not_equal, &right_arg_changed);
+ }
+
if (result_type_ == BinaryOpIC::UNINITIALIZED ||
result_type_ == BinaryOpIC::SMI) {
BinaryOpStub_GenerateSmiCode(
@@ -1502,6 +1546,7 @@
// Code falls through if the result is not returned as either a smi or heap
// number.
+ __ bind(&right_arg_changed);
switch (op_) {
case Token::ADD:
case Token::SUB:
@@ -1604,8 +1649,7 @@
case Token::MUL:
case Token::DIV:
case Token::MOD: {
- Label not_floats;
- Label not_int32;
+ Label not_floats, not_int32, right_arg_changed;
if (CpuFeatures::IsSupported(SSE2)) {
CpuFeatureScope use_sse2(masm, SSE2);
// It could be that only SMIs have been seen at either the left
@@ -1621,8 +1665,15 @@
__ JumpIfNotSmi(eax, ¬_int32);
}
FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats);
- FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, ¬_int32, ecx);
+ FloatingPointHelper::CheckSSE2OperandIsInt32(
+ masm, ¬_int32, xmm0, ebx, ecx, xmm2);
+ FloatingPointHelper::CheckSSE2OperandIsInt32(
+ masm, ¬_int32, xmm1, edi, ecx, xmm2);
if (op_ == Token::MOD) {
+ if (has_fixed_right_arg_) {
+ __ cmp(edi, Immediate(fixed_right_arg_value()));
+ __ j(not_equal, &right_arg_changed);
+ }
GenerateRegisterArgsPush(masm);
__ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION);
} else {
@@ -1675,6 +1726,7 @@
__ bind(¬_floats);
__ bind(¬_int32);
+ __ bind(&right_arg_changed);
GenerateTypeTransition(masm);
break;
}
@@ -2766,14 +2818,6 @@
}
-void FloatingPointHelper::CheckSSE2OperandsAreInt32(MacroAssembler* masm,
- Label* non_int32,
- Register scratch) {
- CheckSSE2OperandIsInt32(masm, non_int32, xmm0, scratch, scratch, xmm2);
- CheckSSE2OperandIsInt32(masm, non_int32, xmm1, scratch, scratch, xmm2);
-}
-
-
void FloatingPointHelper::CheckSSE2OperandIsInt32(MacroAssembler* masm,
Label* non_int32,
XMMRegister operand,
@@ -3327,6 +3371,8 @@
void ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) {
+ Isolate* isolate = masm->isolate();
+
// esp[0] : return address
// esp[4] : number of parameters (tagged)
// esp[8] : receiver displacement
@@ -3458,7 +3504,7 @@
__ j(zero, &skip_parameter_map);
__ mov(FieldOperand(edi, FixedArray::kMapOffset),
- Immediate(FACTORY->non_strict_arguments_elements_map()));
+ Immediate(isolate->factory()->non_strict_arguments_elements_map()));
__ lea(eax, Operand(ebx, reinterpret_cast<intptr_t>(Smi::FromInt(2))));
__ mov(FieldOperand(edi, FixedArray::kLengthOffset), eax);
__ mov(FieldOperand(edi, FixedArray::kHeaderSize + 0 * kPointerSize), esi);
@@ -3479,7 +3525,7 @@
__ mov(ebx, Immediate(Smi::FromInt(Context::MIN_CONTEXT_SLOTS)));
__ add(ebx, Operand(esp, 4 * kPointerSize));
__ sub(ebx, eax);
- __ mov(ecx, FACTORY->the_hole_value());
+ __ mov(ecx, isolate->factory()->the_hole_value());
__ mov(edx, edi);
__ lea(edi, Operand(edi, eax, times_2, kParameterMapHeaderSize));
// eax = loop variable (tagged)
@@ -3514,7 +3560,7 @@
// esp[16] = address of receiver argument
// Copy arguments header and remaining slots (if there are any).
__ mov(FieldOperand(edi, FixedArray::kMapOffset),
- Immediate(FACTORY->fixed_array_map()));
+ Immediate(isolate->factory()->fixed_array_map()));
__ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx);
Label arguments_loop, arguments_test;
@@ -3550,6 +3596,8 @@
void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
+ Isolate* isolate = masm->isolate();
+
// esp[0] : return address
// esp[4] : number of parameters
// esp[8] : receiver displacement
@@ -3620,7 +3668,7 @@
__ lea(edi, Operand(eax, Heap::kArgumentsObjectSizeStrict));
__ mov(FieldOperand(eax, JSObject::kElementsOffset), edi);
__ mov(FieldOperand(edi, FixedArray::kMapOffset),
- Immediate(FACTORY->fixed_array_map()));
+ Immediate(isolate->factory()->fixed_array_map()));
__ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx);
// Untag the length for the loop below.
@@ -4777,7 +4825,11 @@
__ j(not_equal, &slow);
if (RecordCallTarget()) {
- GenerateRecordCallTargetNoArray(masm);
+ if (FLAG_optimize_constructed_arrays) {
+ GenerateRecordCallTarget(masm);
+ } else {
+ GenerateRecordCallTargetNoArray(masm);
+ }
}
// Fast-case: Just invoke the function.
@@ -7818,8 +7870,12 @@
TERMINAL_FAST_ELEMENTS_KIND);
for (int i = 0; i <= to_index; ++i) {
ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
- T stub(kind);
+ T stub(kind, false);
stub.GetCode(isolate)->set_is_pregenerated(true);
+ if (AllocationSiteInfo::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE) {
+ T stub1(kind, true);
+ stub1.GetCode(isolate)->set_is_pregenerated(true);
+ }
}
}
@@ -7834,6 +7890,21 @@
}
+void InternalArrayConstructorStubBase::GenerateStubsAheadOfTime(
+ Isolate* isolate) {
+ ElementsKind kinds[2] = { FAST_ELEMENTS, FAST_HOLEY_ELEMENTS };
+ for (int i = 0; i < 2; i++) {
+ // For internal arrays we only need a few things
+ InternalArrayNoArgumentConstructorStub stubh1(kinds[i]);
+ stubh1.GetCode(isolate)->set_is_pregenerated(true);
+ InternalArraySingleArgumentConstructorStub stubh2(kinds[i]);
+ stubh2.GetCode(isolate)->set_is_pregenerated(true);
+ InternalArrayNArgumentsConstructorStub stubh3(kinds[i]);
+ stubh3.GetCode(isolate)->set_is_pregenerated(true);
+ }
+}
+
+
void ArrayConstructorStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : argc (only if argument_count_ == ANY)
@@ -7919,6 +7990,107 @@
}
+void InternalArrayConstructorStub::GenerateCase(
+ MacroAssembler* masm, ElementsKind kind) {
+ Label not_zero_case, not_one_case;
+ Label normal_sequence;
+
+ __ test(eax, eax);
+ __ j(not_zero, ¬_zero_case);
+ InternalArrayNoArgumentConstructorStub stub0(kind);
+ __ TailCallStub(&stub0);
+
+ __ bind(¬_zero_case);
+ __ cmp(eax, 1);
+ __ j(greater, ¬_one_case);
+
+ if (IsFastPackedElementsKind(kind)) {
+ // We might need to create a holey array
+ // look at the first argument
+ __ mov(ecx, Operand(esp, kPointerSize));
+ __ test(ecx, ecx);
+ __ j(zero, &normal_sequence);
+
+ InternalArraySingleArgumentConstructorStub
+ stub1_holey(GetHoleyElementsKind(kind));
+ __ TailCallStub(&stub1_holey);
+ }
+
+ __ bind(&normal_sequence);
+ InternalArraySingleArgumentConstructorStub stub1(kind);
+ __ TailCallStub(&stub1);
+
+ __ bind(¬_one_case);
+ InternalArrayNArgumentsConstructorStub stubN(kind);
+ __ TailCallStub(&stubN);
+}
+
+
+void InternalArrayConstructorStub::Generate(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- eax : argc
+ // -- ebx : type info cell
+ // -- edi : constructor
+ // -- esp[0] : return address
+ // -- esp[4] : last argument
+ // -----------------------------------
+
+ if (FLAG_debug_code) {
+ // The array construct code is only set for the global and natives
+ // builtin Array functions which always have maps.
+
+ // Initial map for the builtin Array function should be a map.
+ __ mov(ecx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
+ // Will both indicate a NULL and a Smi.
+ __ test(ecx, Immediate(kSmiTagMask));
+ __ Assert(not_zero, "Unexpected initial map for Array function");
+ __ CmpObjectType(ecx, MAP_TYPE, ecx);
+ __ Assert(equal, "Unexpected initial map for Array function");
+ }
+
+ if (FLAG_optimize_constructed_arrays) {
+ // Figure out the right elements kind
+ __ mov(ecx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
+
+ // Load the map's "bit field 2" into |result|. We only need the first byte,
+ // but the following masking takes care of that anyway.
+ __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
+ // Retrieve elements_kind from bit field 2.
+ __ and_(ecx, Map::kElementsKindMask);
+ __ shr(ecx, Map::kElementsKindShift);
+
+ if (FLAG_debug_code) {
+ Label done;
+ __ cmp(ecx, Immediate(FAST_ELEMENTS));
+ __ j(equal, &done);
+ __ cmp(ecx, Immediate(FAST_HOLEY_ELEMENTS));
+ __ Assert(equal,
+ "Invalid ElementsKind for InternalArray or InternalPackedArray");
+ __ bind(&done);
+ }
+
+ Label fast_elements_case;
+ __ cmp(ecx, Immediate(FAST_ELEMENTS));
+ __ j(equal, &fast_elements_case);
+ GenerateCase(masm, FAST_HOLEY_ELEMENTS);
+
+ __ bind(&fast_elements_case);
+ GenerateCase(masm, FAST_ELEMENTS);
+ } else {
+ Label generic_constructor;
+ // Run the native code for the Array function called as constructor.
+ ArrayNativeCode(masm, true, &generic_constructor);
+
+ // Jump to the generic construct code in case the specialized code cannot
+ // handle the construction.
+ __ bind(&generic_constructor);
+ Handle<Code> generic_construct_stub =
+ masm->isolate()->builtins()->JSConstructStubGeneric();
+ __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET);
+ }
+}
+
+
#undef __
} } // namespace v8::internal