Version 3.20.0
Migrated several tests from blink to V8 repository.
Allowed users of the V8 API to distinguish between unset and undefined HiddenValues (issue 2746).
Deprecated old style callbacks in the V8 API.
Turned on parallel recompilation.
Performance and stability improvements on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@15386 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index f3483eb..8cd4685 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -1527,7 +1527,7 @@
UNREACHABLE();
}
- if (op_ == Token::MOD && has_fixed_right_arg_) {
+ if (op_ == Token::MOD && encoded_right_arg_.has_value) {
// 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())));
@@ -1669,7 +1669,7 @@
FloatingPointHelper::CheckSSE2OperandIsInt32(
masm, ¬_int32, xmm1, edi, ecx, xmm2);
if (op_ == Token::MOD) {
- if (has_fixed_right_arg_) {
+ if (encoded_right_arg_.has_value) {
__ cmp(edi, Immediate(fixed_right_arg_value()));
__ j(not_equal, &right_arg_changed);
}
@@ -4678,51 +4678,12 @@
}
-static void GenerateRecordCallTargetNoArray(MacroAssembler* masm) {
- // Cache the called function in a global property cell. Cache states
- // are uninitialized, monomorphic (indicated by a JSFunction), and
- // megamorphic.
- // ebx : cache cell for call target
- // edi : the function to call
- Isolate* isolate = masm->isolate();
- Label initialize, done;
-
- // Load the cache state into ecx.
- __ mov(ecx, FieldOperand(ebx, PropertyCell::kValueOffset));
-
- // A monomorphic cache hit or an already megamorphic state: invoke the
- // function without changing the state.
- __ cmp(ecx, edi);
- __ j(equal, &done, Label::kNear);
- __ cmp(ecx, Immediate(TypeFeedbackCells::MegamorphicSentinel(isolate)));
- __ j(equal, &done, Label::kNear);
-
- // A monomorphic miss (i.e, here the cache is not uninitialized) goes
- // megamorphic.
- __ cmp(ecx, Immediate(TypeFeedbackCells::UninitializedSentinel(isolate)));
- __ j(equal, &initialize, Label::kNear);
- // MegamorphicSentinel is an immortal immovable object (undefined) so no
- // write-barrier is needed.
- __ mov(FieldOperand(ebx, Cell::kValueOffset),
- Immediate(TypeFeedbackCells::MegamorphicSentinel(isolate)));
- __ jmp(&done, Label::kNear);
-
- // An uninitialized cache is patched with the function.
- __ bind(&initialize);
- __ mov(FieldOperand(ebx, Cell::kValueOffset), edi);
- // No need for a write barrier here - cells are rescanned.
-
- __ bind(&done);
-}
-
-
static void GenerateRecordCallTarget(MacroAssembler* masm) {
// Cache the called function in a global property cell. Cache states
// are uninitialized, monomorphic (indicated by a JSFunction), and
// megamorphic.
// ebx : cache cell for call target
// edi : the function to call
- ASSERT(FLAG_optimize_constructed_arrays);
Isolate* isolate = masm->isolate();
Label initialize, done, miss, megamorphic, not_array_function;
@@ -4739,12 +4700,15 @@
// Special handling of the Array() function, which caches not only the
// monomorphic Array function but the initial ElementsKind with special
// sentinels
- Handle<Object> terminal_kind_sentinel =
- TypeFeedbackCells::MonomorphicArraySentinel(isolate,
- LAST_FAST_ELEMENTS_KIND);
__ JumpIfNotSmi(ecx, &miss);
- __ cmp(ecx, Immediate(terminal_kind_sentinel));
- __ j(above, &miss);
+ if (FLAG_debug_code) {
+ Handle<Object> terminal_kind_sentinel =
+ TypeFeedbackCells::MonomorphicArraySentinel(masm->isolate(),
+ LAST_FAST_ELEMENTS_KIND);
+ __ cmp(ecx, Immediate(terminal_kind_sentinel));
+ __ Assert(less_equal, "Array function sentinel is not an ElementsKind");
+ }
+
// Load the global or builtins object from the current context
__ LoadGlobalContext(ecx);
// Make sure the function is the Array() function
@@ -4824,11 +4788,7 @@
__ j(not_equal, &slow);
if (RecordCallTarget()) {
- if (FLAG_optimize_constructed_arrays) {
- GenerateRecordCallTarget(masm);
- } else {
- GenerateRecordCallTargetNoArray(masm);
- }
+ GenerateRecordCallTarget(masm);
}
// Fast-case: Just invoke the function.
@@ -4901,15 +4861,11 @@
__ j(not_equal, &slow);
if (RecordCallTarget()) {
- if (FLAG_optimize_constructed_arrays) {
- GenerateRecordCallTarget(masm);
- } else {
- GenerateRecordCallTargetNoArray(masm);
- }
+ GenerateRecordCallTarget(masm);
}
// Jump to the function-specific construct stub.
- Register jmp_reg = FLAG_optimize_constructed_arrays ? ecx : ebx;
+ Register jmp_reg = ecx;
__ mov(jmp_reg, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
__ mov(jmp_reg, FieldOperand(jmp_reg,
SharedFunctionInfo::kConstructStubOffset));
@@ -4955,9 +4911,7 @@
StubFailureTrampolineStub::GenerateAheadOfTime(isolate);
// It is important that the store buffer overflow stubs are generated first.
RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate);
- if (FLAG_optimize_constructed_arrays) {
- ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
- }
+ ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
}
@@ -5050,11 +5004,6 @@
Label okay;
__ cmp(eax, masm->isolate()->factory()->the_hole_value());
__ j(not_equal, &okay, Label::kNear);
- // TODO(wingo): Currently SuspendJSGeneratorObject returns the hole. Change
- // to return another sentinel like a harmony symbol.
- __ cmp(ebx, Immediate(ExternalReference(
- Runtime::kSuspendJSGeneratorObject, masm->isolate())));
- __ j(equal, &okay, Label::kNear);
__ int3();
__ bind(&okay);
}
@@ -5131,6 +5080,8 @@
// esi: current context (C callee-saved)
// edi: JS function of the caller (C callee-saved)
+ ProfileEntryHookStub::MaybeCallEntryHook(masm);
+
// NOTE: Invocations of builtins may return failure objects instead
// of a proper result. The builtin entry handles this by performing
// a garbage collection and retrying the builtin (twice).
@@ -5204,6 +5155,8 @@
Label invoke, handler_entry, exit;
Label not_outermost_js, not_outermost_js_2;
+ ProfileEntryHookStub::MaybeCallEntryHook(masm);
+
// Set up frame.
__ push(ebp);
__ mov(ebp, esp);
@@ -6907,9 +6860,13 @@
__ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
__ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
STATIC_ASSERT(kInternalizedTag != 0);
- __ and_(tmp1, tmp2);
- __ test(tmp1, Immediate(kIsInternalizedMask));
- __ j(zero, &miss, Label::kNear);
+ __ and_(tmp1, Immediate(kIsNotStringMask | kIsInternalizedMask));
+ __ cmpb(tmp1, kInternalizedTag | kStringTag);
+ __ j(not_equal, &miss, Label::kNear);
+
+ __ and_(tmp2, Immediate(kIsNotStringMask | kIsInternalizedMask));
+ __ cmpb(tmp2, kInternalizedTag | kStringTag);
+ __ j(not_equal, &miss, Label::kNear);
// Internalized strings are compared by identity.
Label done;
@@ -6954,19 +6911,8 @@
__ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
__ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
- Label succeed1;
- __ test(tmp1, Immediate(kIsInternalizedMask));
- __ j(not_zero, &succeed1);
- __ cmpb(tmp1, static_cast<uint8_t>(SYMBOL_TYPE));
- __ j(not_equal, &miss);
- __ bind(&succeed1);
-
- Label succeed2;
- __ test(tmp2, Immediate(kIsInternalizedMask));
- __ j(not_zero, &succeed2);
- __ cmpb(tmp2, static_cast<uint8_t>(SYMBOL_TYPE));
- __ j(not_equal, &miss);
- __ bind(&succeed2);
+ __ JumpIfNotUniqueName(tmp1, &miss, Label::kNear);
+ __ JumpIfNotUniqueName(tmp2, &miss, Label::kNear);
// Unique names are compared by identity.
Label done;
@@ -7031,7 +6977,8 @@
// Check that both strings are internalized. If they are, we're done
// because we already know they are not identical. But in the case of
- // non-equality compare, we still need to determine the order.
+ // non-equality compare, we still need to determine the order. We
+ // also know they are both strings.
if (equality) {
Label do_compare;
STATIC_ASSERT(kInternalizedTag != 0);
@@ -7190,12 +7137,8 @@
// Check if the entry name is not a unique name.
__ mov(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset));
- __ test_b(FieldOperand(entity_name, Map::kInstanceTypeOffset),
- kIsInternalizedMask);
- __ j(not_zero, &good);
- __ cmpb(FieldOperand(entity_name, Map::kInstanceTypeOffset),
- static_cast<uint8_t>(SYMBOL_TYPE));
- __ j(not_equal, miss);
+ __ JumpIfNotUniqueName(FieldOperand(entity_name, Map::kInstanceTypeOffset),
+ miss);
__ bind(&good);
}
@@ -7328,15 +7271,9 @@
// key we are looking for.
// Check if the entry name is not a unique name.
- Label cont;
__ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
- __ test_b(FieldOperand(scratch, Map::kInstanceTypeOffset),
- kIsInternalizedMask);
- __ j(not_zero, &cont);
- __ cmpb(FieldOperand(scratch, Map::kInstanceTypeOffset),
- static_cast<uint8_t>(SYMBOL_TYPE));
- __ j(not_equal, &maybe_in_dictionary);
- __ bind(&cont);
+ __ JumpIfNotUniqueName(FieldOperand(scratch, Map::kInstanceTypeOffset),
+ &maybe_in_dictionary);
}
}
@@ -7761,7 +7698,11 @@
void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) {
- if (entry_hook_ != NULL) {
+ if (masm->isolate()->function_entry_hook() != NULL) {
+ // It's always safe to call the entry hook stub, as the hook itself
+ // is not allowed to call back to V8.
+ AllowStubCallsScope allow_stub_calls(masm, true);
+
ProfileEntryHookStub stub;
masm->CallStub(&stub);
}
@@ -7769,9 +7710,11 @@
void ProfileEntryHookStub::Generate(MacroAssembler* masm) {
- // Ecx is the only volatile register we must save.
- const int kNumSavedRegisters = 1;
+ // Save volatile registers.
+ const int kNumSavedRegisters = 3;
+ __ push(eax);
__ push(ecx);
+ __ push(edx);
// Calculate and push the original stack pointer.
__ lea(eax, Operand(esp, (kNumSavedRegisters + 1) * kPointerSize));
@@ -7784,12 +7727,16 @@
__ push(eax);
// Call the entry hook.
- int32_t hook_location = reinterpret_cast<int32_t>(&entry_hook_);
- __ call(Operand(hook_location, RelocInfo::NONE32));
+ ASSERT(masm->isolate()->function_entry_hook() != NULL);
+ __ call(FUNCTION_ADDR(masm->isolate()->function_entry_hook()),
+ RelocInfo::RUNTIME_ENTRY);
__ add(esp, Immediate(2 * kPointerSize));
// Restore ecx.
+ __ pop(edx);
__ pop(ecx);
+ __ pop(eax);
+
__ ret(0);
}
@@ -7847,6 +7794,10 @@
__ cmp(ebx, Immediate(undefined_sentinel));
__ j(equal, &normal_sequence);
+ // The type cell may have gone megamorphic, don't overwrite if so
+ __ mov(ecx, FieldOperand(ebx, kPointerSize));
+ __ JumpIfNotSmi(ecx, &normal_sequence);
+
// Save the resulting elements kind in type info
__ SmiTag(edx);
__ mov(FieldOperand(ebx, kPointerSize), edx);
@@ -7876,10 +7827,10 @@
TERMINAL_FAST_ELEMENTS_KIND);
for (int i = 0; i <= to_index; ++i) {
ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
- T stub(kind, false);
+ T stub(kind);
stub.GetCode(isolate)->set_is_pregenerated(true);
if (AllocationSiteInfo::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE) {
- T stub1(kind, true);
+ T stub1(kind, CONTEXT_CHECK_REQUIRED, DISABLE_ALLOCATION_SITES);
stub1.GetCode(isolate)->set_is_pregenerated(true);
}
}
@@ -7945,52 +7896,39 @@
__ bind(&okay_here);
}
- if (FLAG_optimize_constructed_arrays) {
- Label no_info, switch_ready;
- // Get the elements kind and case on that.
- __ cmp(ebx, Immediate(undefined_sentinel));
- __ j(equal, &no_info);
- __ mov(edx, FieldOperand(ebx, Cell::kValueOffset));
- __ JumpIfNotSmi(edx, &no_info);
- __ SmiUntag(edx);
- __ jmp(&switch_ready);
- __ bind(&no_info);
- __ mov(edx, Immediate(GetInitialFastElementsKind()));
- __ bind(&switch_ready);
+ Label no_info, switch_ready;
+ // Get the elements kind and case on that.
+ __ cmp(ebx, Immediate(undefined_sentinel));
+ __ j(equal, &no_info);
+ __ mov(edx, FieldOperand(ebx, Cell::kValueOffset));
+ __ JumpIfNotSmi(edx, &no_info);
+ __ SmiUntag(edx);
+ __ jmp(&switch_ready);
+ __ bind(&no_info);
+ __ mov(edx, Immediate(GetInitialFastElementsKind()));
+ __ bind(&switch_ready);
- if (argument_count_ == ANY) {
- Label not_zero_case, not_one_case;
- __ test(eax, eax);
- __ j(not_zero, ¬_zero_case);
- CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm);
+ if (argument_count_ == ANY) {
+ Label not_zero_case, not_one_case;
+ __ test(eax, eax);
+ __ j(not_zero, ¬_zero_case);
+ CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm);
- __ bind(¬_zero_case);
- __ cmp(eax, 1);
- __ j(greater, ¬_one_case);
- CreateArrayDispatchOneArgument(masm);
+ __ bind(¬_zero_case);
+ __ cmp(eax, 1);
+ __ j(greater, ¬_one_case);
+ CreateArrayDispatchOneArgument(masm);
- __ bind(¬_one_case);
- CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm);
- } else if (argument_count_ == NONE) {
- CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm);
- } else if (argument_count_ == ONE) {
- CreateArrayDispatchOneArgument(masm);
- } else if (argument_count_ == MORE_THAN_ONE) {
- CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm);
- } else {
- UNREACHABLE();
- }
+ __ bind(¬_one_case);
+ CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm);
+ } else if (argument_count_ == NONE) {
+ CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm);
+ } else if (argument_count_ == ONE) {
+ CreateArrayDispatchOneArgument(masm);
+ } else if (argument_count_ == MORE_THAN_ONE) {
+ CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm);
} 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);
+ UNREACHABLE();
}
}
@@ -8053,46 +7991,33 @@
__ 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));
+ // 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);
+ // 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;
+ if (FLAG_debug_code) {
+ Label done;
__ 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);
+ __ 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);
}