aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2015-01-08 11:13:37 +0000
committerBen Murdoch <benm@google.com>2015-01-08 11:13:37 +0000
commit9c681630b326ce459f584b3485c9c1b88e800749 (patch)
tree184d3be80cf88c1e04e24b579593e84580e6807c
parent9509a93a54f7e56e92c287cc36d2b626c0679104 (diff)
parentaee41f5d4de09a9ffc245eaea459a75331b6f94d (diff)
downloadv8-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.cc6
-rw-r--r--src/arm/assembler-arm.cc8
-rw-r--r--src/factory.cc1
-rw-r--r--src/jsregexp.cc46
-rw-r--r--src/jsregexp.h5
-rw-r--r--src/version.cc2
-rw-r--r--test/cctest/test-api.cc31
-rw-r--r--test/cctest/test-heap.cc75
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();