OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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/objects.h" | 5 #include "src/objects.h" |
6 | 6 |
7 #include <cmath> | 7 #include <cmath> |
8 #include <iomanip> | 8 #include <iomanip> |
9 #include <sstream> | 9 #include <sstream> |
10 | 10 |
(...skipping 15388 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
15399 } | 15399 } |
15400 | 15400 |
15401 private: | 15401 private: |
15402 Handle<String> source_; | 15402 Handle<String> source_; |
15403 Handle<SharedFunctionInfo> shared_; | 15403 Handle<SharedFunctionInfo> shared_; |
15404 LanguageMode language_mode_; | 15404 LanguageMode language_mode_; |
15405 int scope_position_; | 15405 int scope_position_; |
15406 }; | 15406 }; |
15407 | 15407 |
15408 | 15408 |
| 15409 // static |
| 15410 MaybeHandle<JSRegExp> JSRegExp::New(Handle<String> pattern, |
| 15411 Handle<String> flags) { |
| 15412 Isolate* isolate = pattern->GetIsolate(); |
| 15413 Handle<JSFunction> constructor = isolate->regexp_function(); |
| 15414 Handle<JSRegExp> regexp = |
| 15415 Handle<JSRegExp>::cast(isolate->factory()->NewJSObject(constructor)); |
| 15416 |
| 15417 return JSRegExp::Initialize(regexp, pattern, flags); |
| 15418 } |
| 15419 |
| 15420 |
| 15421 static JSRegExp::Flags RegExpFlagsFromString(Handle<String> flags, |
| 15422 bool* success) { |
| 15423 uint32_t value = JSRegExp::NONE; |
| 15424 int length = flags->length(); |
| 15425 // A longer flags string cannot be valid. |
| 15426 if (length > 5) return JSRegExp::Flags(0); |
| 15427 for (int i = 0; i < length; i++) { |
| 15428 uint32_t flag = JSRegExp::NONE; |
| 15429 switch (flags->Get(i)) { |
| 15430 case 'g': |
| 15431 flag = JSRegExp::GLOBAL; |
| 15432 break; |
| 15433 case 'i': |
| 15434 flag = JSRegExp::IGNORE_CASE; |
| 15435 break; |
| 15436 case 'm': |
| 15437 flag = JSRegExp::MULTILINE; |
| 15438 break; |
| 15439 case 'u': |
| 15440 if (!FLAG_harmony_unicode_regexps) return JSRegExp::Flags(0); |
| 15441 flag = JSRegExp::UNICODE_ESCAPES; |
| 15442 break; |
| 15443 case 'y': |
| 15444 if (!FLAG_harmony_regexps) return JSRegExp::Flags(0); |
| 15445 flag = JSRegExp::STICKY; |
| 15446 break; |
| 15447 default: |
| 15448 return JSRegExp::Flags(0); |
| 15449 } |
| 15450 // Duplicate flag. |
| 15451 if (value & flag) return JSRegExp::Flags(0); |
| 15452 value |= flag; |
| 15453 } |
| 15454 *success = true; |
| 15455 return JSRegExp::Flags(value); |
| 15456 } |
| 15457 |
| 15458 |
| 15459 template <typename Char> |
| 15460 inline int CountRequiredEscapes(Handle<String> source) { |
| 15461 DisallowHeapAllocation no_gc; |
| 15462 int escapes = 0; |
| 15463 Vector<const Char> src = source->GetCharVector<Char>(); |
| 15464 for (int i = 0; i < src.length(); i++) { |
| 15465 if (src[i] == '/' && (i == 0 || src[i - 1] != '\\')) escapes++; |
| 15466 } |
| 15467 return escapes; |
| 15468 } |
| 15469 |
| 15470 |
| 15471 template <typename Char, typename StringType> |
| 15472 inline Handle<StringType> WriteEscapedRegExpSource(Handle<String> source, |
| 15473 Handle<StringType> result) { |
| 15474 DisallowHeapAllocation no_gc; |
| 15475 Vector<const Char> src = source->GetCharVector<Char>(); |
| 15476 Vector<Char> dst(result->GetChars(), result->length()); |
| 15477 int s = 0; |
| 15478 int d = 0; |
| 15479 while (s < src.length()) { |
| 15480 if (src[s] == '/' && (s == 0 || src[s - 1] != '\\')) dst[d++] = '\\'; |
| 15481 dst[d++] = src[s++]; |
| 15482 } |
| 15483 DCHECK_EQ(result->length(), d); |
| 15484 return result; |
| 15485 } |
| 15486 |
| 15487 |
| 15488 MaybeHandle<String> EscapeRegExpSource(Isolate* isolate, |
| 15489 Handle<String> source) { |
| 15490 String::Flatten(source); |
| 15491 if (source->length() == 0) return isolate->factory()->query_colon_string(); |
| 15492 bool one_byte = source->IsOneByteRepresentationUnderneath(); |
| 15493 int escapes = one_byte ? CountRequiredEscapes<uint8_t>(source) |
| 15494 : CountRequiredEscapes<uc16>(source); |
| 15495 if (escapes == 0) return source; |
| 15496 int length = source->length() + escapes; |
| 15497 if (one_byte) { |
| 15498 Handle<SeqOneByteString> result; |
| 15499 ASSIGN_RETURN_ON_EXCEPTION(isolate, result, |
| 15500 isolate->factory()->NewRawOneByteString(length), |
| 15501 String); |
| 15502 return WriteEscapedRegExpSource<uint8_t>(source, result); |
| 15503 } else { |
| 15504 Handle<SeqTwoByteString> result; |
| 15505 ASSIGN_RETURN_ON_EXCEPTION(isolate, result, |
| 15506 isolate->factory()->NewRawTwoByteString(length), |
| 15507 String); |
| 15508 return WriteEscapedRegExpSource<uc16>(source, result); |
| 15509 } |
| 15510 } |
| 15511 |
| 15512 |
| 15513 // static |
| 15514 MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp, |
| 15515 Handle<String> source, |
| 15516 Handle<String> flags_string) { |
| 15517 Isolate* isolate = regexp->GetIsolate(); |
| 15518 Factory* factory = isolate->factory(); |
| 15519 // If source is the empty string we set it to "(?:)" instead as |
| 15520 // suggested by ECMA-262, 5th, section 15.10.4.1. |
| 15521 if (source->length() == 0) source = factory->query_colon_string(); |
| 15522 |
| 15523 bool success = false; |
| 15524 JSRegExp::Flags flags = RegExpFlagsFromString(flags_string, &success); |
| 15525 if (!success) { |
| 15526 THROW_NEW_ERROR( |
| 15527 isolate, |
| 15528 NewSyntaxError(MessageTemplate::kInvalidRegExpFlags, flags_string), |
| 15529 JSRegExp); |
| 15530 } |
| 15531 |
| 15532 Handle<String> escaped_source; |
| 15533 ASSIGN_RETURN_ON_EXCEPTION(isolate, escaped_source, |
| 15534 EscapeRegExpSource(isolate, source), JSRegExp); |
| 15535 |
| 15536 regexp->set_source(*escaped_source); |
| 15537 regexp->set_flags(Smi::FromInt(flags.value())); |
| 15538 |
| 15539 Map* map = regexp->map(); |
| 15540 Object* constructor = map->GetConstructor(); |
| 15541 if (constructor->IsJSFunction() && |
| 15542 JSFunction::cast(constructor)->initial_map() == map) { |
| 15543 // If we still have the original map, set in-object properties directly. |
| 15544 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex, |
| 15545 Smi::FromInt(0), SKIP_WRITE_BARRIER); |
| 15546 } else { |
| 15547 // Map has changed, so use generic, but slower, method. |
| 15548 PropertyAttributes writable = |
| 15549 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE); |
| 15550 JSObject::SetOwnPropertyIgnoreAttributes( |
| 15551 regexp, factory->last_index_string(), |
| 15552 Handle<Smi>(Smi::FromInt(0), isolate), writable) |
| 15553 .Check(); |
| 15554 } |
| 15555 |
| 15556 RETURN_ON_EXCEPTION(isolate, RegExpImpl::Compile(regexp, source, flags), |
| 15557 JSRegExp); |
| 15558 |
| 15559 return regexp; |
| 15560 } |
| 15561 |
| 15562 |
15409 // RegExpKey carries the source and flags of a regular expression as key. | 15563 // RegExpKey carries the source and flags of a regular expression as key. |
15410 class RegExpKey : public HashTableKey { | 15564 class RegExpKey : public HashTableKey { |
15411 public: | 15565 public: |
15412 RegExpKey(Handle<String> string, JSRegExp::Flags flags) | 15566 RegExpKey(Handle<String> string, JSRegExp::Flags flags) |
15413 : string_(string), | 15567 : string_(string), |
15414 flags_(Smi::FromInt(flags.value())) { } | 15568 flags_(Smi::FromInt(flags.value())) { } |
15415 | 15569 |
15416 // Rather than storing the key in the hash table, a pointer to the | 15570 // Rather than storing the key in the hash table, a pointer to the |
15417 // stored value is stored where the key should be. IsMatch then | 15571 // stored value is stored where the key should be. IsMatch then |
15418 // compares the search key to the found object, rather than comparing | 15572 // compares the search key to the found object, rather than comparing |
(...skipping 2704 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
18123 if (cell->value() != *new_value) { | 18277 if (cell->value() != *new_value) { |
18124 cell->set_value(*new_value); | 18278 cell->set_value(*new_value); |
18125 Isolate* isolate = cell->GetIsolate(); | 18279 Isolate* isolate = cell->GetIsolate(); |
18126 cell->dependent_code()->DeoptimizeDependentCodeGroup( | 18280 cell->dependent_code()->DeoptimizeDependentCodeGroup( |
18127 isolate, DependentCode::kPropertyCellChangedGroup); | 18281 isolate, DependentCode::kPropertyCellChangedGroup); |
18128 } | 18282 } |
18129 } | 18283 } |
18130 | 18284 |
18131 } // namespace internal | 18285 } // namespace internal |
18132 } // namespace v8 | 18286 } // namespace v8 |
OLD | NEW |