Update V8 to version 4.1.0.21
This is a cherry-pick of all commits up to and including the
4.1.0.21 cherry-pick in Chromium.
Original commit message:
Version 4.1.0.21 (cherry-pick)
Merged 206e9136bde0f2b5ae8cb77afbb1e7833e5bd412
Unlink pages from the space page list after evacuation.
BUG=430201
LOG=N
R=jkummerow@chromium.org
Review URL: https://codereview.chromium.org/953813002
Cr-Commit-Position: refs/branch-heads/4.1@{#22}
Cr-Branched-From: 2e08d2a7aa9d65d269d8c57aba82eb38a8cb0a18-refs/heads/candidates@{#25353}
---
FPIIM-449
Change-Id: I8c23c7bbb70772b4858fe8a47b64fa97ee0d1f8c
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index 25270d1..ef286bb 100644
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -15,7 +15,7 @@
#include "src/isolate.h"
#include "src/jsregexp.h"
#include "src/regexp-macro-assembler.h"
-#include "src/runtime.h"
+#include "src/runtime/runtime.h"
namespace v8 {
namespace internal {
@@ -234,61 +234,6 @@
}
-void WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime(
- Isolate* isolate) {
- WriteInt32ToHeapNumberStub stub1(isolate, r1, r0, r2);
- WriteInt32ToHeapNumberStub stub2(isolate, r2, r0, r3);
- stub1.GetCode();
- stub2.GetCode();
-}
-
-
-// See comment for class.
-void WriteInt32ToHeapNumberStub::Generate(MacroAssembler* masm) {
- Label max_negative_int;
- // the_int_ has the answer which is a signed int32 but not a Smi.
- // We test for the special value that has a different exponent. This test
- // has the neat side effect of setting the flags according to the sign.
- STATIC_ASSERT(HeapNumber::kSignMask == 0x80000000u);
- __ cmp(the_int(), Operand(0x80000000u));
- __ b(eq, &max_negative_int);
- // Set up the correct exponent in scratch_. All non-Smi int32s have the same.
- // A non-Smi integer is 1.xxx * 2^30 so the exponent is 30 (biased).
- uint32_t non_smi_exponent =
- (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift;
- __ mov(scratch(), Operand(non_smi_exponent));
- // Set the sign bit in scratch_ if the value was negative.
- __ orr(scratch(), scratch(), Operand(HeapNumber::kSignMask), LeaveCC, cs);
- // Subtract from 0 if the value was negative.
- __ rsb(the_int(), the_int(), Operand::Zero(), LeaveCC, cs);
- // We should be masking the implict first digit of the mantissa away here,
- // but it just ends up combining harmlessly with the last digit of the
- // exponent that happens to be 1. The sign bit is 0 so we shift 10 to get
- // the most significant 1 to hit the last bit of the 12 bit sign and exponent.
- DCHECK(((1 << HeapNumber::kExponentShift) & non_smi_exponent) != 0);
- const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2;
- __ orr(scratch(), scratch(), Operand(the_int(), LSR, shift_distance));
- __ str(scratch(),
- FieldMemOperand(the_heap_number(), HeapNumber::kExponentOffset));
- __ mov(scratch(), Operand(the_int(), LSL, 32 - shift_distance));
- __ str(scratch(),
- FieldMemOperand(the_heap_number(), HeapNumber::kMantissaOffset));
- __ Ret();
-
- __ bind(&max_negative_int);
- // The max negative int32 is stored as a positive number in the mantissa of
- // a double because it uses a sign bit instead of using two's complement.
- // The actual mantissa bits stored are all 0 because the implicit most
- // significant 1 bit is not stored.
- non_smi_exponent += 1 << HeapNumber::kExponentShift;
- __ mov(ip, Operand(HeapNumber::kSignMask | non_smi_exponent));
- __ str(ip, FieldMemOperand(the_heap_number(), HeapNumber::kExponentOffset));
- __ mov(ip, Operand::Zero());
- __ str(ip, FieldMemOperand(the_heap_number(), HeapNumber::kMantissaOffset));
- __ Ret();
-}
-
-
// Handle the case where the lhs and rhs are the same object.
// Equality is almost reflexive (everything but NaN), so this is a test
// for "identity and not NaN".
@@ -967,7 +912,6 @@
void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
CEntryStub::GenerateAheadOfTime(isolate);
- WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime(isolate);
StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate);
StubFailureTrampolineStub::GenerateAheadOfTime(isolate);
ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
@@ -1441,7 +1385,7 @@
__ b(ne, &slow);
// Null is not instance of anything.
- __ cmp(scratch, Operand(isolate()->factory()->null_value()));
+ __ cmp(object, Operand(isolate()->factory()->null_value()));
__ b(ne, &object_not_null);
if (ReturnTrueFalseObject()) {
__ Move(r0, factory->false_value());
@@ -1494,15 +1438,54 @@
void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
Label miss;
Register receiver = LoadDescriptor::ReceiverRegister();
+ // Ensure that the vector and slot registers won't be clobbered before
+ // calling the miss handler.
+ DCHECK(!FLAG_vector_ics ||
+ !AreAliased(r4, r5, VectorLoadICDescriptor::VectorRegister(),
+ VectorLoadICDescriptor::SlotRegister()));
- NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(masm, receiver, r3,
- r4, &miss);
+ NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(masm, receiver, r4,
+ r5, &miss);
__ bind(&miss);
PropertyAccessCompiler::TailCallBuiltin(
masm, PropertyAccessCompiler::MissBuiltin(Code::LOAD_IC));
}
+void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
+ // Return address is in lr.
+ Label miss;
+
+ Register receiver = LoadDescriptor::ReceiverRegister();
+ Register index = LoadDescriptor::NameRegister();
+ Register scratch = r5;
+ Register result = r0;
+ DCHECK(!scratch.is(receiver) && !scratch.is(index));
+ DCHECK(!FLAG_vector_ics ||
+ (!scratch.is(VectorLoadICDescriptor::VectorRegister()) &&
+ result.is(VectorLoadICDescriptor::SlotRegister())));
+
+ // StringCharAtGenerator doesn't use the result register until it's passed
+ // the different miss possibilities. If it did, we would have a conflict
+ // when FLAG_vector_ics is true.
+ StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
+ &miss, // When not a string.
+ &miss, // When not a number.
+ &miss, // When index out of range.
+ STRING_INDEX_IS_ARRAY_INDEX,
+ RECEIVER_IS_STRING);
+ char_at_generator.GenerateFast(masm);
+ __ Ret();
+
+ StubRuntimeCallHelper call_helper;
+ char_at_generator.GenerateSlow(masm, call_helper);
+
+ __ bind(&miss);
+ PropertyAccessCompiler::TailCallBuiltin(
+ masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC));
+}
+
+
void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
// The displacement is the offset of the last parameter (if any)
// relative to the frame pointer.
@@ -2376,13 +2359,13 @@
// A monomorphic miss (i.e, here the cache is not uninitialized) goes
// megamorphic.
- __ CompareRoot(r4, Heap::kUninitializedSymbolRootIndex);
+ __ CompareRoot(r4, Heap::kuninitialized_symbolRootIndex);
__ b(eq, &initialize);
// MegamorphicSentinel is an immortal immovable object (undefined) so no
// write-barrier is needed.
__ bind(&megamorphic);
__ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3));
- __ LoadRoot(ip, Heap::kMegamorphicSymbolRootIndex);
+ __ LoadRoot(ip, Heap::kmegamorphic_symbolRootIndex);
__ str(ip, FieldMemOperand(r4, FixedArray::kHeaderSize));
__ jmp(&done);
@@ -2658,6 +2641,10 @@
void CallICStub::Generate(MacroAssembler* masm) {
// r1 - function
// r3 - slot id (Smi)
+ const int with_types_offset =
+ FixedArray::OffsetOfElementAt(TypeFeedbackVector::kWithTypesIndex);
+ const int generic_offset =
+ FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
Label extra_checks_or_miss, slow_start;
Label slow, non_function, wrap, cont;
Label have_js_function;
@@ -2696,26 +2683,70 @@
}
__ bind(&extra_checks_or_miss);
- Label miss;
+ Label uninitialized, miss;
- __ CompareRoot(r4, Heap::kMegamorphicSymbolRootIndex);
+ __ CompareRoot(r4, Heap::kmegamorphic_symbolRootIndex);
__ b(eq, &slow_start);
- __ CompareRoot(r4, Heap::kUninitializedSymbolRootIndex);
- __ b(eq, &miss);
- if (!FLAG_trace_ic) {
- // We are going megamorphic. If the feedback is a JSFunction, it is fine
- // to handle it here. More complex cases are dealt with in the runtime.
- __ AssertNotSmi(r4);
- __ CompareObjectType(r4, r5, r5, JS_FUNCTION_TYPE);
- __ b(ne, &miss);
- __ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3));
- __ LoadRoot(ip, Heap::kMegamorphicSymbolRootIndex);
- __ str(ip, FieldMemOperand(r4, FixedArray::kHeaderSize));
- __ jmp(&slow_start);
+ // The following cases attempt to handle MISS cases without going to the
+ // runtime.
+ if (FLAG_trace_ic) {
+ __ jmp(&miss);
}
- // We are here because tracing is on or we are going monomorphic.
+ __ CompareRoot(r4, Heap::kuninitialized_symbolRootIndex);
+ __ b(eq, &uninitialized);
+
+ // We are going megamorphic. If the feedback is a JSFunction, it is fine
+ // to handle it here. More complex cases are dealt with in the runtime.
+ __ AssertNotSmi(r4);
+ __ CompareObjectType(r4, r5, r5, JS_FUNCTION_TYPE);
+ __ b(ne, &miss);
+ __ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3));
+ __ LoadRoot(ip, Heap::kmegamorphic_symbolRootIndex);
+ __ str(ip, FieldMemOperand(r4, FixedArray::kHeaderSize));
+ // We have to update statistics for runtime profiling.
+ __ ldr(r4, FieldMemOperand(r2, with_types_offset));
+ __ sub(r4, r4, Operand(Smi::FromInt(1)));
+ __ str(r4, FieldMemOperand(r2, with_types_offset));
+ __ ldr(r4, FieldMemOperand(r2, generic_offset));
+ __ add(r4, r4, Operand(Smi::FromInt(1)));
+ __ str(r4, FieldMemOperand(r2, generic_offset));
+ __ jmp(&slow_start);
+
+ __ bind(&uninitialized);
+
+ // We are going monomorphic, provided we actually have a JSFunction.
+ __ JumpIfSmi(r1, &miss);
+
+ // Goto miss case if we do not have a function.
+ __ CompareObjectType(r1, r4, r4, JS_FUNCTION_TYPE);
+ __ b(ne, &miss);
+
+ // Make sure the function is not the Array() function, which requires special
+ // behavior on MISS.
+ __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, r4);
+ __ cmp(r1, r4);
+ __ b(eq, &miss);
+
+ // Update stats.
+ __ ldr(r4, FieldMemOperand(r2, with_types_offset));
+ __ add(r4, r4, Operand(Smi::FromInt(1)));
+ __ str(r4, FieldMemOperand(r2, with_types_offset));
+
+ // Store the function.
+ __ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3));
+ __ add(r4, r4, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+ __ str(r1, MemOperand(r4, 0));
+
+ // Update the write barrier.
+ __ mov(r5, r1);
+ __ RecordWrite(r2, r4, r5, kLRHasNotBeenSaved, kDontSaveFPRegs,
+ EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
+ __ jmp(&have_js_function);
+
+ // We are here because tracing is on or we encountered a MISS case we can't
+ // handle here.
__ bind(&miss);
GenerateMiss(masm);
@@ -2759,14 +2790,16 @@
// StringCharCodeAtGenerator
void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
// If the receiver is a smi trigger the non-string case.
- __ JumpIfSmi(object_, receiver_not_string_);
+ if (check_mode_ == RECEIVER_IS_UNKNOWN) {
+ __ JumpIfSmi(object_, receiver_not_string_);
- // Fetch the instance type of the receiver into result register.
- __ ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset));
- __ ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset));
- // If the receiver is not a string trigger the non-string case.
- __ tst(result_, Operand(kIsNotStringMask));
- __ b(ne, receiver_not_string_);
+ // Fetch the instance type of the receiver into result register.
+ __ ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset));
+ __ ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset));
+ // If the receiver is not a string trigger the non-string case.
+ __ tst(result_, Operand(kIsNotStringMask));
+ __ b(ne, receiver_not_string_);
+ }
// If the index is non-smi trigger the non-smi case.
__ JumpIfNotSmi(index_, &index_not_smi_);
@@ -3137,8 +3170,8 @@
// r2: length
// r3: from index (untagged)
__ SmiTag(r3, r3);
- StringCharAtGenerator generator(
- r0, r3, r2, r0, &runtime, &runtime, &runtime, STRING_INDEX_IS_NUMBER);
+ StringCharAtGenerator generator(r0, r3, r2, r0, &runtime, &runtime, &runtime,
+ STRING_INDEX_IS_NUMBER, RECEIVER_IS_STRING);
generator.GenerateFast(masm);
__ Drop(3);
__ Ret();
@@ -3146,6 +3179,49 @@
}
+void ToNumberStub::Generate(MacroAssembler* masm) {
+ // The ToNumber stub takes one argument in r0.
+ Label not_smi;
+ __ JumpIfNotSmi(r0, ¬_smi);
+ __ Ret();
+ __ bind(¬_smi);
+
+ Label not_heap_number;
+ __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
+ __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
+ // r0: object
+ // r1: instance type.
+ __ cmp(r1, Operand(HEAP_NUMBER_TYPE));
+ __ b(ne, ¬_heap_number);
+ __ Ret();
+ __ bind(¬_heap_number);
+
+ Label not_string, slow_string;
+ __ cmp(r1, Operand(FIRST_NONSTRING_TYPE));
+ __ b(hs, ¬_string);
+ // Check if string has a cached array index.
+ __ ldr(r2, FieldMemOperand(r0, String::kHashFieldOffset));
+ __ tst(r2, Operand(String::kContainsCachedArrayIndexMask));
+ __ b(ne, &slow_string);
+ __ IndexFromHash(r2, r0);
+ __ Ret();
+ __ bind(&slow_string);
+ __ push(r0); // Push argument.
+ __ TailCallRuntime(Runtime::kStringToNumber, 1, 1);
+ __ bind(¬_string);
+
+ Label not_oddball;
+ __ cmp(r1, Operand(ODDBALL_TYPE));
+ __ b(ne, ¬_oddball);
+ __ ldr(r0, FieldMemOperand(r0, Oddball::kToNumberOffset));
+ __ Ret();
+ __ bind(¬_oddball);
+
+ __ push(r0); // Push argument.
+ __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION);
+}
+
+
void StringHelper::GenerateFlatOneByteStringEquals(
MacroAssembler* masm, Register left, Register right, Register scratch1,
Register scratch2, Register scratch3) {