From 0c2e5ec840e2dc64585ea75f7539d87e5af4269e Mon Sep 17 00:00:00 2001 From: isaacs Date: Fri, 8 Feb 2013 17:17:45 -0800 Subject: [PATCH] V8: Upgrade to 3.15.11.15 --- deps/v8/build/common.gypi | 11 +- deps/v8/src/compiler.cc | 2 +- deps/v8/src/hydrogen.cc | 2 + deps/v8/src/log-utils.cc | 3 - deps/v8/src/mark-compact.cc | 36 ++++- deps/v8/src/mark-compact.h | 1 + deps/v8/src/messages.js | 1 + deps/v8/src/mips/codegen-mips.cc | 10 +- deps/v8/src/mips/lithium-codegen-mips.cc | 2 +- deps/v8/src/objects-inl.h | 20 ++- deps/v8/src/objects.cc | 2 +- deps/v8/src/objects.h | 2 +- deps/v8/src/platform-posix.cc | 17 +-- deps/v8/src/runtime.cc | 21 ++- deps/v8/src/string.js | 21 ++- deps/v8/src/v8utils.h | 2 - deps/v8/src/version.cc | 2 +- deps/v8/test/cctest/test-heap.cc | 125 ++++++++++++++++++ deps/v8/test/mjsunit/regress/regress-2437.js | 81 ++++++++++++ deps/v8/test/mjsunit/regress/regress-2499.js | 40 ++++++ .../mjsunit/regress/regress-crbug-170856.js | 33 +++++ 21 files changed, 379 insertions(+), 55 deletions(-) create mode 100644 deps/v8/test/mjsunit/regress/regress-2499.js create mode 100644 deps/v8/test/mjsunit/regress/regress-crbug-170856.js diff --git a/deps/v8/build/common.gypi b/deps/v8/build/common.gypi index 44bebae935..e68ee15fde 100644 --- a/deps/v8/build/common.gypi +++ b/deps/v8/build/common.gypi @@ -160,7 +160,7 @@ [ 'v8_use_arm_eabi_hardfloat=="true"', { 'defines': [ 'USE_EABI_HARDFLOAT=1', - 'CAN_USE_VFP2_INSTRUCTIONS', + 'CAN_USE_VFP3_INSTRUCTIONS', ], 'target_conditions': [ ['_toolset=="target"', { @@ -399,6 +399,15 @@ }], ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd" \ or OS=="android"', { + 'cflags!': [ + '-O2', + '-Os', + ], + 'cflags': [ + '-fdata-sections', + '-ffunction-sections', + '-O3', + ], 'conditions': [ [ 'gcc_version==44 and clang==0', { 'cflags': [ diff --git a/deps/v8/src/compiler.cc b/deps/v8/src/compiler.cc index 5779aae81b..7e4eaa2b3b 100644 --- a/deps/v8/src/compiler.cc +++ b/deps/v8/src/compiler.cc @@ -697,7 +697,7 @@ static bool InstallFullCode(CompilationInfo* info) { Handle scope_info = ScopeInfo::Create(info->scope(), info->zone()); shared->set_scope_info(*scope_info); - shared->set_code(*code); + shared->ReplaceCode(*code); if (!function.is_null()) { function->ReplaceCode(*code); ASSERT(!function->IsOptimized()); diff --git a/deps/v8/src/hydrogen.cc b/deps/v8/src/hydrogen.cc index bdca43ed52..aad9da3e75 100644 --- a/deps/v8/src/hydrogen.cc +++ b/deps/v8/src/hydrogen.cc @@ -8306,6 +8306,7 @@ static bool ShiftAmountsAllowReplaceByRotate(HValue* sa, HValue* const32_minus_sa) { if (!const32_minus_sa->IsSub()) return false; HSub* sub = HSub::cast(const32_minus_sa); + if (sa != sub->right()) return false; HValue* const32 = sub->left(); if (!const32->IsConstant() || HConstant::cast(const32)->Integer32Value() != 32) { @@ -8334,6 +8335,7 @@ bool HGraphBuilder::MatchRotateRight(HValue* left, } else { return false; } + if (shl->left() != shr->left()) return false; if (!ShiftAmountsAllowReplaceByRotate(shl->right(), shr->right()) && !ShiftAmountsAllowReplaceByRotate(shr->right(), shl->right())) { diff --git a/deps/v8/src/log-utils.cc b/deps/v8/src/log-utils.cc index a66db3d931..d8d92cbe21 100644 --- a/deps/v8/src/log-utils.cc +++ b/deps/v8/src/log-utils.cc @@ -107,9 +107,6 @@ void Log::Initialize() { // one character so we can escape the loop properly. p--; break; - case 'p': - stream.Add("%d", OS::GetCurrentProcessId()); - break; case 't': { // %t expands to the current time in milliseconds. double time = OS::TimeCurrentMillis(); diff --git a/deps/v8/src/mark-compact.cc b/deps/v8/src/mark-compact.cc index 8ca14db506..4e6599f09f 100644 --- a/deps/v8/src/mark-compact.cc +++ b/deps/v8/src/mark-compact.cc @@ -885,8 +885,8 @@ void CodeFlusher::ProcessJSFunctionCandidates() { if (!code_mark.Get()) { shared->set_code(lazy_compile); candidate->set_code(lazy_compile); - } else if (code == lazy_compile) { - candidate->set_code(lazy_compile); + } else { + candidate->set_code(code); } // We are in the middle of a GC cycle so the write barrier in the code @@ -935,13 +935,40 @@ void CodeFlusher::ProcessSharedFunctionInfoCandidates() { } +void CodeFlusher::EvictCandidate(SharedFunctionInfo* shared_info) { + // Make sure previous flushing decisions are revisited. + isolate_->heap()->incremental_marking()->RecordWrites(shared_info); + + SharedFunctionInfo* candidate = shared_function_info_candidates_head_; + SharedFunctionInfo* next_candidate; + if (candidate == shared_info) { + next_candidate = GetNextCandidate(shared_info); + shared_function_info_candidates_head_ = next_candidate; + ClearNextCandidate(shared_info); + } else { + while (candidate != NULL) { + next_candidate = GetNextCandidate(candidate); + + if (next_candidate == shared_info) { + next_candidate = GetNextCandidate(shared_info); + SetNextCandidate(candidate, next_candidate); + ClearNextCandidate(shared_info); + break; + } + + candidate = next_candidate; + } + } +} + + void CodeFlusher::EvictCandidate(JSFunction* function) { ASSERT(!function->next_function_link()->IsUndefined()); Object* undefined = isolate_->heap()->undefined_value(); - // The function is no longer a candidate, make sure it gets visited - // again so that previous flushing decisions are revisited. + // Make sure previous flushing decisions are revisited. isolate_->heap()->incremental_marking()->RecordWrites(function); + isolate_->heap()->incremental_marking()->RecordWrites(function->shared()); JSFunction* candidate = jsfunction_candidates_head_; JSFunction* next_candidate; @@ -957,6 +984,7 @@ void CodeFlusher::EvictCandidate(JSFunction* function) { next_candidate = GetNextCandidate(function); SetNextCandidate(candidate, next_candidate); ClearNextCandidate(function, undefined); + break; } candidate = next_candidate; diff --git a/deps/v8/src/mark-compact.h b/deps/v8/src/mark-compact.h index 9a0b014d63..8821c3df30 100644 --- a/deps/v8/src/mark-compact.h +++ b/deps/v8/src/mark-compact.h @@ -434,6 +434,7 @@ class CodeFlusher { } } + void EvictCandidate(SharedFunctionInfo* shared_info); void EvictCandidate(JSFunction* function); void ProcessCandidates() { diff --git a/deps/v8/src/messages.js b/deps/v8/src/messages.js index 0a50ae7861..f0c51c61f2 100644 --- a/deps/v8/src/messages.js +++ b/deps/v8/src/messages.js @@ -1090,6 +1090,7 @@ function captureStackTrace(obj, cons_opt) { // with a data property as soon as the stack trace has been formatted. var getter = function() { var value = FormatRawStackTrace(obj, raw_stack); + raw_stack = void 0; %DefineOrRedefineDataProperty(obj, 'stack', value, NONE); return value; }; diff --git a/deps/v8/src/mips/codegen-mips.cc b/deps/v8/src/mips/codegen-mips.cc index 1da8089635..db313e10ee 100644 --- a/deps/v8/src/mips/codegen-mips.cc +++ b/deps/v8/src/mips/codegen-mips.cc @@ -529,9 +529,9 @@ void SeqStringSetCharGenerator::Generate(MacroAssembler* masm, __ Check(eq, "Non-smi value", at, Operand(zero_reg)); __ lw(at, FieldMemOperand(string, String::kLengthOffset)); - __ Check(lt, "Index is too large", at, Operand(index)); + __ Check(lt, "Index is too large", index, Operand(at)); - __ Check(ge, "Index is negative", index, Operand(Smi::FromInt(0))); + __ Check(ge, "Index is negative", index, Operand(zero_reg)); __ lw(at, FieldMemOperand(string, HeapObject::kMapOffset)); __ lbu(at, FieldMemOperand(at, Map::kInstanceTypeOffset)); @@ -539,9 +539,9 @@ void SeqStringSetCharGenerator::Generate(MacroAssembler* masm, __ And(at, at, Operand(kStringRepresentationMask | kStringEncodingMask)); static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag; static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; - __ Check(eq, "Unexpected string type", at, - Operand(encoding == String::ONE_BYTE_ENCODING - ? one_byte_seq_type : two_byte_seq_type)); + __ Subu(at, at, Operand(encoding == String::ONE_BYTE_ENCODING + ? one_byte_seq_type : two_byte_seq_type)); + __ Check(eq, "Unexpected string type", at, Operand(zero_reg)); } __ Addu(at, diff --git a/deps/v8/src/mips/lithium-codegen-mips.cc b/deps/v8/src/mips/lithium-codegen-mips.cc index fd7af9f0f5..cc589e0b30 100644 --- a/deps/v8/src/mips/lithium-codegen-mips.cc +++ b/deps/v8/src/mips/lithium-codegen-mips.cc @@ -4016,7 +4016,7 @@ void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { __ Branch(¬_applicable, ne, scratch, Operand(from_map)); __ li(new_map_reg, Operand(to_map)); - if (IsFastSmiElementsKind(from_kind) && IsFastObjectElementsKind(to_kind)) { + if (IsSimpleMapChangeTransition(from_kind, to_kind)) { __ sw(new_map_reg, FieldMemOperand(object_reg, HeapObject::kMapOffset)); // Write barrier. __ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg, diff --git a/deps/v8/src/objects-inl.h b/deps/v8/src/objects-inl.h index 67db5b4944..1d9c87f0ef 100644 --- a/deps/v8/src/objects-inl.h +++ b/deps/v8/src/objects-inl.h @@ -4368,6 +4368,19 @@ void SharedFunctionInfo::set_code(Code* value, WriteBarrierMode mode) { } +void SharedFunctionInfo::ReplaceCode(Code* value) { + // If the GC metadata field is already used then the function was + // enqueued as a code flushing candidate and we remove it now. + if (code()->gc_metadata() != NULL) { + CodeFlusher* flusher = GetHeap()->mark_compact_collector()->code_flusher(); + flusher->EvictCandidate(this); + } + + ASSERT(code()->gc_metadata() == NULL && value->gc_metadata() == NULL); + set_code(value); +} + + ScopeInfo* SharedFunctionInfo::scope_info() { return reinterpret_cast(READ_FIELD(this, kScopeInfoOffset)); } @@ -4955,13 +4968,6 @@ void JSRegExp::SetDataAtUnchecked(int index, Object* value, Heap* heap) { } -void JSRegExp::ResetLastIndex() { - InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex, - Smi::FromInt(0), - SKIP_WRITE_BARRIER); // It's a Smi. -} - - ElementsKind JSObject::GetElementsKind() { ElementsKind kind = map()->elements_kind(); #if DEBUG diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc index 885a5dd8b2..126d1e0fd7 100644 --- a/deps/v8/src/objects.cc +++ b/deps/v8/src/objects.cc @@ -8562,7 +8562,7 @@ void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) { // old code, we have to replace it. We should try to avoid this // altogether because it flushes valuable type feedback by // effectively resetting all IC state. - set_code(recompiled); + ReplaceCode(recompiled); } ASSERT(has_deoptimization_support()); } diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h index 6c9b31b937..0be263a488 100644 --- a/deps/v8/src/objects.h +++ b/deps/v8/src/objects.h @@ -5429,6 +5429,7 @@ class SharedFunctionInfo: public HeapObject { // [code]: Function code. DECL_ACCESSORS(code, Code) + inline void ReplaceCode(Code* code); // [optimized_code_map]: Map from native context to optimized code // and a shared literals array or Smi 0 if none. @@ -6648,7 +6649,6 @@ class JSRegExp: public JSObject { inline Object* DataAtUnchecked(int index); inline void SetDataAtUnchecked(int index, Object* value, Heap* heap); inline Type TypeTagUnchecked(); - inline void ResetLastIndex(); static int code_index(bool is_ascii) { if (is_ascii) { diff --git a/deps/v8/src/platform-posix.cc b/deps/v8/src/platform-posix.cc index e652a083cd..0016d59d3a 100644 --- a/deps/v8/src/platform-posix.cc +++ b/deps/v8/src/platform-posix.cc @@ -109,20 +109,11 @@ void* OS::GetRandomMmapAddr() { raw_addr &= V8_UINT64_C(0x3ffffffff000); #else uint32_t raw_addr = V8::RandomPrivate(isolate); - - // For our 32-bit mmap() hint, we pick a random address in the bottom - // half of the top half of the address space (that is, the third quarter). - // Because we do not MAP_FIXED, this will be treated only as a hint -- the - // system will not fail to mmap() because something else happens to already - // be mapped at our random address. We deliberately set the hint high enough - // to get well above the system's break (that is, the heap); systems will - // either try the hint and if that fails move higher (MacOS and other BSD - // derivatives) or try the hint and if that fails allocate as if there were - // no hint at all (Linux, Solaris, illumos and derivatives). The high hint - // prevents the break from getting hemmed in at low values, ceding half of - // the address space to the system heap. + // The range 0x20000000 - 0x60000000 is relatively unpopulated across a + // variety of ASLR modes (PAE kernel, NX compat mode, etc) and on macos + // 10.6 and 10.7. raw_addr &= 0x3ffff000; - raw_addr += 0x80000000; + raw_addr += 0x20000000; #endif return reinterpret_cast(raw_addr); } diff --git a/deps/v8/src/runtime.cc b/deps/v8/src/runtime.cc index 446443148d..09ca04706d 100644 --- a/deps/v8/src/runtime.cc +++ b/deps/v8/src/runtime.cc @@ -1098,14 +1098,15 @@ static MaybeObject* GetOwnProperty(Isolate* isolate, PropertyAttributes attrs = obj->GetLocalPropertyAttribute(*name); if (attrs == ABSENT) return heap->undefined_value(); - AccessorPair* accessors = obj->GetLocalPropertyAccessorPair(*name); + AccessorPair* raw_accessors = obj->GetLocalPropertyAccessorPair(*name); + Handle accessors(raw_accessors, isolate); Handle elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE); elms->set(ENUMERABLE_INDEX, heap->ToBoolean((attrs & DONT_ENUM) == 0)); elms->set(CONFIGURABLE_INDEX, heap->ToBoolean((attrs & DONT_DELETE) == 0)); - elms->set(IS_ACCESSOR_INDEX, heap->ToBoolean(accessors != NULL)); + elms->set(IS_ACCESSOR_INDEX, heap->ToBoolean(raw_accessors != NULL)); - if (accessors == NULL) { + if (raw_accessors == NULL) { elms->set(WRITABLE_INDEX, heap->ToBoolean((attrs & READ_ONLY) == 0)); // GetProperty does access check. Handle value = GetProperty(obj, name); @@ -1790,7 +1791,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) { JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER); regexp->InObjectPropertyAtPut( JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER); - regexp->ResetLastIndex(); + regexp->InObjectPropertyAtPut( + JSRegExp::kLastIndexFieldIndex, Smi::FromInt(0), SKIP_WRITE_BARRIER); return regexp; } @@ -2145,7 +2147,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) { // target function to undefined. SetCode is only used for built-in // constructors like String, Array, and Object, and some web code // doesn't like seeing source code for constructors. - target_shared->set_code(source_shared->code()); + target_shared->ReplaceCode(source_shared->code()); target_shared->set_scope_info(source_shared->scope_info()); target_shared->set_length(source_shared->length()); target_shared->set_formal_parameter_count( @@ -2903,8 +2905,7 @@ MUST_USE_RESULT static MaybeObject* StringReplaceAtomRegExpWithString( int matches = indices.length(); if (matches == 0) { - pattern_regexp->ResetLastIndex(); - return *subject; + return isolate->heap()->undefined_value(); } // Detect integer overflow. @@ -3005,8 +3006,7 @@ MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString( int32_t* current_match = global_cache.FetchNext(); if (current_match == NULL) { if (global_cache.HasException()) return Failure::Exception(); - regexp->ResetLastIndex(); - return *subject; + return isolate->heap()->undefined_value(); } // Guessing the number of parts that the final result string is built @@ -3104,8 +3104,7 @@ MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString( int32_t* current_match = global_cache.FetchNext(); if (current_match == NULL) { if (global_cache.HasException()) return Failure::Exception(); - regexp->ResetLastIndex(); - return *subject; + return isolate->heap()->undefined_value(); } int start = current_match[0]; diff --git a/deps/v8/src/string.js b/deps/v8/src/string.js index d9ca035fb5..eb9aa35486 100644 --- a/deps/v8/src/string.js +++ b/deps/v8/src/string.js @@ -194,6 +194,7 @@ function StringMatch(regexp) { // lastMatchInfo is defined in regexp.js. var result = %StringMatch(subject, regexp, lastMatchInfo); if (result !== null) lastMatchInfoOverride = null; + regexp.lastIndex = 0; return result; } // Non-regexp argument. @@ -244,10 +245,16 @@ function StringReplace(search, replace) { } } else { if (lastMatchInfoOverride == null) { - return %StringReplaceRegExpWithString(subject, - search, - TO_STRING_INLINE(replace), - lastMatchInfo); + var answer = %StringReplaceRegExpWithString(subject, + search, + TO_STRING_INLINE(replace), + lastMatchInfo); + if (IS_UNDEFINED(answer)) { // No match. Return subject string. + search.lastIndex = 0; + return subject; + } + if (search.global) search.lastIndex = 0; + return answer; } else { // We use this hack to detect whether StringReplaceRegExpWithString // found at least one hit. In that case we need to remove any @@ -258,11 +265,17 @@ function StringReplace(search, replace) { search, TO_STRING_INLINE(replace), lastMatchInfo); + if (IS_UNDEFINED(answer)) { // No match. Return subject string. + search.lastIndex = 0; + lastMatchInfo[LAST_SUBJECT_INDEX] = saved_subject; + return subject; + } if (%_IsSmi(lastMatchInfo[LAST_SUBJECT_INDEX])) { lastMatchInfo[LAST_SUBJECT_INDEX] = saved_subject; } else { lastMatchInfoOverride = null; } + if (search.global) search.lastIndex = 0; return answer; } } diff --git a/deps/v8/src/v8utils.h b/deps/v8/src/v8utils.h index 111abdf8b8..9072b4e285 100644 --- a/deps/v8/src/v8utils.h +++ b/deps/v8/src/v8utils.h @@ -209,8 +209,6 @@ INLINE(void CopyChars(sinkchar* dest, const sourcechar* src, int chars)); template void CopyChars(sinkchar* dest, const sourcechar* src, int chars) { - ASSERT(chars >= 0); - if (chars == 0) return; sinkchar* limit = dest + chars; #ifdef V8_HOST_CAN_READ_UNALIGNED if (sizeof(*dest) == sizeof(*src)) { diff --git a/deps/v8/src/version.cc b/deps/v8/src/version.cc index 7d317418d8..31d93d6780 100644 --- a/deps/v8/src/version.cc +++ b/deps/v8/src/version.cc @@ -35,7 +35,7 @@ #define MAJOR_VERSION 3 #define MINOR_VERSION 15 #define BUILD_NUMBER 11 -#define PATCH_LEVEL 10 +#define PATCH_LEVEL 15 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) #define IS_CANDIDATE_VERSION 0 diff --git a/deps/v8/test/cctest/test-heap.cc b/deps/v8/test/cctest/test-heap.cc index 93ac211687..533a1c3ef1 100644 --- a/deps/v8/test/cctest/test-heap.cc +++ b/deps/v8/test/cctest/test-heap.cc @@ -2575,3 +2575,128 @@ TEST(Regress159140) { // Unoptimized code is missing and the deoptimizer will go ballistic. CompileRun("g('bozo');"); } + + +TEST(Regress169209) { + i::FLAG_allow_natives_syntax = true; + i::FLAG_flush_code_incrementally = true; + InitializeVM(); + v8::HandleScope scope; + + // Perform one initial GC to enable code flushing. + HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); + + // Prepare a shared function info eligible for code flushing for which + // the unoptimized code will be replaced during optimization. + Handle shared1; + { + HandleScope inner_scope; + CompileRun("function f() { return 'foobar'; }" + "function g(x) { if (x) f(); }" + "f();" + "g(false);" + "g(false);"); + + Handle f = + v8::Utils::OpenHandle( + *v8::Handle::Cast( + v8::Context::GetCurrent()->Global()->Get(v8_str("f")))); + CHECK(f->is_compiled()); + const int kAgingThreshold = 6; + for (int i = 0; i < kAgingThreshold; i++) { + f->shared()->code()->MakeOlder(static_cast(i % 2)); + } + + shared1 = inner_scope.CloseAndEscape(handle(f->shared(), ISOLATE)); + } + + // Prepare a shared function info eligible for code flushing that will + // represent the dangling tail of the candidate list. + Handle shared2; + { + HandleScope inner_scope; + CompileRun("function flushMe() { return 0; }" + "flushMe(1);"); + + Handle f = + v8::Utils::OpenHandle( + *v8::Handle::Cast( + v8::Context::GetCurrent()->Global()->Get(v8_str("flushMe")))); + CHECK(f->is_compiled()); + const int kAgingThreshold = 6; + for (int i = 0; i < kAgingThreshold; i++) { + f->shared()->code()->MakeOlder(static_cast(i % 2)); + } + + shared2 = inner_scope.CloseAndEscape(handle(f->shared(), ISOLATE)); + } + + // Simulate incremental marking and collect code flushing candidates. + SimulateIncrementalMarking(); + CHECK(shared1->code()->gc_metadata() != NULL); + + // Optimize function and make sure the unoptimized code is replaced. +#ifdef DEBUG + FLAG_stop_at = "f"; +#endif + CompileRun("%OptimizeFunctionOnNextCall(g);" + "g(false);"); + + // Finish garbage collection cycle. + HEAP->CollectAllGarbage(Heap::kNoGCFlags); + CHECK(shared1->code()->gc_metadata() == NULL); +} + + +TEST(Regress168801) { + i::FLAG_always_compact = true; + i::FLAG_cache_optimized_code = false; + i::FLAG_allow_natives_syntax = true; + i::FLAG_flush_code_incrementally = true; + InitializeVM(); + v8::HandleScope scope; + + // Perform one initial GC to enable code flushing. + HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); + + // Ensure the code ends up on an evacuation candidate. + SimulateFullSpace(HEAP->code_space()); + + // Prepare an unoptimized function that is eligible for code flushing. + Handle function; + { + HandleScope inner_scope; + CompileRun("function mkClosure() {" + " return function(x) { return x + 1; };" + "}" + "var f = mkClosure();" + "f(1); f(2);"); + + Handle f = + v8::Utils::OpenHandle( + *v8::Handle::Cast( + v8::Context::GetCurrent()->Global()->Get(v8_str("f")))); + CHECK(f->is_compiled()); + const int kAgingThreshold = 6; + for (int i = 0; i < kAgingThreshold; i++) { + f->shared()->code()->MakeOlder(static_cast(i % 2)); + } + + function = inner_scope.CloseAndEscape(handle(*f, ISOLATE)); + } + + // Simulate incremental marking so that unoptimized function is enqueued as a + // candidate for code flushing. The shared function info however will not be + // explicitly enqueued. + SimulateIncrementalMarking(); + + // Now optimize the function so that it is taken off the candidate list. + { + HandleScope inner_scope; + CompileRun("%OptimizeFunctionOnNextCall(f); f(3);"); + } + + // This cycle will bust the heap and subsequent cycles will go ballistic. + HEAP->CollectAllGarbage(Heap::kNoGCFlags); + HEAP->CollectAllGarbage(Heap::kNoGCFlags); +} diff --git a/deps/v8/test/mjsunit/regress/regress-2437.js b/deps/v8/test/mjsunit/regress/regress-2437.js index 06b69b23db..c82293ae32 100644 --- a/deps/v8/test/mjsunit/regress/regress-2437.js +++ b/deps/v8/test/mjsunit/regress/regress-2437.js @@ -25,6 +25,14 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// Summary of the spec: lastIndex is reset to 0 if +// - a regexp fails to match, regardless of global or non-global. +// - a global regexp is used in a function that returns multiple results, +// such as String.prototype.replace or String.prototype.match, since it +// repeats the regexp until it fails to match. +// Otherwise lastIndex is only set when a global regexp matches, to the index +// after the match. + // Test Regexp.prototype.exec r = /a/; r.lastIndex = 1; @@ -73,3 +81,76 @@ r.lastIndex = 1; "zzzz".replace(r, function() { return ""; }); assertEquals(0, r.lastIndex); +// Regexp functions that returns multiple results: +// A global regexp always resets lastIndex regardless of whether it matches. +r = /a/g; +r.lastIndex = -1; +"0123abcd".replace(r, "x"); +assertEquals(0, r.lastIndex); + +r.lastIndex = -1; +"01234567".replace(r, "x"); +assertEquals(0, r.lastIndex); + +r.lastIndex = -1; +"0123abcd".match(r); +assertEquals(0, r.lastIndex); + +r.lastIndex = -1; +"01234567".match(r); +assertEquals(0, r.lastIndex); + +// A non-global regexp resets lastIndex iff it does not match. +r = /a/; +r.lastIndex = -1; +"0123abcd".replace(r, "x"); +assertEquals(-1, r.lastIndex); + +r.lastIndex = -1; +"01234567".replace(r, "x"); +assertEquals(0, r.lastIndex); + +r.lastIndex = -1; +"0123abcd".match(r); +assertEquals(-1, r.lastIndex); + +r.lastIndex = -1; +"01234567".match(r); +assertEquals(0, r.lastIndex); + +// Also test RegExp.prototype.exec and RegExp.prototype.test +r = /a/g; +r.lastIndex = 1; +r.exec("01234567"); +assertEquals(0, r.lastIndex); + +r.lastIndex = 1; +r.exec("0123abcd"); +assertEquals(5, r.lastIndex); + +r = /a/; +r.lastIndex = 1; +r.exec("01234567"); +assertEquals(0, r.lastIndex); + +r.lastIndex = 1; +r.exec("0123abcd"); +assertEquals(1, r.lastIndex); + +r = /a/g; +r.lastIndex = 1; +r.test("01234567"); +assertEquals(0, r.lastIndex); + +r.lastIndex = 1; +r.test("0123abcd"); +assertEquals(5, r.lastIndex); + +r = /a/; +r.lastIndex = 1; +r.test("01234567"); +assertEquals(0, r.lastIndex); + +r.lastIndex = 1; +r.test("0123abcd"); +assertEquals(1, r.lastIndex); diff --git a/deps/v8/test/mjsunit/regress/regress-2499.js b/deps/v8/test/mjsunit/regress/regress-2499.js new file mode 100644 index 0000000000..52aad874db --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-2499.js @@ -0,0 +1,40 @@ +// Copyright 2013 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. + +// Flags: --allow-natives-syntax + +function foo(word, nBits) { + return (word[1] >>> nBits) | (word[0] << (32 - nBits)); +} + +word = [0x1001, 0]; + +var expected = foo(word, 1); +foo(word, 1); +%OptimizeFunctionOnNextCall(foo); +var optimized = foo(word, 1); +assertEquals(expected, optimized) diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-170856.js b/deps/v8/test/mjsunit/regress/regress-crbug-170856.js new file mode 100644 index 0000000000..2e73b12caa --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-170856.js @@ -0,0 +1,33 @@ +// Copyright 2013 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. + +r = new RegExp("a"); +for (var i = 0; i < 100; i++) { + r["abc" + i] = i; +} +"zzzz".replace(r, ""); +assertEquals(0, r.lastIndex);