diff options
author | Ben Murdoch <benm@google.com> | 2015-01-08 11:13:37 +0000 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2015-01-08 11:13:37 +0000 |
commit | 9c681630b326ce459f584b3485c9c1b88e800749 (patch) | |
tree | 184d3be80cf88c1e04e24b579593e84580e6807c | |
parent | 9509a93a54f7e56e92c287cc36d2b626c0679104 (diff) | |
parent | aee41f5d4de09a9ffc245eaea459a75331b6f94d (diff) | |
download | v8-9c681630b326ce459f584b3485c9c1b88e800749.tar.gz |
Merge v8 from https://chromium.googlesource.com/v8/v8.git at aee41f5d4de09a9ffc245eaea459a75331b6f94d
This commit was generated by merge_from_chromium.py.
Change-Id: Ib1202a65df08c8e5c26296774e0fddcdaea9752b
-rw-r--r-- | src/api.cc | 6 | ||||
-rw-r--r-- | src/arm/assembler-arm.cc | 8 | ||||
-rw-r--r-- | src/factory.cc | 1 | ||||
-rw-r--r-- | src/jsregexp.cc | 46 | ||||
-rw-r--r-- | src/jsregexp.h | 5 | ||||
-rw-r--r-- | src/version.cc | 2 | ||||
-rw-r--r-- | test/cctest/test-api.cc | 31 | ||||
-rw-r--r-- | test/cctest/test-heap.cc | 75 |
8 files changed, 140 insertions, 34 deletions
diff --git a/src/api.cc b/src/api.cc index 2c8009e1d..239c7ac21 100644 --- a/src/api.cc +++ b/src/api.cc @@ -5545,7 +5545,11 @@ Local<String> v8::String::Concat(Handle<String> left, Handle<String> right) { LOG_API(isolate, "String::New(char)"); ENTER_V8(isolate); i::Handle<i::String> right_string = Utils::OpenHandle(*right); - // We do not expect this to fail. Change this if it does. + // If we are steering towards a range error, do not wait for the error to be + // thrown, and return the null handle instead. + if (left_string->length() + right_string->length() > i::String::kMaxLength) { + return Local<String>(); + } i::Handle<i::String> result = isolate->factory()->NewConsString( left_string, right_string).ToHandleChecked(); return Utils::ToLocal(result); diff --git a/src/arm/assembler-arm.cc b/src/arm/assembler-arm.cc index 17bf4f93a..c7b91c584 100644 --- a/src/arm/assembler-arm.cc +++ b/src/arm/assembler-arm.cc @@ -1338,7 +1338,7 @@ int Assembler::branch_offset(Label* L, bool jump_elimination_allowed) { void Assembler::b(int branch_offset, Condition cond) { DCHECK((branch_offset & 3) == 0); int imm24 = branch_offset >> 2; - DCHECK(is_int24(imm24)); + CHECK(is_int24(imm24)); emit(cond | B27 | B25 | (imm24 & kImm24Mask)); if (cond == al) { @@ -1352,7 +1352,7 @@ void Assembler::bl(int branch_offset, Condition cond) { positions_recorder()->WriteRecordedPositions(); DCHECK((branch_offset & 3) == 0); int imm24 = branch_offset >> 2; - DCHECK(is_int24(imm24)); + CHECK(is_int24(imm24)); emit(cond | B27 | B25 | B24 | (imm24 & kImm24Mask)); } @@ -1362,7 +1362,7 @@ void Assembler::blx(int branch_offset) { // v5 and above DCHECK((branch_offset & 1) == 0); int h = ((branch_offset & 2) >> 1)*B24; int imm24 = branch_offset >> 2; - DCHECK(is_int24(imm24)); + CHECK(is_int24(imm24)); emit(kSpecialCondition | B27 | B25 | h | (imm24 & kImm24Mask)); } @@ -1504,7 +1504,7 @@ void Assembler::mov_label_offset(Register dst, Label* label) { // // When the label gets bound: target_at extracts the link and target_at_put // patches the instructions. - DCHECK(is_uint24(link)); + CHECK(is_uint24(link)); BlockConstPoolScope block_const_pool(this); emit(link); nop(dst.code()); diff --git a/src/factory.cc b/src/factory.cc index 72974a317..19df01a96 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -1665,6 +1665,7 @@ void Factory::NewJSArrayStorage(Handle<JSArray> array, return; } + HandleScope inner_scope(isolate()); Handle<FixedArrayBase> elms; ElementsKind elements_kind = array->GetElementsKind(); if (IsFastDoubleElementsKind(elements_kind)) { diff --git a/src/jsregexp.cc b/src/jsregexp.cc index d078d07d5..8111a127e 100644 --- a/src/jsregexp.cc +++ b/src/jsregexp.cc @@ -1027,6 +1027,8 @@ class RegExpCompiler { inline bool ignore_case() { return ignore_case_; } inline bool one_byte() { return one_byte_; } + inline bool optimize() { return optimize_; } + inline void set_optimize(bool value) { optimize_ = value; } FrequencyCollator* frequency_collator() { return &frequency_collator_; } int current_expansion_factor() { return current_expansion_factor_; } @@ -1047,6 +1049,7 @@ class RegExpCompiler { bool ignore_case_; bool one_byte_; bool reg_exp_too_big_; + bool optimize_; int current_expansion_factor_; FrequencyCollator frequency_collator_; Zone* zone_; @@ -1079,6 +1082,7 @@ RegExpCompiler::RegExpCompiler(int capture_count, bool ignore_case, ignore_case_(ignore_case), one_byte_(one_byte), reg_exp_too_big_(false), + optimize_(FLAG_regexp_optimization), current_expansion_factor_(1), frequency_collator_(), zone_(zone) { @@ -1094,16 +1098,6 @@ RegExpEngine::CompilationResult RegExpCompiler::Assemble( Handle<String> pattern) { Heap* heap = pattern->GetHeap(); - bool use_slow_safe_regexp_compiler = false; - if (heap->total_regexp_code_generated() > - RegExpImpl::kRegWxpCompiledLimit && - heap->isolate()->memory_allocator()->SizeExecutable() > - RegExpImpl::kRegExpExecutableMemoryLimit) { - use_slow_safe_regexp_compiler = true; - } - - macro_assembler->set_slow_safe(use_slow_safe_regexp_compiler); - #ifdef DEBUG if (FLAG_trace_regexp_assembler) macro_assembler_ = new RegExpMacroAssemblerTracer(macro_assembler); @@ -2257,8 +2251,7 @@ RegExpNode::LimitResult RegExpNode::LimitVersions(RegExpCompiler* compiler, // We are being asked to make a non-generic version. Keep track of how many // non-generic versions we generate so as not to overdo it. trace_count_++; - if (FLAG_regexp_optimization && - trace_count_ < kMaxCopiesCodeGenerated && + if (compiler->optimize() && trace_count_ < kMaxCopiesCodeGenerated && compiler->recursion_depth() <= RegExpCompiler::kMaxRecursion) { return CONTINUE; } @@ -4137,15 +4130,12 @@ void ChoiceNode::EmitChoices(RegExpCompiler* compiler, } alt_gen->expects_preload = preload->preload_is_current_; bool generate_full_check_inline = false; - if (FLAG_regexp_optimization && + if (compiler->optimize() && try_to_emit_quick_check_for_alternative(i == 0) && - alternative.node()->EmitQuickCheck(compiler, - trace, - &new_trace, - preload->preload_has_checked_bounds_, - &alt_gen->possible_success, - &alt_gen->quick_check_details, - fall_through_on_failure)) { + alternative.node()->EmitQuickCheck( + compiler, trace, &new_trace, preload->preload_has_checked_bounds_, + &alt_gen->possible_success, &alt_gen->quick_check_details, + fall_through_on_failure)) { // Quick check was generated for this choice. preload->preload_is_current_ = true; preload->preload_has_checked_bounds_ = true; @@ -4943,7 +4933,7 @@ RegExpNode* RegExpQuantifier::ToNode(int min, if (body_can_be_empty) { body_start_reg = compiler->AllocateRegister(); - } else if (FLAG_regexp_optimization && !needs_capture_clearing) { + } else if (compiler->optimize() && !needs_capture_clearing) { // Only unroll if there are no captures and the body can't be // empty. { @@ -6041,6 +6031,8 @@ RegExpEngine::CompilationResult RegExpEngine::Compile( } RegExpCompiler compiler(data->capture_count, ignore_case, is_one_byte, zone); + compiler.set_optimize(!TooMuchRegExpCode(pattern)); + // Sample some characters from the middle of the string. static const int kSampleSize = 128; @@ -6143,6 +6135,8 @@ RegExpEngine::CompilationResult RegExpEngine::Compile( RegExpMacroAssemblerIrregexp macro_assembler(codes, zone); #endif // V8_INTERPRETED_REGEXP + macro_assembler.set_slow_safe(TooMuchRegExpCode(pattern)); + // Inserted here, instead of in Assembler, because it depends on information // in the AST that isn't replicated in the Node structure. static const int kMaxBacksearchLimit = 1024; @@ -6166,4 +6160,14 @@ RegExpEngine::CompilationResult RegExpEngine::Compile( } +bool RegExpEngine::TooMuchRegExpCode(Handle<String> pattern) { + Heap* heap = pattern->GetHeap(); + bool too_much = pattern->length() > RegExpImpl::kRegExpTooLargeToOptimize; + if (heap->total_regexp_code_generated() > RegExpImpl::kRegExpCompiledLimit && + heap->isolate()->memory_allocator()->SizeExecutable() > + RegExpImpl::kRegExpExecutableMemoryLimit) { + too_much = true; + } + return too_much; +} }} // namespace v8::internal diff --git a/src/jsregexp.h b/src/jsregexp.h index c65adea4c..c81ccb21d 100644 --- a/src/jsregexp.h +++ b/src/jsregexp.h @@ -213,7 +213,8 @@ class RegExpImpl { // total regexp code compiled including code that has subsequently been freed // and the total executable memory at any point. static const int kRegExpExecutableMemoryLimit = 16 * MB; - static const int kRegWxpCompiledLimit = 1 * MB; + static const int kRegExpCompiledLimit = 1 * MB; + static const int kRegExpTooLargeToOptimize = 10 * KB; private: static bool CompileIrregexp(Handle<JSRegExp> re, @@ -1666,6 +1667,8 @@ class RegExpEngine: public AllStatic { Handle<String> sample_subject, bool is_one_byte, Zone* zone); + static bool TooMuchRegExpCode(Handle<String> pattern); + static void DotPrint(const char* label, RegExpNode* node, bool ignore_case); }; diff --git a/src/version.cc b/src/version.cc index 60eb70312..81515d1ae 100644 --- a/src/version.cc +++ b/src/version.cc @@ -35,7 +35,7 @@ #define MAJOR_VERSION 3 #define MINOR_VERSION 30 #define BUILD_NUMBER 33 -#define PATCH_LEVEL 9 +#define PATCH_LEVEL 13 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) #define IS_CANDIDATE_VERSION 0 diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index 068a07ee7..2bcd9209c 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -742,23 +742,28 @@ THREADED_TEST(UsingExternalOneByteString) { } -class DummyResource : public v8::String::ExternalStringResource { +class RandomLengthResource : public v8::String::ExternalStringResource { public: + explicit RandomLengthResource(int length) : length_(length) {} virtual const uint16_t* data() const { return string_; } - virtual size_t length() const { return 1 << 30; } + virtual size_t length() const { return length_; } private: uint16_t string_[10]; + int length_; }; -class DummyOneByteResource : public v8::String::ExternalOneByteStringResource { +class RandomLengthOneByteResource + : public v8::String::ExternalOneByteStringResource { public: + explicit RandomLengthOneByteResource(int length) : length_(length) {} virtual const char* data() const { return string_; } - virtual size_t length() const { return 1 << 30; } + virtual size_t length() const { return length_; } private: char string_[10]; + int length_; }; @@ -767,7 +772,7 @@ THREADED_TEST(NewExternalForVeryLongString) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); v8::TryCatch try_catch; - DummyOneByteResource r; + RandomLengthOneByteResource r(1 << 30); v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), &r); CHECK(str.IsEmpty()); CHECK(try_catch.HasCaught()); @@ -779,7 +784,7 @@ THREADED_TEST(NewExternalForVeryLongString) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); v8::TryCatch try_catch; - DummyResource r; + RandomLengthResource r(1 << 30); v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), &r); CHECK(str.IsEmpty()); CHECK(try_catch.HasCaught()); @@ -24164,3 +24169,17 @@ TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit2) { const char* chunks[] = {chunk1, chunk2, "foo();", NULL}; RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8); } + + +TEST(StringConcatOverflow) { + v8::V8::Initialize(); + v8::HandleScope scope(CcTest::isolate()); + RandomLengthOneByteResource* r = + new RandomLengthOneByteResource(i::String::kMaxLength); + v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), r); + CHECK(!str.IsEmpty()); + v8::TryCatch try_catch; + v8::Local<v8::String> result = v8::String::Concat(str, str); + CHECK(result.IsEmpty()); + CHECK(!try_catch.HasCaught()); +} diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc index 543a89dcb..cc44c393b 100644 --- a/test/cctest/test-heap.cc +++ b/test/cctest/test-heap.cc @@ -1694,6 +1694,64 @@ TEST(TestInternalWeakListsTraverseWithGC) { } +TEST(TestSizeOfRegExpCode) { + if (!FLAG_regexp_optimization) return; + + v8::V8::Initialize(); + + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + LocalContext context; + + // Adjust source below and this check to match + // RegExpImple::kRegExpTooLargeToOptimize. + DCHECK_EQ(i::RegExpImpl::kRegExpTooLargeToOptimize, 10 * KB); + + // Compile a regexp that is much larger if we are using regexp optimizations. + CompileRun( + "var reg_exp_source = '(?:a|bc|def|ghij|klmno|pqrstu)';" + "var half_size_reg_exp;" + "while (reg_exp_source.length < 10 * 1024) {" + " half_size_reg_exp = reg_exp_source;" + " reg_exp_source = reg_exp_source + reg_exp_source;" + "}" + // Flatten string. + "reg_exp_source.match(/f/);"); + + // Get initial heap size after several full GCs, which will stabilize + // the heap size and return with sweeping finished completely. + CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); + CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); + CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); + CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); + CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); + MarkCompactCollector* collector = CcTest::heap()->mark_compact_collector(); + if (collector->sweeping_in_progress()) { + collector->EnsureSweepingCompleted(); + } + int initial_size = static_cast<int>(CcTest::heap()->SizeOfObjects()); + + CompileRun("'foo'.match(reg_exp_source);"); + CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); + int size_with_regexp = static_cast<int>(CcTest::heap()->SizeOfObjects()); + + CompileRun("'foo'.match(half_size_reg_exp);"); + CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); + int size_with_optimized_regexp = + static_cast<int>(CcTest::heap()->SizeOfObjects()); + + int size_of_regexp_code = size_with_regexp - initial_size; + + CHECK_LE(size_of_regexp_code, 500 * KB); + + // Small regexp is half the size, but compiles to more than twice the code + // due to the optimization steps. + CHECK_GE(size_with_optimized_regexp, + size_with_regexp + size_of_regexp_code * 2); +} + + TEST(TestSizeOfObjects) { v8::V8::Initialize(); @@ -4742,6 +4800,23 @@ TEST(Regress3631) { } +TEST(Regress442710) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + Heap* heap = isolate->heap(); + Factory* factory = isolate->factory(); + + HandleScope sc(isolate); + Handle<GlobalObject> global(CcTest::i_isolate()->context()->global_object()); + Handle<JSArray> array = factory->NewJSArray(2); + + Handle<String> name = factory->InternalizeUtf8String("testArray"); + JSReceiver::SetProperty(global, name, array, SLOPPY).Check(); + CompileRun("testArray[0] = 1; testArray[1] = 2; testArray.shift();"); + heap->CollectGarbage(OLD_POINTER_SPACE); +} + + #ifdef DEBUG TEST(PathTracer) { CcTest::InitializeVM(); |