OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/v8.h" | 5 #include "src/v8.h" |
6 | 6 |
7 #include "src/ast.h" | 7 #include "src/ast.h" |
8 #include "src/base/platform/platform.h" | 8 #include "src/base/platform/platform.h" |
9 #include "src/compilation-cache.h" | 9 #include "src/compilation-cache.h" |
10 #include "src/compiler.h" | 10 #include "src/compiler.h" |
11 #include "src/execution.h" | 11 #include "src/execution.h" |
12 #include "src/factory.h" | 12 #include "src/factory.h" |
13 #include "src/jsregexp-inl.h" | 13 #include "src/jsregexp-inl.h" |
14 #include "src/jsregexp.h" | 14 #include "src/jsregexp.h" |
| 15 #include "src/messages.h" |
15 #include "src/ostreams.h" | 16 #include "src/ostreams.h" |
16 #include "src/parser.h" | 17 #include "src/parser.h" |
17 #include "src/regexp-macro-assembler.h" | 18 #include "src/regexp-macro-assembler.h" |
18 #include "src/regexp-macro-assembler-irregexp.h" | 19 #include "src/regexp-macro-assembler-irregexp.h" |
19 #include "src/regexp-macro-assembler-tracer.h" | 20 #include "src/regexp-macro-assembler-tracer.h" |
20 #include "src/regexp-stack.h" | 21 #include "src/regexp-stack.h" |
21 #include "src/runtime/runtime.h" | 22 #include "src/runtime/runtime.h" |
22 #include "src/string-search.h" | 23 #include "src/string-search.h" |
23 #include "src/unicode-decoder.h" | 24 #include "src/unicode-decoder.h" |
24 | 25 |
(...skipping 30 matching lines...) Expand all Loading... |
55 Handle<String> pattern, | 56 Handle<String> pattern, |
56 Handle<String> flags) { | 57 Handle<String> flags) { |
57 // Call the construct code with 2 arguments. | 58 // Call the construct code with 2 arguments. |
58 Handle<Object> argv[] = { pattern, flags }; | 59 Handle<Object> argv[] = { pattern, flags }; |
59 return Execution::New(constructor, arraysize(argv), argv); | 60 return Execution::New(constructor, arraysize(argv), argv); |
60 } | 61 } |
61 | 62 |
62 | 63 |
63 MUST_USE_RESULT | 64 MUST_USE_RESULT |
64 static inline MaybeHandle<Object> ThrowRegExpException( | 65 static inline MaybeHandle<Object> ThrowRegExpException( |
65 Handle<JSRegExp> re, | 66 Handle<JSRegExp> re, Handle<String> pattern, Handle<String> error_text) { |
66 Handle<String> pattern, | |
67 Handle<String> error_text, | |
68 const char* message) { | |
69 Isolate* isolate = re->GetIsolate(); | 67 Isolate* isolate = re->GetIsolate(); |
70 Factory* factory = isolate->factory(); | 68 THROW_NEW_ERROR(isolate, NewSyntaxError(MessageTemplate::kMalformedRegExp, |
71 Handle<FixedArray> elements = factory->NewFixedArray(2); | 69 pattern, error_text), |
72 elements->set(0, *pattern); | 70 Object); |
73 elements->set(1, *error_text); | |
74 Handle<JSArray> array = factory->NewJSArrayWithElements(elements); | |
75 Handle<Object> regexp_err; | |
76 THROW_NEW_ERROR(isolate, NewSyntaxError(message, array), Object); | |
77 } | 71 } |
78 | 72 |
79 | 73 |
| 74 inline void ThrowRegExpException(Handle<JSRegExp> re, |
| 75 Handle<String> error_text) { |
| 76 USE(ThrowRegExpException(re, Handle<String>(re->Pattern()), error_text)); |
| 77 } |
| 78 |
| 79 |
80 ContainedInLattice AddRange(ContainedInLattice containment, | 80 ContainedInLattice AddRange(ContainedInLattice containment, |
81 const int* ranges, | 81 const int* ranges, |
82 int ranges_length, | 82 int ranges_length, |
83 Interval new_range) { | 83 Interval new_range) { |
84 DCHECK((ranges_length & 1) == 1); | 84 DCHECK((ranges_length & 1) == 1); |
85 DCHECK(ranges[ranges_length - 1] == String::kMaxUtf16CodeUnit + 1); | 85 DCHECK(ranges[ranges_length - 1] == String::kMaxUtf16CodeUnit + 1); |
86 if (containment == kLatticeUnknown) return containment; | 86 if (containment == kLatticeUnknown) return containment; |
87 bool inside = false; | 87 bool inside = false; |
88 int last = 0; | 88 int last = 0; |
89 for (int i = 0; i < ranges_length; inside = !inside, last = ranges[i], i++) { | 89 for (int i = 0; i < ranges_length; inside = !inside, last = ranges[i], i++) { |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
152 return re; | 152 return re; |
153 } | 153 } |
154 pattern = String::Flatten(pattern); | 154 pattern = String::Flatten(pattern); |
155 PostponeInterruptsScope postpone(isolate); | 155 PostponeInterruptsScope postpone(isolate); |
156 RegExpCompileData parse_result; | 156 RegExpCompileData parse_result; |
157 FlatStringReader reader(isolate, pattern); | 157 FlatStringReader reader(isolate, pattern); |
158 if (!RegExpParser::ParseRegExp(re->GetIsolate(), &zone, &reader, | 158 if (!RegExpParser::ParseRegExp(re->GetIsolate(), &zone, &reader, |
159 flags.is_multiline(), flags.is_unicode(), | 159 flags.is_multiline(), flags.is_unicode(), |
160 &parse_result)) { | 160 &parse_result)) { |
161 // Throw an exception if we fail to parse the pattern. | 161 // Throw an exception if we fail to parse the pattern. |
162 return ThrowRegExpException(re, | 162 return ThrowRegExpException(re, pattern, parse_result.error); |
163 pattern, | |
164 parse_result.error, | |
165 "malformed_regexp"); | |
166 } | 163 } |
167 | 164 |
168 bool has_been_compiled = false; | 165 bool has_been_compiled = false; |
169 | 166 |
170 if (parse_result.simple && | 167 if (parse_result.simple && |
171 !flags.is_ignore_case() && | 168 !flags.is_ignore_case() && |
172 !flags.is_sticky() && | 169 !flags.is_sticky() && |
173 !HasFewDifferentCharacters(pattern)) { | 170 !HasFewDifferentCharacters(pattern)) { |
174 // Parse-tree is a single atom that is equal to the pattern. | 171 // Parse-tree is a single atom that is equal to the pattern. |
175 AtomCompile(re, pattern, flags, pattern); | 172 AtomCompile(re, pattern, flags, pattern); |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
345 if (saved_code->IsCode()) { | 342 if (saved_code->IsCode()) { |
346 // Reinstate the code in the original place. | 343 // Reinstate the code in the original place. |
347 re->SetDataAt(JSRegExp::code_index(is_one_byte), saved_code); | 344 re->SetDataAt(JSRegExp::code_index(is_one_byte), saved_code); |
348 DCHECK(compiled_code->IsSmi()); | 345 DCHECK(compiled_code->IsSmi()); |
349 return true; | 346 return true; |
350 } | 347 } |
351 return CompileIrregexp(re, sample_subject, is_one_byte); | 348 return CompileIrregexp(re, sample_subject, is_one_byte); |
352 } | 349 } |
353 | 350 |
354 | 351 |
355 static void CreateRegExpErrorObjectAndThrow(Handle<JSRegExp> re, | |
356 Handle<String> error_message, | |
357 Isolate* isolate) { | |
358 Factory* factory = isolate->factory(); | |
359 Handle<FixedArray> elements = factory->NewFixedArray(2); | |
360 elements->set(0, re->Pattern()); | |
361 elements->set(1, *error_message); | |
362 Handle<JSArray> array = factory->NewJSArrayWithElements(elements); | |
363 Handle<Object> error = factory->NewSyntaxError("malformed_regexp", array); | |
364 isolate->Throw(*error); | |
365 } | |
366 | |
367 | |
368 bool RegExpImpl::CompileIrregexp(Handle<JSRegExp> re, | 352 bool RegExpImpl::CompileIrregexp(Handle<JSRegExp> re, |
369 Handle<String> sample_subject, | 353 Handle<String> sample_subject, |
370 bool is_one_byte) { | 354 bool is_one_byte) { |
371 // Compile the RegExp. | 355 // Compile the RegExp. |
372 Isolate* isolate = re->GetIsolate(); | 356 Isolate* isolate = re->GetIsolate(); |
373 Zone zone; | 357 Zone zone; |
374 PostponeInterruptsScope postpone(isolate); | 358 PostponeInterruptsScope postpone(isolate); |
375 // If we had a compilation error the last time this is saved at the | 359 // If we had a compilation error the last time this is saved at the |
376 // saved code index. | 360 // saved code index. |
377 Object* entry = re->DataAt(JSRegExp::code_index(is_one_byte)); | 361 Object* entry = re->DataAt(JSRegExp::code_index(is_one_byte)); |
378 // When arriving here entry can only be a smi, either representing an | 362 // When arriving here entry can only be a smi, either representing an |
379 // uncompiled regexp, a previous compilation error, or code that has | 363 // uncompiled regexp, a previous compilation error, or code that has |
380 // been flushed. | 364 // been flushed. |
381 DCHECK(entry->IsSmi()); | 365 DCHECK(entry->IsSmi()); |
382 int entry_value = Smi::cast(entry)->value(); | 366 int entry_value = Smi::cast(entry)->value(); |
383 DCHECK(entry_value == JSRegExp::kUninitializedValue || | 367 DCHECK(entry_value == JSRegExp::kUninitializedValue || |
384 entry_value == JSRegExp::kCompilationErrorValue || | 368 entry_value == JSRegExp::kCompilationErrorValue || |
385 (entry_value < JSRegExp::kCodeAgeMask && entry_value >= 0)); | 369 (entry_value < JSRegExp::kCodeAgeMask && entry_value >= 0)); |
386 | 370 |
387 if (entry_value == JSRegExp::kCompilationErrorValue) { | 371 if (entry_value == JSRegExp::kCompilationErrorValue) { |
388 // A previous compilation failed and threw an error which we store in | 372 // A previous compilation failed and threw an error which we store in |
389 // the saved code index (we store the error message, not the actual | 373 // the saved code index (we store the error message, not the actual |
390 // error). Recreate the error object and throw it. | 374 // error). Recreate the error object and throw it. |
391 Object* error_string = re->DataAt(JSRegExp::saved_code_index(is_one_byte)); | 375 Object* error_string = re->DataAt(JSRegExp::saved_code_index(is_one_byte)); |
392 DCHECK(error_string->IsString()); | 376 DCHECK(error_string->IsString()); |
393 Handle<String> error_message(String::cast(error_string)); | 377 Handle<String> error_message(String::cast(error_string)); |
394 CreateRegExpErrorObjectAndThrow(re, error_message, isolate); | 378 ThrowRegExpException(re, error_message); |
395 return false; | 379 return false; |
396 } | 380 } |
397 | 381 |
398 JSRegExp::Flags flags = re->GetFlags(); | 382 JSRegExp::Flags flags = re->GetFlags(); |
399 | 383 |
400 Handle<String> pattern(re->Pattern()); | 384 Handle<String> pattern(re->Pattern()); |
401 pattern = String::Flatten(pattern); | 385 pattern = String::Flatten(pattern); |
402 RegExpCompileData compile_data; | 386 RegExpCompileData compile_data; |
403 FlatStringReader reader(isolate, pattern); | 387 FlatStringReader reader(isolate, pattern); |
404 if (!RegExpParser::ParseRegExp(isolate, &zone, &reader, flags.is_multiline(), | 388 if (!RegExpParser::ParseRegExp(isolate, &zone, &reader, flags.is_multiline(), |
405 flags.is_unicode(), &compile_data)) { | 389 flags.is_unicode(), &compile_data)) { |
406 // Throw an exception if we fail to parse the pattern. | 390 // Throw an exception if we fail to parse the pattern. |
407 // THIS SHOULD NOT HAPPEN. We already pre-parsed it successfully once. | 391 // THIS SHOULD NOT HAPPEN. We already pre-parsed it successfully once. |
408 USE(ThrowRegExpException(re, | 392 USE(ThrowRegExpException(re, pattern, compile_data.error)); |
409 pattern, | |
410 compile_data.error, | |
411 "malformed_regexp")); | |
412 return false; | 393 return false; |
413 } | 394 } |
414 RegExpEngine::CompilationResult result = RegExpEngine::Compile( | 395 RegExpEngine::CompilationResult result = RegExpEngine::Compile( |
415 isolate, &zone, &compile_data, flags.is_ignore_case(), flags.is_global(), | 396 isolate, &zone, &compile_data, flags.is_ignore_case(), flags.is_global(), |
416 flags.is_multiline(), flags.is_sticky(), pattern, sample_subject, | 397 flags.is_multiline(), flags.is_sticky(), pattern, sample_subject, |
417 is_one_byte); | 398 is_one_byte); |
418 if (result.error_message != NULL) { | 399 if (result.error_message != NULL) { |
419 // Unable to compile regexp. | 400 // Unable to compile regexp. |
420 Handle<String> error_message = isolate->factory()->NewStringFromUtf8( | 401 Handle<String> error_message = isolate->factory()->NewStringFromUtf8( |
421 CStrVector(result.error_message)).ToHandleChecked(); | 402 CStrVector(result.error_message)).ToHandleChecked(); |
422 CreateRegExpErrorObjectAndThrow(re, error_message, isolate); | 403 ThrowRegExpException(re, error_message); |
423 return false; | 404 return false; |
424 } | 405 } |
425 | 406 |
426 Handle<FixedArray> data = Handle<FixedArray>(FixedArray::cast(re->data())); | 407 Handle<FixedArray> data = Handle<FixedArray>(FixedArray::cast(re->data())); |
427 data->set(JSRegExp::code_index(is_one_byte), result.code); | 408 data->set(JSRegExp::code_index(is_one_byte), result.code); |
428 int register_max = IrregexpMaxRegisterCount(*data); | 409 int register_max = IrregexpMaxRegisterCount(*data); |
429 if (result.num_registers > register_max) { | 410 if (result.num_registers > register_max) { |
430 SetIrregexpMaxRegisterCount(*data, result.num_registers); | 411 SetIrregexpMaxRegisterCount(*data, result.num_registers); |
431 } | 412 } |
432 | 413 |
(...skipping 5751 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6184 Heap* heap = pattern->GetHeap(); | 6165 Heap* heap = pattern->GetHeap(); |
6185 bool too_much = pattern->length() > RegExpImpl::kRegExpTooLargeToOptimize; | 6166 bool too_much = pattern->length() > RegExpImpl::kRegExpTooLargeToOptimize; |
6186 if (heap->total_regexp_code_generated() > RegExpImpl::kRegExpCompiledLimit && | 6167 if (heap->total_regexp_code_generated() > RegExpImpl::kRegExpCompiledLimit && |
6187 heap->isolate()->memory_allocator()->SizeExecutable() > | 6168 heap->isolate()->memory_allocator()->SizeExecutable() > |
6188 RegExpImpl::kRegExpExecutableMemoryLimit) { | 6169 RegExpImpl::kRegExpExecutableMemoryLimit) { |
6189 too_much = true; | 6170 too_much = true; |
6190 } | 6171 } |
6191 return too_much; | 6172 return too_much; |
6192 } | 6173 } |
6193 }} // namespace v8::internal | 6174 }} // namespace v8::internal |
OLD | NEW |