blob: 22321c36643e09e264a8b38706dd60067c19e02f [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// Copyright 2012 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
Emily Bernierd0a1eb72015-03-24 16:35:39 -040028#include <cstdlib>
29#include <sstream>
Steve Blocka7e24c12009-10-30 11:49:00 +000030
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000031#include "include/v8.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000032#include "src/v8.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000033
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000034#include "src/ast/ast.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000035#include "src/char-predicates-inl.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000036#include "src/ostreams.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000037#include "src/regexp/jsregexp.h"
38#include "src/regexp/regexp-macro-assembler.h"
39#include "src/regexp/regexp-macro-assembler-irregexp.h"
40#include "src/regexp/regexp-parser.h"
41#include "src/splay-tree-inl.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000042#include "src/string-stream.h"
Steve Block6ded16b2010-05-10 14:33:55 +010043#ifdef V8_INTERPRETED_REGEXP
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000044#include "src/regexp/interpreter-irregexp.h"
Steve Block6ded16b2010-05-10 14:33:55 +010045#else // V8_INTERPRETED_REGEXP
Ben Murdochb8a8cc12014-11-26 15:28:44 +000046#include "src/macro-assembler.h"
47#if V8_TARGET_ARCH_ARM
48#include "src/arm/assembler-arm.h" // NOLINT
49#include "src/arm/macro-assembler-arm.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000050#include "src/regexp/arm/regexp-macro-assembler-arm.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000051#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +000052#if V8_TARGET_ARCH_ARM64
53#include "src/arm64/assembler-arm64.h"
54#include "src/arm64/macro-assembler-arm64.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000055#include "src/regexp/arm64/regexp-macro-assembler-arm64.h"
56#endif
57#if V8_TARGET_ARCH_PPC
58#include "src/ppc/assembler-ppc.h"
59#include "src/ppc/macro-assembler-ppc.h"
60#include "src/regexp/ppc/regexp-macro-assembler-ppc.h"
Steve Block44f0eee2011-05-26 01:26:41 +010061#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +000062#if V8_TARGET_ARCH_MIPS
63#include "src/mips/assembler-mips.h"
64#include "src/mips/macro-assembler-mips.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000065#include "src/regexp/mips/regexp-macro-assembler-mips.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000066#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +000067#if V8_TARGET_ARCH_MIPS64
68#include "src/mips64/assembler-mips64.h"
69#include "src/mips64/macro-assembler-mips64.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000070#include "src/regexp/mips64/regexp-macro-assembler-mips64.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000071#endif
72#if V8_TARGET_ARCH_X64
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000073#include "src/regexp/x64/regexp-macro-assembler-x64.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000074#include "src/x64/assembler-x64.h"
75#include "src/x64/macro-assembler-x64.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000076#endif
77#if V8_TARGET_ARCH_IA32
78#include "src/ia32/assembler-ia32.h"
79#include "src/ia32/macro-assembler-ia32.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000080#include "src/regexp/ia32/regexp-macro-assembler-ia32.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000081#endif
82#if V8_TARGET_ARCH_X87
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000083#include "src/regexp/x87/regexp-macro-assembler-x87.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000084#include "src/x87/assembler-x87.h"
85#include "src/x87/macro-assembler-x87.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000086#endif
Steve Block6ded16b2010-05-10 14:33:55 +010087#endif // V8_INTERPRETED_REGEXP
Ben Murdochb8a8cc12014-11-26 15:28:44 +000088#include "test/cctest/cctest.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000089
90using namespace v8::internal;
91
92
Leon Clarkee46be812010-01-19 14:06:41 +000093static bool CheckParse(const char* input) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000094 v8::HandleScope scope(CcTest::isolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000095 Zone zone;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000096 FlatStringReader reader(CcTest::i_isolate(), CStrVector(input));
Leon Clarkee46be812010-01-19 14:06:41 +000097 RegExpCompileData result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000098 return v8::internal::RegExpParser::ParseRegExp(
Ben Murdoch097c5b22016-05-18 11:27:45 +010099 CcTest::i_isolate(), &zone, &reader, JSRegExp::kNone, &result);
Leon Clarkee46be812010-01-19 14:06:41 +0000100}
101
102
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000103static void CheckParseEq(const char* input, const char* expected,
104 bool unicode = false) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000105 v8::HandleScope scope(CcTest::isolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000106 Zone zone;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000107 FlatStringReader reader(CcTest::i_isolate(), CStrVector(input));
Steve Blocka7e24c12009-10-30 11:49:00 +0000108 RegExpCompileData result;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100109 JSRegExp::Flags flags = JSRegExp::kNone;
110 if (unicode) flags |= JSRegExp::kUnicode;
111 CHECK(v8::internal::RegExpParser::ParseRegExp(CcTest::i_isolate(), &zone,
112 &reader, flags, &result));
Steve Blocka7e24c12009-10-30 11:49:00 +0000113 CHECK(result.tree != NULL);
114 CHECK(result.error.is_null());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400115 std::ostringstream os;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000116 result.tree->Print(os, &zone);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000117 if (strcmp(expected, os.str().c_str()) != 0) {
118 printf("%s | %s\n", expected, os.str().c_str());
119 }
120 CHECK_EQ(0, strcmp(expected, os.str().c_str()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000121}
122
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000123
Steve Blocka7e24c12009-10-30 11:49:00 +0000124static bool CheckSimple(const char* input) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000125 v8::HandleScope scope(CcTest::isolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000126 Zone zone;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000127 FlatStringReader reader(CcTest::i_isolate(), CStrVector(input));
Steve Blocka7e24c12009-10-30 11:49:00 +0000128 RegExpCompileData result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000129 CHECK(v8::internal::RegExpParser::ParseRegExp(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100130 CcTest::i_isolate(), &zone, &reader, JSRegExp::kNone, &result));
Steve Blocka7e24c12009-10-30 11:49:00 +0000131 CHECK(result.tree != NULL);
132 CHECK(result.error.is_null());
133 return result.simple;
134}
135
136struct MinMaxPair {
137 int min_match;
138 int max_match;
139};
140
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000141
Steve Blocka7e24c12009-10-30 11:49:00 +0000142static MinMaxPair CheckMinMaxMatch(const char* input) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000143 v8::HandleScope scope(CcTest::isolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000144 Zone zone;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000145 FlatStringReader reader(CcTest::i_isolate(), CStrVector(input));
Steve Blocka7e24c12009-10-30 11:49:00 +0000146 RegExpCompileData result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000147 CHECK(v8::internal::RegExpParser::ParseRegExp(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100148 CcTest::i_isolate(), &zone, &reader, JSRegExp::kNone, &result));
Steve Blocka7e24c12009-10-30 11:49:00 +0000149 CHECK(result.tree != NULL);
150 CHECK(result.error.is_null());
151 int min_match = result.tree->min_match();
152 int max_match = result.tree->max_match();
153 MinMaxPair pair = { min_match, max_match };
154 return pair;
155}
156
157
Leon Clarkee46be812010-01-19 14:06:41 +0000158#define CHECK_PARSE_ERROR(input) CHECK(!CheckParse(input))
Steve Blocka7e24c12009-10-30 11:49:00 +0000159#define CHECK_SIMPLE(input, simple) CHECK_EQ(simple, CheckSimple(input));
160#define CHECK_MIN_MAX(input, min, max) \
161 { MinMaxPair min_max = CheckMinMaxMatch(input); \
162 CHECK_EQ(min, min_max.min_match); \
163 CHECK_EQ(max, min_max.max_match); \
164 }
165
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000166
167void TestRegExpParser(bool lookbehind) {
168 FLAG_harmony_regexp_lookbehind = lookbehind;
169 FLAG_harmony_unicode_regexps = true;
170
Leon Clarkee46be812010-01-19 14:06:41 +0000171 CHECK_PARSE_ERROR("?");
172
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000173 CheckParseEq("abc", "'abc'");
174 CheckParseEq("", "%");
175 CheckParseEq("abc|def", "(| 'abc' 'def')");
176 CheckParseEq("abc|def|ghi", "(| 'abc' 'def' 'ghi')");
177 CheckParseEq("^xxx$", "(: @^i 'xxx' @$i)");
178 CheckParseEq("ab\\b\\d\\bcd", "(: 'ab' @b [0-9] @b 'cd')");
179 CheckParseEq("\\w|\\d", "(| [0-9 A-Z _ a-z] [0-9])");
180 CheckParseEq("a*", "(# 0 - g 'a')");
181 CheckParseEq("a*?", "(# 0 - n 'a')");
182 CheckParseEq("abc+", "(: 'ab' (# 1 - g 'c'))");
183 CheckParseEq("abc+?", "(: 'ab' (# 1 - n 'c'))");
184 CheckParseEq("xyz?", "(: 'xy' (# 0 1 g 'z'))");
185 CheckParseEq("xyz??", "(: 'xy' (# 0 1 n 'z'))");
186 CheckParseEq("xyz{0,1}", "(: 'xy' (# 0 1 g 'z'))");
187 CheckParseEq("xyz{0,1}?", "(: 'xy' (# 0 1 n 'z'))");
188 CheckParseEq("xyz{93}", "(: 'xy' (# 93 93 g 'z'))");
189 CheckParseEq("xyz{93}?", "(: 'xy' (# 93 93 n 'z'))");
190 CheckParseEq("xyz{1,32}", "(: 'xy' (# 1 32 g 'z'))");
191 CheckParseEq("xyz{1,32}?", "(: 'xy' (# 1 32 n 'z'))");
192 CheckParseEq("xyz{1,}", "(: 'xy' (# 1 - g 'z'))");
193 CheckParseEq("xyz{1,}?", "(: 'xy' (# 1 - n 'z'))");
194 CheckParseEq("a\\fb\\nc\\rd\\te\\vf", "'a\\x0cb\\x0ac\\x0dd\\x09e\\x0bf'");
195 CheckParseEq("a\\nb\\bc", "(: 'a\\x0ab' @b 'c')");
196 CheckParseEq("(?:foo)", "'foo'");
197 CheckParseEq("(?: foo )", "' foo '");
198 CheckParseEq("(foo|bar|baz)", "(^ (| 'foo' 'bar' 'baz'))");
199 CheckParseEq("foo|(bar|baz)|quux", "(| 'foo' (^ (| 'bar' 'baz')) 'quux')");
200 CheckParseEq("foo(?=bar)baz", "(: 'foo' (-> + 'bar') 'baz')");
201 CheckParseEq("foo(?!bar)baz", "(: 'foo' (-> - 'bar') 'baz')");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000202 if (lookbehind) {
203 CheckParseEq("foo(?<=bar)baz", "(: 'foo' (<- + 'bar') 'baz')");
204 CheckParseEq("foo(?<!bar)baz", "(: 'foo' (<- - 'bar') 'baz')");
205 } else {
206 CHECK_PARSE_ERROR("foo(?<=bar)baz");
207 CHECK_PARSE_ERROR("foo(?<!bar)baz");
208 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000209 CheckParseEq("()", "(^ %)");
210 CheckParseEq("(?=)", "(-> + %)");
Ben Murdoch097c5b22016-05-18 11:27:45 +0100211 CheckParseEq("[]", "^[\\x00-\\u{10ffff}]"); // Doesn't compile on windows
212 CheckParseEq("[^]", "[\\x00-\\u{10ffff}]"); // \uffff isn't in codepage 1252
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000213 CheckParseEq("[x]", "[x]");
214 CheckParseEq("[xyz]", "[x y z]");
215 CheckParseEq("[a-zA-Z0-9]", "[a-z A-Z 0-9]");
216 CheckParseEq("[-123]", "[- 1 2 3]");
217 CheckParseEq("[^123]", "^[1 2 3]");
218 CheckParseEq("]", "']'");
219 CheckParseEq("}", "'}'");
220 CheckParseEq("[a-b-c]", "[a-b - c]");
221 CheckParseEq("[\\d]", "[0-9]");
222 CheckParseEq("[x\\dz]", "[x 0-9 z]");
223 CheckParseEq("[\\d-z]", "[0-9 - z]");
224 CheckParseEq("[\\d-\\d]", "[0-9 - 0-9]");
225 CheckParseEq("[z-\\d]", "[z - 0-9]");
Ben Murdoch086aeea2011-05-13 15:57:08 +0100226 // Control character outside character class.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000227 CheckParseEq("\\cj\\cJ\\ci\\cI\\ck\\cK", "'\\x0a\\x0a\\x09\\x09\\x0b\\x0b'");
228 CheckParseEq("\\c!", "'\\c!'");
229 CheckParseEq("\\c_", "'\\c_'");
230 CheckParseEq("\\c~", "'\\c~'");
231 CheckParseEq("\\c1", "'\\c1'");
Ben Murdoch086aeea2011-05-13 15:57:08 +0100232 // Control character inside character class.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000233 CheckParseEq("[\\c!]", "[\\ c !]");
234 CheckParseEq("[\\c_]", "[\\x1f]");
235 CheckParseEq("[\\c~]", "[\\ c ~]");
236 CheckParseEq("[\\ca]", "[\\x01]");
237 CheckParseEq("[\\cz]", "[\\x1a]");
238 CheckParseEq("[\\cA]", "[\\x01]");
239 CheckParseEq("[\\cZ]", "[\\x1a]");
240 CheckParseEq("[\\c1]", "[\\x11]");
Ben Murdoch086aeea2011-05-13 15:57:08 +0100241
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000242 CheckParseEq("[a\\]c]", "[a ] c]");
243 CheckParseEq("\\[\\]\\{\\}\\(\\)\\%\\^\\#\\ ", "'[]{}()%^# '");
244 CheckParseEq("[\\[\\]\\{\\}\\(\\)\\%\\^\\#\\ ]", "[[ ] { } ( ) % ^ # ]");
245 CheckParseEq("\\0", "'\\x00'");
246 CheckParseEq("\\8", "'8'");
247 CheckParseEq("\\9", "'9'");
248 CheckParseEq("\\11", "'\\x09'");
249 CheckParseEq("\\11a", "'\\x09a'");
250 CheckParseEq("\\011", "'\\x09'");
251 CheckParseEq("\\00011", "'\\x0011'");
252 CheckParseEq("\\118", "'\\x098'");
253 CheckParseEq("\\111", "'I'");
254 CheckParseEq("\\1111", "'I1'");
255 CheckParseEq("(x)(x)(x)\\1", "(: (^ 'x') (^ 'x') (^ 'x') (<- 1))");
256 CheckParseEq("(x)(x)(x)\\2", "(: (^ 'x') (^ 'x') (^ 'x') (<- 2))");
257 CheckParseEq("(x)(x)(x)\\3", "(: (^ 'x') (^ 'x') (^ 'x') (<- 3))");
258 CheckParseEq("(x)(x)(x)\\4", "(: (^ 'x') (^ 'x') (^ 'x') '\\x04')");
259 CheckParseEq("(x)(x)(x)\\1*",
260 "(: (^ 'x') (^ 'x') (^ 'x')"
261 " (# 0 - g (<- 1)))");
262 CheckParseEq("(x)(x)(x)\\2*",
263 "(: (^ 'x') (^ 'x') (^ 'x')"
264 " (# 0 - g (<- 2)))");
265 CheckParseEq("(x)(x)(x)\\3*",
266 "(: (^ 'x') (^ 'x') (^ 'x')"
267 " (# 0 - g (<- 3)))");
268 CheckParseEq("(x)(x)(x)\\4*",
269 "(: (^ 'x') (^ 'x') (^ 'x')"
270 " (# 0 - g '\\x04'))");
271 CheckParseEq("(x)(x)(x)(x)(x)(x)(x)(x)(x)(x)\\10",
272 "(: (^ 'x') (^ 'x') (^ 'x') (^ 'x') (^ 'x') (^ 'x')"
273 " (^ 'x') (^ 'x') (^ 'x') (^ 'x') (<- 10))");
274 CheckParseEq("(x)(x)(x)(x)(x)(x)(x)(x)(x)(x)\\11",
275 "(: (^ 'x') (^ 'x') (^ 'x') (^ 'x') (^ 'x') (^ 'x')"
276 " (^ 'x') (^ 'x') (^ 'x') (^ 'x') '\\x09')");
277 CheckParseEq("(a)\\1", "(: (^ 'a') (<- 1))");
278 CheckParseEq("(a\\1)", "(^ 'a')");
279 CheckParseEq("(\\1a)", "(^ 'a')");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000280 CheckParseEq("(\\2)(\\1)", "(: (^ (<- 2)) (^ (<- 1)))");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000281 CheckParseEq("(?=a)?a", "'a'");
282 CheckParseEq("(?=a){0,10}a", "'a'");
283 CheckParseEq("(?=a){1,10}a", "(: (-> + 'a') 'a')");
284 CheckParseEq("(?=a){9,10}a", "(: (-> + 'a') 'a')");
285 CheckParseEq("(?!a)?a", "'a'");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000286 CheckParseEq("\\1(a)", "(: (<- 1) (^ 'a'))");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000287 CheckParseEq("(?!(a))\\1", "(: (-> - (^ 'a')) (<- 1))");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000288 CheckParseEq("(?!\\1(a\\1)\\1)\\1",
289 "(: (-> - (: (<- 1) (^ 'a') (<- 1))) (<- 1))");
290 CheckParseEq("\\1\\2(a(?:\\1(b\\1\\2))\\2)\\1",
291 "(: (<- 1) (<- 2) (^ (: 'a' (^ 'b') (<- 2))) (<- 1))");
292 if (lookbehind) {
293 CheckParseEq("\\1\\2(a(?<=\\1(b\\1\\2))\\2)\\1",
294 "(: (<- 1) (<- 2) (^ (: 'a' (<- + (^ 'b')) (<- 2))) (<- 1))");
295 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000296 CheckParseEq("[\\0]", "[\\x00]");
297 CheckParseEq("[\\11]", "[\\x09]");
298 CheckParseEq("[\\11a]", "[\\x09 a]");
299 CheckParseEq("[\\011]", "[\\x09]");
300 CheckParseEq("[\\00011]", "[\\x00 1 1]");
301 CheckParseEq("[\\118]", "[\\x09 8]");
302 CheckParseEq("[\\111]", "[I]");
303 CheckParseEq("[\\1111]", "[I 1]");
304 CheckParseEq("\\x34", "'\x34'");
305 CheckParseEq("\\x60", "'\x60'");
306 CheckParseEq("\\x3z", "'x3z'");
307 CheckParseEq("\\c", "'\\c'");
308 CheckParseEq("\\u0034", "'\x34'");
309 CheckParseEq("\\u003z", "'u003z'");
310 CheckParseEq("foo[z]*", "(: 'foo' (# 0 - g [z]))");
Steve Blocka7e24c12009-10-30 11:49:00 +0000311
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000312 // Unicode regexps
313 CheckParseEq("\\u{12345}", "'\\ud808\\udf45'", true);
314 CheckParseEq("\\u{12345}\\u{23456}", "(! '\\ud808\\udf45' '\\ud84d\\udc56')",
315 true);
316 CheckParseEq("\\u{12345}|\\u{23456}", "(| '\\ud808\\udf45' '\\ud84d\\udc56')",
317 true);
318 CheckParseEq("\\u{12345}{3}", "(# 3 3 g '\\ud808\\udf45')", true);
319 CheckParseEq("\\u{12345}*", "(# 0 - g '\\ud808\\udf45')", true);
320
Ben Murdoch097c5b22016-05-18 11:27:45 +0100321 CheckParseEq("\\ud808\\udf45*", "(# 0 - g '\\ud808\\udf45')", true);
322 CheckParseEq("[\\ud808\\udf45-\\ud809\\udccc]", "[\\u{012345}-\\u{0124cc}]",
323 true);
324
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000325 CHECK_SIMPLE("", false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000326 CHECK_SIMPLE("a", true);
327 CHECK_SIMPLE("a|b", false);
328 CHECK_SIMPLE("a\\n", false);
329 CHECK_SIMPLE("^a", false);
330 CHECK_SIMPLE("a$", false);
331 CHECK_SIMPLE("a\\b!", false);
332 CHECK_SIMPLE("a\\Bb", false);
333 CHECK_SIMPLE("a*", false);
334 CHECK_SIMPLE("a*?", false);
335 CHECK_SIMPLE("a?", false);
336 CHECK_SIMPLE("a??", false);
337 CHECK_SIMPLE("a{0,1}?", false);
338 CHECK_SIMPLE("a{1,1}?", false);
339 CHECK_SIMPLE("a{1,2}?", false);
340 CHECK_SIMPLE("a+?", false);
341 CHECK_SIMPLE("(a)", false);
342 CHECK_SIMPLE("(a)\\1", false);
343 CHECK_SIMPLE("(\\1a)", false);
344 CHECK_SIMPLE("\\1(a)", false);
345 CHECK_SIMPLE("a\\s", false);
346 CHECK_SIMPLE("a\\S", false);
347 CHECK_SIMPLE("a\\d", false);
348 CHECK_SIMPLE("a\\D", false);
349 CHECK_SIMPLE("a\\w", false);
350 CHECK_SIMPLE("a\\W", false);
351 CHECK_SIMPLE("a.", false);
352 CHECK_SIMPLE("a\\q", false);
353 CHECK_SIMPLE("a[a]", false);
354 CHECK_SIMPLE("a[^a]", false);
355 CHECK_SIMPLE("a[a-z]", false);
356 CHECK_SIMPLE("a[\\q]", false);
357 CHECK_SIMPLE("a(?:b)", false);
358 CHECK_SIMPLE("a(?=b)", false);
359 CHECK_SIMPLE("a(?!b)", false);
360 CHECK_SIMPLE("\\x60", false);
361 CHECK_SIMPLE("\\u0060", false);
362 CHECK_SIMPLE("\\cA", false);
363 CHECK_SIMPLE("\\q", false);
364 CHECK_SIMPLE("\\1112", false);
365 CHECK_SIMPLE("\\0", false);
366 CHECK_SIMPLE("(a)\\1", false);
367 CHECK_SIMPLE("(?=a)?a", false);
368 CHECK_SIMPLE("(?!a)?a\\1", false);
369 CHECK_SIMPLE("(?:(?=a))a\\1", false);
370
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000371 CheckParseEq("a{}", "'a{}'");
372 CheckParseEq("a{,}", "'a{,}'");
373 CheckParseEq("a{", "'a{'");
374 CheckParseEq("a{z}", "'a{z}'");
375 CheckParseEq("a{1z}", "'a{1z}'");
376 CheckParseEq("a{12z}", "'a{12z}'");
377 CheckParseEq("a{12,", "'a{12,'");
378 CheckParseEq("a{12,3b", "'a{12,3b'");
379 CheckParseEq("{}", "'{}'");
380 CheckParseEq("{,}", "'{,}'");
381 CheckParseEq("{", "'{'");
382 CheckParseEq("{z}", "'{z}'");
383 CheckParseEq("{1z}", "'{1z}'");
384 CheckParseEq("{12z}", "'{12z}'");
385 CheckParseEq("{12,", "'{12,'");
386 CheckParseEq("{12,3b", "'{12,3b'");
Steve Blocka7e24c12009-10-30 11:49:00 +0000387
388 CHECK_MIN_MAX("a", 1, 1);
389 CHECK_MIN_MAX("abc", 3, 3);
390 CHECK_MIN_MAX("a[bc]d", 3, 3);
391 CHECK_MIN_MAX("a|bc", 1, 2);
392 CHECK_MIN_MAX("ab|c", 1, 2);
393 CHECK_MIN_MAX("a||bc", 0, 2);
394 CHECK_MIN_MAX("|", 0, 0);
395 CHECK_MIN_MAX("(?:ab)", 2, 2);
396 CHECK_MIN_MAX("(?:ab|cde)", 2, 3);
397 CHECK_MIN_MAX("(?:ab)|cde", 2, 3);
398 CHECK_MIN_MAX("(ab)", 2, 2);
399 CHECK_MIN_MAX("(ab|cde)", 2, 3);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000400 CHECK_MIN_MAX("(ab)\\1", 2, RegExpTree::kInfinity);
401 CHECK_MIN_MAX("(ab|cde)\\1", 2, RegExpTree::kInfinity);
Steve Blocka7e24c12009-10-30 11:49:00 +0000402 CHECK_MIN_MAX("(?:ab)?", 0, 2);
403 CHECK_MIN_MAX("(?:ab)*", 0, RegExpTree::kInfinity);
404 CHECK_MIN_MAX("(?:ab)+", 2, RegExpTree::kInfinity);
405 CHECK_MIN_MAX("a?", 0, 1);
406 CHECK_MIN_MAX("a*", 0, RegExpTree::kInfinity);
407 CHECK_MIN_MAX("a+", 1, RegExpTree::kInfinity);
408 CHECK_MIN_MAX("a??", 0, 1);
409 CHECK_MIN_MAX("a*?", 0, RegExpTree::kInfinity);
410 CHECK_MIN_MAX("a+?", 1, RegExpTree::kInfinity);
411 CHECK_MIN_MAX("(?:a?)?", 0, 1);
412 CHECK_MIN_MAX("(?:a*)?", 0, RegExpTree::kInfinity);
413 CHECK_MIN_MAX("(?:a+)?", 0, RegExpTree::kInfinity);
414 CHECK_MIN_MAX("(?:a?)+", 0, RegExpTree::kInfinity);
415 CHECK_MIN_MAX("(?:a*)+", 0, RegExpTree::kInfinity);
416 CHECK_MIN_MAX("(?:a+)+", 1, RegExpTree::kInfinity);
417 CHECK_MIN_MAX("(?:a?)*", 0, RegExpTree::kInfinity);
418 CHECK_MIN_MAX("(?:a*)*", 0, RegExpTree::kInfinity);
419 CHECK_MIN_MAX("(?:a+)*", 0, RegExpTree::kInfinity);
420 CHECK_MIN_MAX("a{0}", 0, 0);
421 CHECK_MIN_MAX("(?:a+){0}", 0, 0);
422 CHECK_MIN_MAX("(?:a+){0,0}", 0, 0);
423 CHECK_MIN_MAX("a*b", 1, RegExpTree::kInfinity);
424 CHECK_MIN_MAX("a+b", 2, RegExpTree::kInfinity);
425 CHECK_MIN_MAX("a*b|c", 1, RegExpTree::kInfinity);
426 CHECK_MIN_MAX("a+b|c", 1, RegExpTree::kInfinity);
427 CHECK_MIN_MAX("(?:a{5,1000000}){3,1000000}", 15, RegExpTree::kInfinity);
428 CHECK_MIN_MAX("(?:ab){4,7}", 8, 14);
429 CHECK_MIN_MAX("a\\bc", 2, 2);
430 CHECK_MIN_MAX("a\\Bc", 2, 2);
431 CHECK_MIN_MAX("a\\sc", 3, 3);
432 CHECK_MIN_MAX("a\\Sc", 3, 3);
433 CHECK_MIN_MAX("a(?=b)c", 2, 2);
434 CHECK_MIN_MAX("a(?=bbb|bb)c", 2, 2);
435 CHECK_MIN_MAX("a(?!bbb|bb)c", 2, 2);
436}
437
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000438
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000439TEST(ParserWithLookbehind) {
440 TestRegExpParser(true); // Lookbehind enabled.
441}
442
443
444TEST(ParserWithoutLookbehind) {
445 TestRegExpParser(true); // Lookbehind enabled.
446}
447
448
Steve Blocka7e24c12009-10-30 11:49:00 +0000449TEST(ParserRegression) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000450 CheckParseEq("[A-Z$-][x]", "(! [A-Z $ -] [x])");
451 CheckParseEq("a{3,4*}", "(: 'a{3,' (# 0 - g '4') '}')");
452 CheckParseEq("{", "'{'");
453 CheckParseEq("a|", "(| 'a' %)");
Steve Blocka7e24c12009-10-30 11:49:00 +0000454}
455
456static void ExpectError(const char* input,
457 const char* expected) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000458 v8::HandleScope scope(CcTest::isolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000459 Zone zone;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000460 FlatStringReader reader(CcTest::i_isolate(), CStrVector(input));
Steve Blocka7e24c12009-10-30 11:49:00 +0000461 RegExpCompileData result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000462 CHECK(!v8::internal::RegExpParser::ParseRegExp(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100463 CcTest::i_isolate(), &zone, &reader, JSRegExp::kNone, &result));
Steve Blocka7e24c12009-10-30 11:49:00 +0000464 CHECK(result.tree == NULL);
465 CHECK(!result.error.is_null());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000466 v8::base::SmartArrayPointer<char> str = result.error->ToCString(ALLOW_NULLS);
467 CHECK_EQ(0, strcmp(expected, str.get()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000468}
469
470
471TEST(Errors) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000472 const char* kEndBackslash = "\\ at end of pattern";
473 ExpectError("\\", kEndBackslash);
474 const char* kUnterminatedGroup = "Unterminated group";
475 ExpectError("(foo", kUnterminatedGroup);
476 const char* kInvalidGroup = "Invalid group";
477 ExpectError("(?", kInvalidGroup);
478 const char* kUnterminatedCharacterClass = "Unterminated character class";
479 ExpectError("[", kUnterminatedCharacterClass);
480 ExpectError("[a-", kUnterminatedCharacterClass);
481 const char* kNothingToRepeat = "Nothing to repeat";
482 ExpectError("*", kNothingToRepeat);
483 ExpectError("?", kNothingToRepeat);
484 ExpectError("+", kNothingToRepeat);
485 ExpectError("{1}", kNothingToRepeat);
486 ExpectError("{1,2}", kNothingToRepeat);
487 ExpectError("{1,}", kNothingToRepeat);
488
489 // Check that we don't allow more than kMaxCapture captures
490 const int kMaxCaptures = 1 << 16; // Must match RegExpParser::kMaxCaptures.
491 const char* kTooManyCaptures = "Too many captures";
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400492 std::ostringstream os;
Steve Blocka7e24c12009-10-30 11:49:00 +0000493 for (int i = 0; i <= kMaxCaptures; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000494 os << "()";
Steve Blocka7e24c12009-10-30 11:49:00 +0000495 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400496 ExpectError(os.str().c_str(), kTooManyCaptures);
Steve Blocka7e24c12009-10-30 11:49:00 +0000497}
498
499
500static bool IsDigit(uc16 c) {
501 return ('0' <= c && c <= '9');
502}
503
504
505static bool NotDigit(uc16 c) {
506 return !IsDigit(c);
507}
508
509
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000510static bool IsWhiteSpaceOrLineTerminator(uc16 c) {
511 // According to ECMA 5.1, 15.10.2.12 the CharacterClassEscape \s includes
512 // WhiteSpace (7.2) and LineTerminator (7.3) values.
513 return v8::internal::WhiteSpaceOrLineTerminator::Is(c);
Steve Blocka7e24c12009-10-30 11:49:00 +0000514}
515
516
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000517static bool NotWhiteSpaceNorLineTermiantor(uc16 c) {
518 return !IsWhiteSpaceOrLineTerminator(c);
Steve Blocka7e24c12009-10-30 11:49:00 +0000519}
520
521
522static bool NotWord(uc16 c) {
523 return !IsRegExpWord(c);
524}
525
526
527static void TestCharacterClassEscapes(uc16 c, bool (pred)(uc16 c)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000528 Zone zone;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000529 ZoneList<CharacterRange>* ranges =
530 new(&zone) ZoneList<CharacterRange>(2, &zone);
531 CharacterRange::AddClassEscape(c, ranges, &zone);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100532 for (uc32 i = 0; i < (1 << 16); i++) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000533 bool in_class = false;
534 for (int j = 0; !in_class && j < ranges->length(); j++) {
535 CharacterRange& range = ranges->at(j);
536 in_class = (range.from() <= i && i <= range.to());
537 }
538 CHECK_EQ(pred(i), in_class);
539 }
540}
541
542
543TEST(CharacterClassEscapes) {
544 TestCharacterClassEscapes('.', IsRegExpNewline);
545 TestCharacterClassEscapes('d', IsDigit);
546 TestCharacterClassEscapes('D', NotDigit);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000547 TestCharacterClassEscapes('s', IsWhiteSpaceOrLineTerminator);
548 TestCharacterClassEscapes('S', NotWhiteSpaceNorLineTermiantor);
Steve Blocka7e24c12009-10-30 11:49:00 +0000549 TestCharacterClassEscapes('w', IsRegExpWord);
550 TestCharacterClassEscapes('W', NotWord);
551}
552
553
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000554static RegExpNode* Compile(const char* input, bool multiline, bool unicode,
555 bool is_one_byte, Zone* zone) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000556 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100557 FlatStringReader reader(isolate, CStrVector(input));
Steve Blocka7e24c12009-10-30 11:49:00 +0000558 RegExpCompileData compile_data;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100559 JSRegExp::Flags flags = JSRegExp::kNone;
560 if (multiline) flags = JSRegExp::kMultiline;
561 if (unicode) flags = JSRegExp::kUnicode;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000562 if (!v8::internal::RegExpParser::ParseRegExp(CcTest::i_isolate(), zone,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100563 &reader, flags, &compile_data))
Steve Blocka7e24c12009-10-30 11:49:00 +0000564 return NULL;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000565 Handle<String> pattern = isolate->factory()
566 ->NewStringFromUtf8(CStrVector(input))
567 .ToHandleChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000568 Handle<String> sample_subject =
569 isolate->factory()->NewStringFromUtf8(CStrVector("")).ToHandleChecked();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100570 RegExpEngine::Compile(isolate, zone, &compile_data, flags, pattern,
571 sample_subject, is_one_byte);
Steve Blocka7e24c12009-10-30 11:49:00 +0000572 return compile_data.node;
573}
574
575
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000576static void Execute(const char* input, bool multiline, bool unicode,
577 bool is_one_byte, bool dot_output = false) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000578 v8::HandleScope scope(CcTest::isolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000579 Zone zone;
580 RegExpNode* node = Compile(input, multiline, unicode, is_one_byte, &zone);
Steve Blocka7e24c12009-10-30 11:49:00 +0000581 USE(node);
582#ifdef DEBUG
583 if (dot_output) {
584 RegExpEngine::DotPrint(input, node, false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000585 }
586#endif // DEBUG
587}
588
589
590class TestConfig {
591 public:
592 typedef int Key;
593 typedef int Value;
594 static const int kNoKey;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100595 static int NoValue() { return 0; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000596 static inline int Compare(int a, int b) {
597 if (a < b)
598 return -1;
599 else if (a > b)
600 return 1;
601 else
602 return 0;
603 }
604};
605
606
607const int TestConfig::kNoKey = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000608
609
610static unsigned PseudoRandom(int i, int j) {
611 return ~(~((i * 781) ^ (j * 329)));
612}
613
614
615TEST(SplayTreeSimple) {
616 static const unsigned kLimit = 1000;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000617 Zone zone;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000618 ZoneSplayTree<TestConfig> tree(&zone);
Steve Blocka7e24c12009-10-30 11:49:00 +0000619 bool seen[kLimit];
620 for (unsigned i = 0; i < kLimit; i++) seen[i] = false;
621#define CHECK_MAPS_EQUAL() do { \
622 for (unsigned k = 0; k < kLimit; k++) \
623 CHECK_EQ(seen[k], tree.Find(k, &loc)); \
624 } while (false)
625 for (int i = 0; i < 50; i++) {
626 for (int j = 0; j < 50; j++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000627 int next = PseudoRandom(i, j) % kLimit;
Steve Blocka7e24c12009-10-30 11:49:00 +0000628 if (seen[next]) {
629 // We've already seen this one. Check the value and remove
630 // it.
631 ZoneSplayTree<TestConfig>::Locator loc;
632 CHECK(tree.Find(next, &loc));
633 CHECK_EQ(next, loc.key());
634 CHECK_EQ(3 * next, loc.value());
635 tree.Remove(next);
636 seen[next] = false;
637 CHECK_MAPS_EQUAL();
638 } else {
639 // Check that it wasn't there already and then add it.
640 ZoneSplayTree<TestConfig>::Locator loc;
641 CHECK(!tree.Find(next, &loc));
642 CHECK(tree.Insert(next, &loc));
643 CHECK_EQ(next, loc.key());
644 loc.set_value(3 * next);
645 seen[next] = true;
646 CHECK_MAPS_EQUAL();
647 }
648 int val = PseudoRandom(j, i) % kLimit;
649 if (seen[val]) {
650 ZoneSplayTree<TestConfig>::Locator loc;
651 CHECK(tree.FindGreatestLessThan(val, &loc));
652 CHECK_EQ(loc.key(), val);
653 break;
654 }
655 val = PseudoRandom(i + j, i - j) % kLimit;
656 if (seen[val]) {
657 ZoneSplayTree<TestConfig>::Locator loc;
658 CHECK(tree.FindLeastGreaterThan(val, &loc));
659 CHECK_EQ(loc.key(), val);
660 break;
661 }
662 }
663 }
664}
665
666
667TEST(DispatchTableConstruction) {
668 // Initialize test data.
669 static const int kLimit = 1000;
670 static const int kRangeCount = 8;
671 static const int kRangeSize = 16;
672 uc16 ranges[kRangeCount][2 * kRangeSize];
673 for (int i = 0; i < kRangeCount; i++) {
674 Vector<uc16> range(ranges[i], 2 * kRangeSize);
675 for (int j = 0; j < 2 * kRangeSize; j++) {
676 range[j] = PseudoRandom(i + 25, j + 87) % kLimit;
677 }
678 range.Sort();
679 for (int j = 1; j < 2 * kRangeSize; j++) {
680 CHECK(range[j-1] <= range[j]);
681 }
682 }
683 // Enter test data into dispatch table.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000684 Zone zone;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000685 DispatchTable table(&zone);
Steve Blocka7e24c12009-10-30 11:49:00 +0000686 for (int i = 0; i < kRangeCount; i++) {
687 uc16* range = ranges[i];
688 for (int j = 0; j < 2 * kRangeSize; j += 2)
Ben Murdoch097c5b22016-05-18 11:27:45 +0100689 table.AddRange(CharacterRange::Range(range[j], range[j + 1]), i, &zone);
Steve Blocka7e24c12009-10-30 11:49:00 +0000690 }
691 // Check that the table looks as we would expect
692 for (int p = 0; p < kLimit; p++) {
693 OutSet* outs = table.Get(p);
694 for (int j = 0; j < kRangeCount; j++) {
695 uc16* range = ranges[j];
696 bool is_on = false;
697 for (int k = 0; !is_on && (k < 2 * kRangeSize); k += 2)
698 is_on = (range[k] <= p && p <= range[k + 1]);
699 CHECK_EQ(is_on, outs->Get(j));
700 }
701 }
702}
703
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000704
Leon Clarkee46be812010-01-19 14:06:41 +0000705// Test of debug-only syntax.
706#ifdef DEBUG
707
708TEST(ParsePossessiveRepetition) {
709 bool old_flag_value = FLAG_regexp_possessive_quantifier;
710
711 // Enable possessive quantifier syntax.
712 FLAG_regexp_possessive_quantifier = true;
713
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000714 CheckParseEq("a*+", "(# 0 - p 'a')");
715 CheckParseEq("a++", "(# 1 - p 'a')");
716 CheckParseEq("a?+", "(# 0 1 p 'a')");
717 CheckParseEq("a{10,20}+", "(# 10 20 p 'a')");
718 CheckParseEq("za{10,20}+b", "(: 'z' (# 10 20 p 'a') 'b')");
Leon Clarkee46be812010-01-19 14:06:41 +0000719
720 // Disable possessive quantifier syntax.
721 FLAG_regexp_possessive_quantifier = false;
722
723 CHECK_PARSE_ERROR("a*+");
724 CHECK_PARSE_ERROR("a++");
725 CHECK_PARSE_ERROR("a?+");
726 CHECK_PARSE_ERROR("a{10,20}+");
727 CHECK_PARSE_ERROR("a{10,20}+b");
728
729 FLAG_regexp_possessive_quantifier = old_flag_value;
730}
731
732#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000733
734// Tests of interpreter.
735
736
Steve Block6ded16b2010-05-10 14:33:55 +0100737#ifndef V8_INTERPRETED_REGEXP
Steve Blocka7e24c12009-10-30 11:49:00 +0000738
739#if V8_TARGET_ARCH_IA32
740typedef RegExpMacroAssemblerIA32 ArchRegExpMacroAssembler;
741#elif V8_TARGET_ARCH_X64
742typedef RegExpMacroAssemblerX64 ArchRegExpMacroAssembler;
743#elif V8_TARGET_ARCH_ARM
744typedef RegExpMacroAssemblerARM ArchRegExpMacroAssembler;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000745#elif V8_TARGET_ARCH_ARM64
746typedef RegExpMacroAssemblerARM64 ArchRegExpMacroAssembler;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000747#elif V8_TARGET_ARCH_PPC
748typedef RegExpMacroAssemblerPPC ArchRegExpMacroAssembler;
Andrei Popescu31002712010-02-23 13:46:05 +0000749#elif V8_TARGET_ARCH_MIPS
Steve Block44f0eee2011-05-26 01:26:41 +0100750typedef RegExpMacroAssemblerMIPS ArchRegExpMacroAssembler;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000751#elif V8_TARGET_ARCH_MIPS64
752typedef RegExpMacroAssemblerMIPS ArchRegExpMacroAssembler;
753#elif V8_TARGET_ARCH_X87
754typedef RegExpMacroAssemblerX87 ArchRegExpMacroAssembler;
Steve Blocka7e24c12009-10-30 11:49:00 +0000755#endif
756
757class ContextInitializer {
758 public:
759 ContextInitializer()
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000760 : scope_(CcTest::isolate()),
761 env_(v8::Context::New(CcTest::isolate())) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000762 env_->Enter();
763 }
764 ~ContextInitializer() {
765 env_->Exit();
Steve Blocka7e24c12009-10-30 11:49:00 +0000766 }
767 private:
Steve Blocka7e24c12009-10-30 11:49:00 +0000768 v8::HandleScope scope_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000769 v8::Local<v8::Context> env_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000770};
771
772
773static ArchRegExpMacroAssembler::Result Execute(Code* code,
774 String* input,
775 int start_offset,
776 const byte* input_start,
777 const byte* input_end,
Leon Clarked91b9f72010-01-27 17:25:45 +0000778 int* captures) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000779 return NativeRegExpMacroAssembler::Execute(
780 code,
781 input,
782 start_offset,
783 input_start,
784 input_end,
Steve Block44f0eee2011-05-26 01:26:41 +0100785 captures,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000786 0,
787 CcTest::i_isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000788}
789
790
791TEST(MacroAssemblerNativeSuccess) {
792 v8::V8::Initialize();
793 ContextInitializer initializer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000794 Isolate* isolate = CcTest::i_isolate();
795 Factory* factory = isolate->factory();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000796 Zone zone;
Steve Blocka7e24c12009-10-30 11:49:00 +0000797
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000798 ArchRegExpMacroAssembler m(isolate, &zone, NativeRegExpMacroAssembler::LATIN1,
799 4);
Steve Blocka7e24c12009-10-30 11:49:00 +0000800
801 m.Succeed();
802
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000803 Handle<String> source = factory->NewStringFromStaticChars("");
Steve Blocka7e24c12009-10-30 11:49:00 +0000804 Handle<Object> code_object = m.GetCode(source);
805 Handle<Code> code = Handle<Code>::cast(code_object);
806
807 int captures[4] = {42, 37, 87, 117};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000808 Handle<String> input = factory->NewStringFromStaticChars("foofoo");
809 Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input);
Steve Blocka7e24c12009-10-30 11:49:00 +0000810 const byte* start_adr =
811 reinterpret_cast<const byte*>(seq_input->GetCharsAddress());
812
813 NativeRegExpMacroAssembler::Result result =
814 Execute(*code,
815 *input,
816 0,
817 start_adr,
818 start_adr + seq_input->length(),
Leon Clarked91b9f72010-01-27 17:25:45 +0000819 captures);
Steve Blocka7e24c12009-10-30 11:49:00 +0000820
821 CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
822 CHECK_EQ(-1, captures[0]);
823 CHECK_EQ(-1, captures[1]);
824 CHECK_EQ(-1, captures[2]);
825 CHECK_EQ(-1, captures[3]);
826}
827
828
829TEST(MacroAssemblerNativeSimple) {
830 v8::V8::Initialize();
831 ContextInitializer initializer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000832 Isolate* isolate = CcTest::i_isolate();
833 Factory* factory = isolate->factory();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000834 Zone zone;
Steve Blocka7e24c12009-10-30 11:49:00 +0000835
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000836 ArchRegExpMacroAssembler m(isolate, &zone, NativeRegExpMacroAssembler::LATIN1,
837 4);
Steve Blocka7e24c12009-10-30 11:49:00 +0000838
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000839 Label fail, backtrack;
840 m.PushBacktrack(&fail);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000841 m.CheckNotAtStart(0, NULL);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000842 m.LoadCurrentCharacter(2, NULL);
843 m.CheckNotCharacter('o', NULL);
844 m.LoadCurrentCharacter(1, NULL, false);
845 m.CheckNotCharacter('o', NULL);
846 m.LoadCurrentCharacter(0, NULL, false);
847 m.CheckNotCharacter('f', NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000848 m.WriteCurrentPositionToRegister(0, 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000849 m.WriteCurrentPositionToRegister(1, 3);
Steve Blocka7e24c12009-10-30 11:49:00 +0000850 m.AdvanceCurrentPosition(3);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000851 m.PushBacktrack(&backtrack);
Steve Blocka7e24c12009-10-30 11:49:00 +0000852 m.Succeed();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000853 m.Bind(&backtrack);
854 m.Backtrack();
Steve Blocka7e24c12009-10-30 11:49:00 +0000855 m.Bind(&fail);
856 m.Fail();
857
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000858 Handle<String> source = factory->NewStringFromStaticChars("^foo");
Steve Blocka7e24c12009-10-30 11:49:00 +0000859 Handle<Object> code_object = m.GetCode(source);
860 Handle<Code> code = Handle<Code>::cast(code_object);
861
862 int captures[4] = {42, 37, 87, 117};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000863 Handle<String> input = factory->NewStringFromStaticChars("foofoo");
864 Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input);
Steve Blocka7e24c12009-10-30 11:49:00 +0000865 Address start_adr = seq_input->GetCharsAddress();
866
867 NativeRegExpMacroAssembler::Result result =
868 Execute(*code,
869 *input,
870 0,
871 start_adr,
872 start_adr + input->length(),
Leon Clarked91b9f72010-01-27 17:25:45 +0000873 captures);
Steve Blocka7e24c12009-10-30 11:49:00 +0000874
875 CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
876 CHECK_EQ(0, captures[0]);
877 CHECK_EQ(3, captures[1]);
878 CHECK_EQ(-1, captures[2]);
879 CHECK_EQ(-1, captures[3]);
880
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000881 input = factory->NewStringFromStaticChars("barbarbar");
882 seq_input = Handle<SeqOneByteString>::cast(input);
Steve Blocka7e24c12009-10-30 11:49:00 +0000883 start_adr = seq_input->GetCharsAddress();
884
885 result = Execute(*code,
886 *input,
887 0,
888 start_adr,
889 start_adr + input->length(),
Leon Clarked91b9f72010-01-27 17:25:45 +0000890 captures);
Steve Blocka7e24c12009-10-30 11:49:00 +0000891
892 CHECK_EQ(NativeRegExpMacroAssembler::FAILURE, result);
893}
894
895
896TEST(MacroAssemblerNativeSimpleUC16) {
897 v8::V8::Initialize();
898 ContextInitializer initializer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000899 Isolate* isolate = CcTest::i_isolate();
900 Factory* factory = isolate->factory();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000901 Zone zone;
Steve Blocka7e24c12009-10-30 11:49:00 +0000902
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000903 ArchRegExpMacroAssembler m(isolate, &zone, NativeRegExpMacroAssembler::UC16,
904 4);
Steve Blocka7e24c12009-10-30 11:49:00 +0000905
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000906 Label fail, backtrack;
907 m.PushBacktrack(&fail);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000908 m.CheckNotAtStart(0, NULL);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000909 m.LoadCurrentCharacter(2, NULL);
910 m.CheckNotCharacter('o', NULL);
911 m.LoadCurrentCharacter(1, NULL, false);
912 m.CheckNotCharacter('o', NULL);
913 m.LoadCurrentCharacter(0, NULL, false);
914 m.CheckNotCharacter('f', NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000915 m.WriteCurrentPositionToRegister(0, 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000916 m.WriteCurrentPositionToRegister(1, 3);
Steve Blocka7e24c12009-10-30 11:49:00 +0000917 m.AdvanceCurrentPosition(3);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000918 m.PushBacktrack(&backtrack);
Steve Blocka7e24c12009-10-30 11:49:00 +0000919 m.Succeed();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000920 m.Bind(&backtrack);
921 m.Backtrack();
Steve Blocka7e24c12009-10-30 11:49:00 +0000922 m.Bind(&fail);
923 m.Fail();
924
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000925 Handle<String> source = factory->NewStringFromStaticChars("^foo");
Steve Blocka7e24c12009-10-30 11:49:00 +0000926 Handle<Object> code_object = m.GetCode(source);
927 Handle<Code> code = Handle<Code>::cast(code_object);
928
929 int captures[4] = {42, 37, 87, 117};
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100930 const uc16 input_data[6] = {'f', 'o', 'o', 'f', 'o',
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000931 static_cast<uc16>(0x2603)};
932 Handle<String> input = factory->NewStringFromTwoByte(
933 Vector<const uc16>(input_data, 6)).ToHandleChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +0000934 Handle<SeqTwoByteString> seq_input = Handle<SeqTwoByteString>::cast(input);
935 Address start_adr = seq_input->GetCharsAddress();
936
937 NativeRegExpMacroAssembler::Result result =
938 Execute(*code,
939 *input,
940 0,
941 start_adr,
942 start_adr + input->length(),
Leon Clarked91b9f72010-01-27 17:25:45 +0000943 captures);
Steve Blocka7e24c12009-10-30 11:49:00 +0000944
945 CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
946 CHECK_EQ(0, captures[0]);
947 CHECK_EQ(3, captures[1]);
948 CHECK_EQ(-1, captures[2]);
949 CHECK_EQ(-1, captures[3]);
950
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100951 const uc16 input_data2[9] = {'b', 'a', 'r', 'b', 'a', 'r', 'b', 'a',
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000952 static_cast<uc16>(0x2603)};
953 input = factory->NewStringFromTwoByte(
954 Vector<const uc16>(input_data2, 9)).ToHandleChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +0000955 seq_input = Handle<SeqTwoByteString>::cast(input);
956 start_adr = seq_input->GetCharsAddress();
957
958 result = Execute(*code,
959 *input,
960 0,
961 start_adr,
962 start_adr + input->length() * 2,
Leon Clarked91b9f72010-01-27 17:25:45 +0000963 captures);
Steve Blocka7e24c12009-10-30 11:49:00 +0000964
965 CHECK_EQ(NativeRegExpMacroAssembler::FAILURE, result);
966}
967
968
969TEST(MacroAssemblerNativeBacktrack) {
970 v8::V8::Initialize();
971 ContextInitializer initializer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000972 Isolate* isolate = CcTest::i_isolate();
973 Factory* factory = isolate->factory();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000974 Zone zone;
Steve Blocka7e24c12009-10-30 11:49:00 +0000975
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000976 ArchRegExpMacroAssembler m(isolate, &zone, NativeRegExpMacroAssembler::LATIN1,
977 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000978
979 Label fail;
980 Label backtrack;
981 m.LoadCurrentCharacter(10, &fail);
982 m.Succeed();
983 m.Bind(&fail);
984 m.PushBacktrack(&backtrack);
985 m.LoadCurrentCharacter(10, NULL);
986 m.Succeed();
987 m.Bind(&backtrack);
988 m.Fail();
989
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000990 Handle<String> source = factory->NewStringFromStaticChars("..........");
Steve Blocka7e24c12009-10-30 11:49:00 +0000991 Handle<Object> code_object = m.GetCode(source);
992 Handle<Code> code = Handle<Code>::cast(code_object);
993
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000994 Handle<String> input = factory->NewStringFromStaticChars("foofoo");
995 Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input);
Steve Blocka7e24c12009-10-30 11:49:00 +0000996 Address start_adr = seq_input->GetCharsAddress();
997
998 NativeRegExpMacroAssembler::Result result =
999 Execute(*code,
1000 *input,
1001 0,
1002 start_adr,
1003 start_adr + input->length(),
Leon Clarked91b9f72010-01-27 17:25:45 +00001004 NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001005
1006 CHECK_EQ(NativeRegExpMacroAssembler::FAILURE, result);
1007}
1008
1009
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001010TEST(MacroAssemblerNativeBackReferenceLATIN1) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001011 v8::V8::Initialize();
1012 ContextInitializer initializer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001013 Isolate* isolate = CcTest::i_isolate();
1014 Factory* factory = isolate->factory();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001015 Zone zone;
Steve Blocka7e24c12009-10-30 11:49:00 +00001016
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001017 ArchRegExpMacroAssembler m(isolate, &zone, NativeRegExpMacroAssembler::LATIN1,
1018 4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001019
1020 m.WriteCurrentPositionToRegister(0, 0);
1021 m.AdvanceCurrentPosition(2);
1022 m.WriteCurrentPositionToRegister(1, 0);
1023 Label nomatch;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001024 m.CheckNotBackReference(0, false, &nomatch);
Steve Blocka7e24c12009-10-30 11:49:00 +00001025 m.Fail();
1026 m.Bind(&nomatch);
1027 m.AdvanceCurrentPosition(2);
1028 Label missing_match;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001029 m.CheckNotBackReference(0, false, &missing_match);
Steve Blocka7e24c12009-10-30 11:49:00 +00001030 m.WriteCurrentPositionToRegister(2, 0);
1031 m.Succeed();
1032 m.Bind(&missing_match);
1033 m.Fail();
1034
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001035 Handle<String> source = factory->NewStringFromStaticChars("^(..)..\1");
Steve Blocka7e24c12009-10-30 11:49:00 +00001036 Handle<Object> code_object = m.GetCode(source);
1037 Handle<Code> code = Handle<Code>::cast(code_object);
1038
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001039 Handle<String> input = factory->NewStringFromStaticChars("fooofo");
1040 Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input);
Steve Blocka7e24c12009-10-30 11:49:00 +00001041 Address start_adr = seq_input->GetCharsAddress();
1042
1043 int output[4];
1044 NativeRegExpMacroAssembler::Result result =
1045 Execute(*code,
1046 *input,
1047 0,
1048 start_adr,
1049 start_adr + input->length(),
Leon Clarked91b9f72010-01-27 17:25:45 +00001050 output);
Steve Blocka7e24c12009-10-30 11:49:00 +00001051
1052 CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
1053 CHECK_EQ(0, output[0]);
1054 CHECK_EQ(2, output[1]);
1055 CHECK_EQ(6, output[2]);
1056 CHECK_EQ(-1, output[3]);
1057}
1058
1059
1060TEST(MacroAssemblerNativeBackReferenceUC16) {
1061 v8::V8::Initialize();
1062 ContextInitializer initializer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001063 Isolate* isolate = CcTest::i_isolate();
1064 Factory* factory = isolate->factory();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001065 Zone zone;
Steve Blocka7e24c12009-10-30 11:49:00 +00001066
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001067 ArchRegExpMacroAssembler m(isolate, &zone, NativeRegExpMacroAssembler::UC16,
1068 4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001069
1070 m.WriteCurrentPositionToRegister(0, 0);
1071 m.AdvanceCurrentPosition(2);
1072 m.WriteCurrentPositionToRegister(1, 0);
1073 Label nomatch;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001074 m.CheckNotBackReference(0, false, &nomatch);
Steve Blocka7e24c12009-10-30 11:49:00 +00001075 m.Fail();
1076 m.Bind(&nomatch);
1077 m.AdvanceCurrentPosition(2);
1078 Label missing_match;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001079 m.CheckNotBackReference(0, false, &missing_match);
Steve Blocka7e24c12009-10-30 11:49:00 +00001080 m.WriteCurrentPositionToRegister(2, 0);
1081 m.Succeed();
1082 m.Bind(&missing_match);
1083 m.Fail();
1084
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001085 Handle<String> source = factory->NewStringFromStaticChars("^(..)..\1");
Steve Blocka7e24c12009-10-30 11:49:00 +00001086 Handle<Object> code_object = m.GetCode(source);
1087 Handle<Code> code = Handle<Code>::cast(code_object);
1088
1089 const uc16 input_data[6] = {'f', 0x2028, 'o', 'o', 'f', 0x2028};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001090 Handle<String> input = factory->NewStringFromTwoByte(
1091 Vector<const uc16>(input_data, 6)).ToHandleChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001092 Handle<SeqTwoByteString> seq_input = Handle<SeqTwoByteString>::cast(input);
1093 Address start_adr = seq_input->GetCharsAddress();
1094
1095 int output[4];
1096 NativeRegExpMacroAssembler::Result result =
1097 Execute(*code,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001098 *input,
1099 0,
1100 start_adr,
1101 start_adr + input->length() * 2,
1102 output);
Steve Blocka7e24c12009-10-30 11:49:00 +00001103
1104 CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
1105 CHECK_EQ(0, output[0]);
1106 CHECK_EQ(2, output[1]);
1107 CHECK_EQ(6, output[2]);
1108 CHECK_EQ(-1, output[3]);
1109}
1110
1111
1112
1113TEST(MacroAssemblernativeAtStart) {
1114 v8::V8::Initialize();
1115 ContextInitializer initializer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001116 Isolate* isolate = CcTest::i_isolate();
1117 Factory* factory = isolate->factory();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001118 Zone zone;
Steve Blocka7e24c12009-10-30 11:49:00 +00001119
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001120 ArchRegExpMacroAssembler m(isolate, &zone, NativeRegExpMacroAssembler::LATIN1,
1121 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001122
1123 Label not_at_start, newline, fail;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001124 m.CheckNotAtStart(0, &not_at_start);
Steve Blocka7e24c12009-10-30 11:49:00 +00001125 // Check that prevchar = '\n' and current = 'f'.
1126 m.CheckCharacter('\n', &newline);
1127 m.Bind(&fail);
1128 m.Fail();
1129 m.Bind(&newline);
1130 m.LoadCurrentCharacter(0, &fail);
1131 m.CheckNotCharacter('f', &fail);
1132 m.Succeed();
1133
1134 m.Bind(&not_at_start);
1135 // Check that prevchar = 'o' and current = 'b'.
1136 Label prevo;
1137 m.CheckCharacter('o', &prevo);
1138 m.Fail();
1139 m.Bind(&prevo);
1140 m.LoadCurrentCharacter(0, &fail);
1141 m.CheckNotCharacter('b', &fail);
1142 m.Succeed();
1143
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001144 Handle<String> source = factory->NewStringFromStaticChars("(^f|ob)");
Steve Blocka7e24c12009-10-30 11:49:00 +00001145 Handle<Object> code_object = m.GetCode(source);
1146 Handle<Code> code = Handle<Code>::cast(code_object);
1147
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001148 Handle<String> input = factory->NewStringFromStaticChars("foobar");
1149 Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input);
Steve Blocka7e24c12009-10-30 11:49:00 +00001150 Address start_adr = seq_input->GetCharsAddress();
1151
1152 NativeRegExpMacroAssembler::Result result =
1153 Execute(*code,
1154 *input,
1155 0,
1156 start_adr,
1157 start_adr + input->length(),
Leon Clarked91b9f72010-01-27 17:25:45 +00001158 NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001159
1160 CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
1161
1162 result = Execute(*code,
1163 *input,
1164 3,
1165 start_adr + 3,
1166 start_adr + input->length(),
Leon Clarked91b9f72010-01-27 17:25:45 +00001167 NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001168
1169 CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
1170}
1171
1172
1173TEST(MacroAssemblerNativeBackRefNoCase) {
1174 v8::V8::Initialize();
1175 ContextInitializer initializer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001176 Isolate* isolate = CcTest::i_isolate();
1177 Factory* factory = isolate->factory();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001178 Zone zone;
Steve Blocka7e24c12009-10-30 11:49:00 +00001179
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001180 ArchRegExpMacroAssembler m(isolate, &zone, NativeRegExpMacroAssembler::LATIN1,
1181 4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001182
1183 Label fail, succ;
1184
1185 m.WriteCurrentPositionToRegister(0, 0);
1186 m.WriteCurrentPositionToRegister(2, 0);
1187 m.AdvanceCurrentPosition(3);
1188 m.WriteCurrentPositionToRegister(3, 0);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001189 m.CheckNotBackReferenceIgnoreCase(2, false, false, &fail); // Match "AbC".
1190 m.CheckNotBackReferenceIgnoreCase(2, false, false, &fail); // Match "ABC".
Steve Blocka7e24c12009-10-30 11:49:00 +00001191 Label expected_fail;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001192 m.CheckNotBackReferenceIgnoreCase(2, false, false, &expected_fail);
Steve Blocka7e24c12009-10-30 11:49:00 +00001193 m.Bind(&fail);
1194 m.Fail();
1195
1196 m.Bind(&expected_fail);
1197 m.AdvanceCurrentPosition(3); // Skip "xYz"
Ben Murdoch097c5b22016-05-18 11:27:45 +01001198 m.CheckNotBackReferenceIgnoreCase(2, false, false, &succ);
Steve Blocka7e24c12009-10-30 11:49:00 +00001199 m.Fail();
1200
1201 m.Bind(&succ);
1202 m.WriteCurrentPositionToRegister(1, 0);
1203 m.Succeed();
1204
1205 Handle<String> source =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001206 factory->NewStringFromStaticChars("^(abc)\1\1(?!\1)...(?!\1)");
Steve Blocka7e24c12009-10-30 11:49:00 +00001207 Handle<Object> code_object = m.GetCode(source);
1208 Handle<Code> code = Handle<Code>::cast(code_object);
1209
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001210 Handle<String> input = factory->NewStringFromStaticChars("aBcAbCABCxYzab");
1211 Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input);
Steve Blocka7e24c12009-10-30 11:49:00 +00001212 Address start_adr = seq_input->GetCharsAddress();
1213
1214 int output[4];
1215 NativeRegExpMacroAssembler::Result result =
1216 Execute(*code,
1217 *input,
1218 0,
1219 start_adr,
1220 start_adr + input->length(),
Leon Clarked91b9f72010-01-27 17:25:45 +00001221 output);
Steve Blocka7e24c12009-10-30 11:49:00 +00001222
1223 CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
1224 CHECK_EQ(0, output[0]);
1225 CHECK_EQ(12, output[1]);
1226 CHECK_EQ(0, output[2]);
1227 CHECK_EQ(3, output[3]);
1228}
1229
1230
1231
1232TEST(MacroAssemblerNativeRegisters) {
1233 v8::V8::Initialize();
1234 ContextInitializer initializer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001235 Isolate* isolate = CcTest::i_isolate();
1236 Factory* factory = isolate->factory();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001237 Zone zone;
Steve Blocka7e24c12009-10-30 11:49:00 +00001238
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001239 ArchRegExpMacroAssembler m(isolate, &zone, NativeRegExpMacroAssembler::LATIN1,
1240 6);
Steve Blocka7e24c12009-10-30 11:49:00 +00001241
1242 uc16 foo_chars[3] = {'f', 'o', 'o'};
1243 Vector<const uc16> foo(foo_chars, 3);
1244
1245 enum registers { out1, out2, out3, out4, out5, out6, sp, loop_cnt };
1246 Label fail;
1247 Label backtrack;
1248 m.WriteCurrentPositionToRegister(out1, 0); // Output: [0]
1249 m.PushRegister(out1, RegExpMacroAssembler::kNoStackLimitCheck);
1250 m.PushBacktrack(&backtrack);
1251 m.WriteStackPointerToRegister(sp);
1252 // Fill stack and registers
1253 m.AdvanceCurrentPosition(2);
1254 m.WriteCurrentPositionToRegister(out1, 0);
1255 m.PushRegister(out1, RegExpMacroAssembler::kNoStackLimitCheck);
1256 m.PushBacktrack(&fail);
1257 // Drop backtrack stack frames.
1258 m.ReadStackPointerFromRegister(sp);
1259 // And take the first backtrack (to &backtrack)
1260 m.Backtrack();
1261
1262 m.PushCurrentPosition();
1263 m.AdvanceCurrentPosition(2);
1264 m.PopCurrentPosition();
1265
1266 m.Bind(&backtrack);
1267 m.PopRegister(out1);
1268 m.ReadCurrentPositionFromRegister(out1);
1269 m.AdvanceCurrentPosition(3);
1270 m.WriteCurrentPositionToRegister(out2, 0); // [0,3]
1271
1272 Label loop;
1273 m.SetRegister(loop_cnt, 0); // loop counter
1274 m.Bind(&loop);
1275 m.AdvanceRegister(loop_cnt, 1);
1276 m.AdvanceCurrentPosition(1);
1277 m.IfRegisterLT(loop_cnt, 3, &loop);
1278 m.WriteCurrentPositionToRegister(out3, 0); // [0,3,6]
1279
1280 Label loop2;
1281 m.SetRegister(loop_cnt, 2); // loop counter
1282 m.Bind(&loop2);
1283 m.AdvanceRegister(loop_cnt, -1);
1284 m.AdvanceCurrentPosition(1);
1285 m.IfRegisterGE(loop_cnt, 0, &loop2);
1286 m.WriteCurrentPositionToRegister(out4, 0); // [0,3,6,9]
1287
1288 Label loop3;
1289 Label exit_loop3;
1290 m.PushRegister(out4, RegExpMacroAssembler::kNoStackLimitCheck);
1291 m.PushRegister(out4, RegExpMacroAssembler::kNoStackLimitCheck);
1292 m.ReadCurrentPositionFromRegister(out3);
1293 m.Bind(&loop3);
1294 m.AdvanceCurrentPosition(1);
1295 m.CheckGreedyLoop(&exit_loop3);
1296 m.GoTo(&loop3);
1297 m.Bind(&exit_loop3);
1298 m.PopCurrentPosition();
1299 m.WriteCurrentPositionToRegister(out5, 0); // [0,3,6,9,9,-1]
1300
1301 m.Succeed();
1302
1303 m.Bind(&fail);
1304 m.Fail();
1305
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001306 Handle<String> source = factory->NewStringFromStaticChars("<loop test>");
Steve Blocka7e24c12009-10-30 11:49:00 +00001307 Handle<Object> code_object = m.GetCode(source);
1308 Handle<Code> code = Handle<Code>::cast(code_object);
1309
1310 // String long enough for test (content doesn't matter).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001311 Handle<String> input = factory->NewStringFromStaticChars("foofoofoofoofoo");
1312 Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input);
Steve Blocka7e24c12009-10-30 11:49:00 +00001313 Address start_adr = seq_input->GetCharsAddress();
1314
1315 int output[6];
1316 NativeRegExpMacroAssembler::Result result =
1317 Execute(*code,
1318 *input,
1319 0,
1320 start_adr,
1321 start_adr + input->length(),
Leon Clarked91b9f72010-01-27 17:25:45 +00001322 output);
Steve Blocka7e24c12009-10-30 11:49:00 +00001323
1324 CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
1325 CHECK_EQ(0, output[0]);
1326 CHECK_EQ(3, output[1]);
1327 CHECK_EQ(6, output[2]);
1328 CHECK_EQ(9, output[3]);
1329 CHECK_EQ(9, output[4]);
1330 CHECK_EQ(-1, output[5]);
1331}
1332
1333
1334TEST(MacroAssemblerStackOverflow) {
1335 v8::V8::Initialize();
1336 ContextInitializer initializer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001337 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch8b112d22011-06-08 16:22:53 +01001338 Factory* factory = isolate->factory();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001339 Zone zone;
Steve Blocka7e24c12009-10-30 11:49:00 +00001340
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001341 ArchRegExpMacroAssembler m(isolate, &zone, NativeRegExpMacroAssembler::LATIN1,
1342 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001343
1344 Label loop;
1345 m.Bind(&loop);
1346 m.PushBacktrack(&loop);
1347 m.GoTo(&loop);
1348
1349 Handle<String> source =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001350 factory->NewStringFromStaticChars("<stack overflow test>");
Steve Blocka7e24c12009-10-30 11:49:00 +00001351 Handle<Object> code_object = m.GetCode(source);
1352 Handle<Code> code = Handle<Code>::cast(code_object);
1353
1354 // String long enough for test (content doesn't matter).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001355 Handle<String> input = factory->NewStringFromStaticChars("dummy");
1356 Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input);
Steve Blocka7e24c12009-10-30 11:49:00 +00001357 Address start_adr = seq_input->GetCharsAddress();
1358
1359 NativeRegExpMacroAssembler::Result result =
1360 Execute(*code,
1361 *input,
1362 0,
1363 start_adr,
1364 start_adr + input->length(),
Leon Clarked91b9f72010-01-27 17:25:45 +00001365 NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001366
1367 CHECK_EQ(NativeRegExpMacroAssembler::EXCEPTION, result);
Ben Murdoch8b112d22011-06-08 16:22:53 +01001368 CHECK(isolate->has_pending_exception());
1369 isolate->clear_pending_exception();
Steve Blocka7e24c12009-10-30 11:49:00 +00001370}
1371
1372
1373TEST(MacroAssemblerNativeLotsOfRegisters) {
1374 v8::V8::Initialize();
1375 ContextInitializer initializer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001376 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch8b112d22011-06-08 16:22:53 +01001377 Factory* factory = isolate->factory();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001378 Zone zone;
Steve Blocka7e24c12009-10-30 11:49:00 +00001379
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001380 ArchRegExpMacroAssembler m(isolate, &zone, NativeRegExpMacroAssembler::LATIN1,
1381 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001382
1383 // At least 2048, to ensure the allocated space for registers
1384 // span one full page.
1385 const int large_number = 8000;
1386 m.WriteCurrentPositionToRegister(large_number, 42);
1387 m.WriteCurrentPositionToRegister(0, 0);
1388 m.WriteCurrentPositionToRegister(1, 1);
1389 Label done;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001390 m.CheckNotBackReference(0, false, &done); // Performs a system-stack push.
Steve Blocka7e24c12009-10-30 11:49:00 +00001391 m.Bind(&done);
1392 m.PushRegister(large_number, RegExpMacroAssembler::kNoStackLimitCheck);
1393 m.PopRegister(1);
1394 m.Succeed();
1395
1396 Handle<String> source =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001397 factory->NewStringFromStaticChars("<huge register space test>");
Steve Blocka7e24c12009-10-30 11:49:00 +00001398 Handle<Object> code_object = m.GetCode(source);
1399 Handle<Code> code = Handle<Code>::cast(code_object);
1400
1401 // String long enough for test (content doesn't matter).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001402 Handle<String> input = factory->NewStringFromStaticChars("sample text");
1403 Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input);
Steve Blocka7e24c12009-10-30 11:49:00 +00001404 Address start_adr = seq_input->GetCharsAddress();
1405
1406 int captures[2];
1407 NativeRegExpMacroAssembler::Result result =
1408 Execute(*code,
1409 *input,
1410 0,
1411 start_adr,
1412 start_adr + input->length(),
Leon Clarked91b9f72010-01-27 17:25:45 +00001413 captures);
Steve Blocka7e24c12009-10-30 11:49:00 +00001414
1415 CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
1416 CHECK_EQ(0, captures[0]);
1417 CHECK_EQ(42, captures[1]);
1418
Ben Murdoch8b112d22011-06-08 16:22:53 +01001419 isolate->clear_pending_exception();
Steve Blocka7e24c12009-10-30 11:49:00 +00001420}
1421
Steve Block6ded16b2010-05-10 14:33:55 +01001422#else // V8_INTERPRETED_REGEXP
Steve Blocka7e24c12009-10-30 11:49:00 +00001423
1424TEST(MacroAssembler) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001425 byte codes[1024];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001426 Zone zone;
1427 RegExpMacroAssemblerIrregexp m(CcTest::i_isolate(), Vector<byte>(codes, 1024),
1428 &zone);
Steve Blocka7e24c12009-10-30 11:49:00 +00001429 // ^f(o)o.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001430 Label start, fail, backtrack;
1431
Steve Blocka7e24c12009-10-30 11:49:00 +00001432 m.SetRegister(4, 42);
1433 m.PushRegister(4, RegExpMacroAssembler::kNoStackLimitCheck);
1434 m.AdvanceRegister(4, 42);
1435 m.GoTo(&start);
1436 m.Fail();
1437 m.Bind(&start);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001438 m.PushBacktrack(&fail);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001439 m.CheckNotAtStart(0, NULL);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001440 m.LoadCurrentCharacter(0, NULL);
1441 m.CheckNotCharacter('f', NULL);
1442 m.LoadCurrentCharacter(1, NULL);
1443 m.CheckNotCharacter('o', NULL);
1444 m.LoadCurrentCharacter(2, NULL);
1445 m.CheckNotCharacter('o', NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001446 m.WriteCurrentPositionToRegister(0, 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001447 m.WriteCurrentPositionToRegister(1, 3);
1448 m.WriteCurrentPositionToRegister(2, 1);
1449 m.WriteCurrentPositionToRegister(3, 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001450 m.AdvanceCurrentPosition(3);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001451 m.PushBacktrack(&backtrack);
Steve Blocka7e24c12009-10-30 11:49:00 +00001452 m.Succeed();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001453 m.Bind(&backtrack);
1454 m.ClearRegisters(2, 3);
Steve Blocka7e24c12009-10-30 11:49:00 +00001455 m.Backtrack();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001456 m.Bind(&fail);
Steve Blocka7e24c12009-10-30 11:49:00 +00001457 m.PopRegister(0);
1458 m.Fail();
1459
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001460 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch8b112d22011-06-08 16:22:53 +01001461 Factory* factory = isolate->factory();
1462 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001463
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001464 Handle<String> source = factory->NewStringFromStaticChars("^f(o)o");
Steve Blocka7e24c12009-10-30 11:49:00 +00001465 Handle<ByteArray> array = Handle<ByteArray>::cast(m.GetCode(source));
1466 int captures[5];
1467
1468 const uc16 str1[] = {'f', 'o', 'o', 'b', 'a', 'r'};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001469 Handle<String> f1_16 = factory->NewStringFromTwoByte(
1470 Vector<const uc16>(str1, 6)).ToHandleChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001471
Ben Murdoch8b112d22011-06-08 16:22:53 +01001472 CHECK(IrregexpInterpreter::Match(isolate, array, f1_16, captures, 0));
Steve Blocka7e24c12009-10-30 11:49:00 +00001473 CHECK_EQ(0, captures[0]);
1474 CHECK_EQ(3, captures[1]);
1475 CHECK_EQ(1, captures[2]);
1476 CHECK_EQ(2, captures[3]);
1477 CHECK_EQ(84, captures[4]);
1478
1479 const uc16 str2[] = {'b', 'a', 'r', 'f', 'o', 'o'};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001480 Handle<String> f2_16 = factory->NewStringFromTwoByte(
1481 Vector<const uc16>(str2, 6)).ToHandleChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001482
Ben Murdoch8b112d22011-06-08 16:22:53 +01001483 CHECK(!IrregexpInterpreter::Match(isolate, array, f2_16, captures, 0));
Steve Blocka7e24c12009-10-30 11:49:00 +00001484 CHECK_EQ(42, captures[0]);
1485}
1486
Steve Block6ded16b2010-05-10 14:33:55 +01001487#endif // V8_INTERPRETED_REGEXP
Steve Blocka7e24c12009-10-30 11:49:00 +00001488
1489
1490TEST(AddInverseToTable) {
1491 static const int kLimit = 1000;
1492 static const int kRangeCount = 16;
1493 for (int t = 0; t < 10; t++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001494 Zone zone;
Steve Blocka7e24c12009-10-30 11:49:00 +00001495 ZoneList<CharacterRange>* ranges =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001496 new(&zone) ZoneList<CharacterRange>(kRangeCount, &zone);
Steve Blocka7e24c12009-10-30 11:49:00 +00001497 for (int i = 0; i < kRangeCount; i++) {
1498 int from = PseudoRandom(t + 87, i + 25) % kLimit;
1499 int to = from + (PseudoRandom(i + 87, t + 25) % (kLimit / 20));
1500 if (to > kLimit) to = kLimit;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001501 ranges->Add(CharacterRange::Range(from, to), &zone);
Steve Blocka7e24c12009-10-30 11:49:00 +00001502 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001503 DispatchTable table(&zone);
1504 DispatchTableConstructor cons(&table, false, &zone);
Steve Blocka7e24c12009-10-30 11:49:00 +00001505 cons.set_choice_index(0);
1506 cons.AddInverse(ranges);
1507 for (int i = 0; i < kLimit; i++) {
1508 bool is_on = false;
1509 for (int j = 0; !is_on && j < kRangeCount; j++)
1510 is_on = ranges->at(j).Contains(i);
1511 OutSet* set = table.Get(i);
1512 CHECK_EQ(is_on, set->Get(0) == false);
1513 }
1514 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001515 Zone zone;
Steve Blocka7e24c12009-10-30 11:49:00 +00001516 ZoneList<CharacterRange>* ranges =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001517 new(&zone) ZoneList<CharacterRange>(1, &zone);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001518 ranges->Add(CharacterRange::Range(0xFFF0, 0xFFFE), &zone);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001519 DispatchTable table(&zone);
1520 DispatchTableConstructor cons(&table, false, &zone);
Steve Blocka7e24c12009-10-30 11:49:00 +00001521 cons.set_choice_index(0);
1522 cons.AddInverse(ranges);
1523 CHECK(!table.Get(0xFFFE)->Get(0));
1524 CHECK(table.Get(0xFFFF)->Get(0));
1525}
1526
1527
1528static uc32 canonicalize(uc32 c) {
1529 unibrow::uchar canon[unibrow::Ecma262Canonicalize::kMaxWidth];
1530 int count = unibrow::Ecma262Canonicalize::Convert(c, '\0', canon, NULL);
1531 if (count == 0) {
1532 return c;
1533 } else {
1534 CHECK_EQ(1, count);
1535 return canon[0];
1536 }
1537}
1538
1539
1540TEST(LatinCanonicalize) {
1541 unibrow::Mapping<unibrow::Ecma262UnCanonicalize> un_canonicalize;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001542 for (unibrow::uchar lower = 'a'; lower <= 'z'; lower++) {
1543 unibrow::uchar upper = lower + ('A' - 'a');
Steve Blocka7e24c12009-10-30 11:49:00 +00001544 CHECK_EQ(canonicalize(lower), canonicalize(upper));
1545 unibrow::uchar uncanon[unibrow::Ecma262UnCanonicalize::kMaxWidth];
1546 int length = un_canonicalize.get(lower, '\0', uncanon);
1547 CHECK_EQ(2, length);
1548 CHECK_EQ(upper, uncanon[0]);
1549 CHECK_EQ(lower, uncanon[1]);
1550 }
1551 for (uc32 c = 128; c < (1 << 21); c++)
1552 CHECK_GE(canonicalize(c), 128);
1553 unibrow::Mapping<unibrow::ToUppercase> to_upper;
Ben Murdochbb769b22010-08-11 14:56:33 +01001554 // Canonicalization is only defined for the Basic Multilingual Plane.
1555 for (uc32 c = 0; c < (1 << 16); c++) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001556 unibrow::uchar upper[unibrow::ToUppercase::kMaxWidth];
1557 int length = to_upper.get(c, '\0', upper);
1558 if (length == 0) {
1559 length = 1;
1560 upper[0] = c;
1561 }
1562 uc32 u = upper[0];
1563 if (length > 1 || (c >= 128 && u < 128))
1564 u = c;
1565 CHECK_EQ(u, canonicalize(c));
1566 }
1567}
1568
1569
Ben Murdochbb769b22010-08-11 14:56:33 +01001570static uc32 CanonRangeEnd(uc32 c) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001571 unibrow::uchar canon[unibrow::CanonicalizationRange::kMaxWidth];
1572 int count = unibrow::CanonicalizationRange::Convert(c, '\0', canon, NULL);
1573 if (count == 0) {
1574 return c;
1575 } else {
1576 CHECK_EQ(1, count);
1577 return canon[0];
1578 }
1579}
1580
1581
1582TEST(RangeCanonicalization) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001583 // Check that we arrive at the same result when using the basic
1584 // range canonicalization primitives as when using immediate
1585 // canonicalization.
1586 unibrow::Mapping<unibrow::Ecma262UnCanonicalize> un_canonicalize;
Ben Murdochbb769b22010-08-11 14:56:33 +01001587 int block_start = 0;
1588 while (block_start <= 0xFFFF) {
1589 uc32 block_end = CanonRangeEnd(block_start);
1590 unsigned block_length = block_end - block_start + 1;
1591 if (block_length > 1) {
1592 unibrow::uchar first[unibrow::Ecma262UnCanonicalize::kMaxWidth];
1593 int first_length = un_canonicalize.get(block_start, '\0', first);
1594 for (unsigned i = 1; i < block_length; i++) {
1595 unibrow::uchar succ[unibrow::Ecma262UnCanonicalize::kMaxWidth];
1596 int succ_length = un_canonicalize.get(block_start + i, '\0', succ);
1597 CHECK_EQ(first_length, succ_length);
1598 for (int j = 0; j < succ_length; j++) {
1599 int calc = first[j] + i;
1600 int found = succ[j];
1601 CHECK_EQ(calc, found);
1602 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001603 }
1604 }
Ben Murdochbb769b22010-08-11 14:56:33 +01001605 block_start = block_start + block_length;
Steve Blocka7e24c12009-10-30 11:49:00 +00001606 }
1607}
1608
1609
1610TEST(UncanonicalizeEquivalence) {
1611 unibrow::Mapping<unibrow::Ecma262UnCanonicalize> un_canonicalize;
1612 unibrow::uchar chars[unibrow::Ecma262UnCanonicalize::kMaxWidth];
1613 for (int i = 0; i < (1 << 16); i++) {
1614 int length = un_canonicalize.get(i, '\0', chars);
1615 for (int j = 0; j < length; j++) {
1616 unibrow::uchar chars2[unibrow::Ecma262UnCanonicalize::kMaxWidth];
1617 int length2 = un_canonicalize.get(chars[j], '\0', chars2);
1618 CHECK_EQ(length, length2);
1619 for (int k = 0; k < length; k++)
1620 CHECK_EQ(static_cast<int>(chars[k]), static_cast<int>(chars2[k]));
1621 }
1622 }
1623}
1624
1625
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001626static void TestRangeCaseIndependence(Isolate* isolate, CharacterRange input,
Steve Blocka7e24c12009-10-30 11:49:00 +00001627 Vector<CharacterRange> expected) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001628 Zone zone;
Steve Blocka7e24c12009-10-30 11:49:00 +00001629 int count = expected.length();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001630 ZoneList<CharacterRange>* list =
1631 new(&zone) ZoneList<CharacterRange>(count, &zone);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001632 list->Add(input, &zone);
1633 CharacterRange::AddCaseEquivalents(isolate, &zone, list, false);
1634 list->Remove(0); // Remove the input before checking results.
Steve Blocka7e24c12009-10-30 11:49:00 +00001635 CHECK_EQ(count, list->length());
1636 for (int i = 0; i < list->length(); i++) {
1637 CHECK_EQ(expected[i].from(), list->at(i).from());
1638 CHECK_EQ(expected[i].to(), list->at(i).to());
1639 }
1640}
1641
1642
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001643static void TestSimpleRangeCaseIndependence(Isolate* isolate,
1644 CharacterRange input,
Steve Blocka7e24c12009-10-30 11:49:00 +00001645 CharacterRange expected) {
1646 EmbeddedVector<CharacterRange, 1> vector;
1647 vector[0] = expected;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001648 TestRangeCaseIndependence(isolate, input, vector);
Steve Blocka7e24c12009-10-30 11:49:00 +00001649}
1650
1651
1652TEST(CharacterRangeCaseIndependence) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001653 Isolate* isolate = CcTest::i_isolate();
1654 TestSimpleRangeCaseIndependence(isolate, CharacterRange::Singleton('a'),
Steve Blocka7e24c12009-10-30 11:49:00 +00001655 CharacterRange::Singleton('A'));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001656 TestSimpleRangeCaseIndependence(isolate, CharacterRange::Singleton('z'),
Steve Blocka7e24c12009-10-30 11:49:00 +00001657 CharacterRange::Singleton('Z'));
Ben Murdoch097c5b22016-05-18 11:27:45 +01001658 TestSimpleRangeCaseIndependence(isolate, CharacterRange::Range('a', 'z'),
1659 CharacterRange::Range('A', 'Z'));
1660 TestSimpleRangeCaseIndependence(isolate, CharacterRange::Range('c', 'f'),
1661 CharacterRange::Range('C', 'F'));
1662 TestSimpleRangeCaseIndependence(isolate, CharacterRange::Range('a', 'b'),
1663 CharacterRange::Range('A', 'B'));
1664 TestSimpleRangeCaseIndependence(isolate, CharacterRange::Range('y', 'z'),
1665 CharacterRange::Range('Y', 'Z'));
1666 TestSimpleRangeCaseIndependence(isolate,
1667 CharacterRange::Range('a' - 1, 'z' + 1),
1668 CharacterRange::Range('A', 'Z'));
1669 TestSimpleRangeCaseIndependence(isolate, CharacterRange::Range('A', 'Z'),
1670 CharacterRange::Range('a', 'z'));
1671 TestSimpleRangeCaseIndependence(isolate, CharacterRange::Range('C', 'F'),
1672 CharacterRange::Range('c', 'f'));
1673 TestSimpleRangeCaseIndependence(isolate,
1674 CharacterRange::Range('A' - 1, 'Z' + 1),
1675 CharacterRange::Range('a', 'z'));
Steve Blocka7e24c12009-10-30 11:49:00 +00001676 // Here we need to add [l-z] to complete the case independence of
1677 // [A-Za-z] but we expect [a-z] to be added since we always add a
1678 // whole block at a time.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001679 TestSimpleRangeCaseIndependence(isolate, CharacterRange::Range('A', 'k'),
1680 CharacterRange::Range('a', 'z'));
Steve Blocka7e24c12009-10-30 11:49:00 +00001681}
1682
1683
Ben Murdoch097c5b22016-05-18 11:27:45 +01001684static bool InClass(uc32 c, ZoneList<CharacterRange>* ranges) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001685 if (ranges == NULL)
1686 return false;
1687 for (int i = 0; i < ranges->length(); i++) {
1688 CharacterRange range = ranges->at(i);
1689 if (range.from() <= c && c <= range.to())
1690 return true;
1691 }
1692 return false;
1693}
1694
1695
Ben Murdoch097c5b22016-05-18 11:27:45 +01001696TEST(UnicodeRangeSplitter) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001697 Zone zone;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001698 ZoneList<CharacterRange>* base =
1699 new(&zone) ZoneList<CharacterRange>(1, &zone);
1700 base->Add(CharacterRange::Everything(), &zone);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001701 UnicodeRangeSplitter splitter(&zone, base);
1702 // BMP
1703 for (uc32 c = 0; c < 0xd800; c++) {
1704 CHECK(InClass(c, splitter.bmp()));
1705 CHECK(!InClass(c, splitter.lead_surrogates()));
1706 CHECK(!InClass(c, splitter.trail_surrogates()));
1707 CHECK(!InClass(c, splitter.non_bmp()));
1708 }
1709 // Lead surrogates
1710 for (uc32 c = 0xd800; c < 0xdbff; c++) {
1711 CHECK(!InClass(c, splitter.bmp()));
1712 CHECK(InClass(c, splitter.lead_surrogates()));
1713 CHECK(!InClass(c, splitter.trail_surrogates()));
1714 CHECK(!InClass(c, splitter.non_bmp()));
1715 }
1716 // Trail surrogates
1717 for (uc32 c = 0xdc00; c < 0xdfff; c++) {
1718 CHECK(!InClass(c, splitter.bmp()));
1719 CHECK(!InClass(c, splitter.lead_surrogates()));
1720 CHECK(InClass(c, splitter.trail_surrogates()));
1721 CHECK(!InClass(c, splitter.non_bmp()));
1722 }
1723 // BMP
1724 for (uc32 c = 0xe000; c < 0xffff; c++) {
1725 CHECK(InClass(c, splitter.bmp()));
1726 CHECK(!InClass(c, splitter.lead_surrogates()));
1727 CHECK(!InClass(c, splitter.trail_surrogates()));
1728 CHECK(!InClass(c, splitter.non_bmp()));
1729 }
1730 // Non-BMP
1731 for (uc32 c = 0x10000; c < 0x10ffff; c++) {
1732 CHECK(!InClass(c, splitter.bmp()));
1733 CHECK(!InClass(c, splitter.lead_surrogates()));
1734 CHECK(!InClass(c, splitter.trail_surrogates()));
1735 CHECK(InClass(c, splitter.non_bmp()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001736 }
1737}
1738
1739
Leon Clarkee46be812010-01-19 14:06:41 +00001740TEST(CanonicalizeCharacterSets) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001741 Zone zone;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001742 ZoneList<CharacterRange>* list =
1743 new(&zone) ZoneList<CharacterRange>(4, &zone);
Leon Clarkee46be812010-01-19 14:06:41 +00001744 CharacterSet set(list);
1745
Ben Murdoch097c5b22016-05-18 11:27:45 +01001746 list->Add(CharacterRange::Range(10, 20), &zone);
1747 list->Add(CharacterRange::Range(30, 40), &zone);
1748 list->Add(CharacterRange::Range(50, 60), &zone);
Leon Clarkee46be812010-01-19 14:06:41 +00001749 set.Canonicalize();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001750 CHECK_EQ(3, list->length());
1751 CHECK_EQ(10, list->at(0).from());
1752 CHECK_EQ(20, list->at(0).to());
1753 CHECK_EQ(30, list->at(1).from());
1754 CHECK_EQ(40, list->at(1).to());
1755 CHECK_EQ(50, list->at(2).from());
1756 CHECK_EQ(60, list->at(2).to());
Leon Clarkee46be812010-01-19 14:06:41 +00001757
1758 list->Rewind(0);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001759 list->Add(CharacterRange::Range(10, 20), &zone);
1760 list->Add(CharacterRange::Range(50, 60), &zone);
1761 list->Add(CharacterRange::Range(30, 40), &zone);
Leon Clarkee46be812010-01-19 14:06:41 +00001762 set.Canonicalize();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001763 CHECK_EQ(3, list->length());
1764 CHECK_EQ(10, list->at(0).from());
1765 CHECK_EQ(20, list->at(0).to());
1766 CHECK_EQ(30, list->at(1).from());
1767 CHECK_EQ(40, list->at(1).to());
1768 CHECK_EQ(50, list->at(2).from());
1769 CHECK_EQ(60, list->at(2).to());
Leon Clarkee46be812010-01-19 14:06:41 +00001770
1771 list->Rewind(0);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001772 list->Add(CharacterRange::Range(30, 40), &zone);
1773 list->Add(CharacterRange::Range(10, 20), &zone);
1774 list->Add(CharacterRange::Range(25, 25), &zone);
1775 list->Add(CharacterRange::Range(100, 100), &zone);
1776 list->Add(CharacterRange::Range(1, 1), &zone);
Leon Clarkee46be812010-01-19 14:06:41 +00001777 set.Canonicalize();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001778 CHECK_EQ(5, list->length());
1779 CHECK_EQ(1, list->at(0).from());
1780 CHECK_EQ(1, list->at(0).to());
1781 CHECK_EQ(10, list->at(1).from());
1782 CHECK_EQ(20, list->at(1).to());
1783 CHECK_EQ(25, list->at(2).from());
1784 CHECK_EQ(25, list->at(2).to());
1785 CHECK_EQ(30, list->at(3).from());
1786 CHECK_EQ(40, list->at(3).to());
1787 CHECK_EQ(100, list->at(4).from());
1788 CHECK_EQ(100, list->at(4).to());
Leon Clarkee46be812010-01-19 14:06:41 +00001789
1790 list->Rewind(0);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001791 list->Add(CharacterRange::Range(10, 19), &zone);
1792 list->Add(CharacterRange::Range(21, 30), &zone);
1793 list->Add(CharacterRange::Range(20, 20), &zone);
Leon Clarkee46be812010-01-19 14:06:41 +00001794 set.Canonicalize();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001795 CHECK_EQ(1, list->length());
1796 CHECK_EQ(10, list->at(0).from());
1797 CHECK_EQ(30, list->at(0).to());
Leon Clarkee46be812010-01-19 14:06:41 +00001798}
1799
Leon Clarked91b9f72010-01-27 17:25:45 +00001800
1801TEST(CharacterRangeMerge) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001802 Zone zone;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001803 ZoneList<CharacterRange> l1(4, &zone);
1804 ZoneList<CharacterRange> l2(4, &zone);
Leon Clarked91b9f72010-01-27 17:25:45 +00001805 // Create all combinations of intersections of ranges, both singletons and
1806 // longer.
1807
1808 int offset = 0;
1809
1810 // The five kinds of singleton intersections:
1811 // X
1812 // Y - outside before
1813 // Y - outside touching start
1814 // Y - overlap
1815 // Y - outside touching end
1816 // Y - outside after
1817
1818 for (int i = 0; i < 5; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001819 l1.Add(CharacterRange::Singleton(offset + 2), &zone);
1820 l2.Add(CharacterRange::Singleton(offset + i), &zone);
Leon Clarked91b9f72010-01-27 17:25:45 +00001821 offset += 6;
1822 }
1823
1824 // The seven kinds of singleton/non-singleton intersections:
1825 // XXX
1826 // Y - outside before
1827 // Y - outside touching start
1828 // Y - inside touching start
1829 // Y - entirely inside
1830 // Y - inside touching end
1831 // Y - outside touching end
1832 // Y - disjoint after
1833
1834 for (int i = 0; i < 7; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001835 l1.Add(CharacterRange::Range(offset + 2, offset + 4), &zone);
1836 l2.Add(CharacterRange::Singleton(offset + i), &zone);
Leon Clarked91b9f72010-01-27 17:25:45 +00001837 offset += 8;
1838 }
1839
1840 // The eleven kinds of non-singleton intersections:
1841 //
1842 // XXXXXXXX
1843 // YYYY - outside before.
1844 // YYYY - outside touching start.
1845 // YYYY - overlapping start
1846 // YYYY - inside touching start
1847 // YYYY - entirely inside
1848 // YYYY - inside touching end
1849 // YYYY - overlapping end
1850 // YYYY - outside touching end
1851 // YYYY - outside after
1852 // YYYYYYYY - identical
1853 // YYYYYYYYYYYY - containing entirely.
1854
1855 for (int i = 0; i < 9; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001856 l1.Add(CharacterRange::Range(offset + 6, offset + 15), &zone); // Length 8.
1857 l2.Add(CharacterRange::Range(offset + 2 * i, offset + 2 * i + 3), &zone);
Leon Clarked91b9f72010-01-27 17:25:45 +00001858 offset += 22;
1859 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001860 l1.Add(CharacterRange::Range(offset + 6, offset + 15), &zone);
1861 l2.Add(CharacterRange::Range(offset + 6, offset + 15), &zone);
Leon Clarked91b9f72010-01-27 17:25:45 +00001862 offset += 22;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001863 l1.Add(CharacterRange::Range(offset + 6, offset + 15), &zone);
1864 l2.Add(CharacterRange::Range(offset + 4, offset + 17), &zone);
Leon Clarked91b9f72010-01-27 17:25:45 +00001865 offset += 22;
1866
1867 // Different kinds of multi-range overlap:
1868 // XXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXX
1869 // YYYY Y YYYY Y YYYY Y YYYY Y YYYY Y YYYY Y
1870
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001871 l1.Add(CharacterRange::Range(offset, offset + 21), &zone);
1872 l1.Add(CharacterRange::Range(offset + 31, offset + 52), &zone);
Leon Clarked91b9f72010-01-27 17:25:45 +00001873 for (int i = 0; i < 6; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001874 l2.Add(CharacterRange::Range(offset + 2, offset + 5), &zone);
1875 l2.Add(CharacterRange::Singleton(offset + 8), &zone);
Leon Clarked91b9f72010-01-27 17:25:45 +00001876 offset += 9;
1877 }
1878
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001879 CHECK(CharacterRange::IsCanonical(&l1));
1880 CHECK(CharacterRange::IsCanonical(&l2));
Leon Clarked91b9f72010-01-27 17:25:45 +00001881
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001882 ZoneList<CharacterRange> first_only(4, &zone);
1883 ZoneList<CharacterRange> second_only(4, &zone);
1884 ZoneList<CharacterRange> both(4, &zone);
Leon Clarked91b9f72010-01-27 17:25:45 +00001885}
Leon Clarkee46be812010-01-19 14:06:41 +00001886
1887
Steve Blocka7e24c12009-10-30 11:49:00 +00001888TEST(Graph) {
Leon Clarkee46be812010-01-19 14:06:41 +00001889 Execute("\\b\\w+\\b", false, true, true);
Steve Blocka7e24c12009-10-30 11:49:00 +00001890}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001891
1892
1893namespace {
1894
1895int* global_use_counts = NULL;
1896
1897void MockUseCounterCallback(v8::Isolate* isolate,
1898 v8::Isolate::UseCounterFeature feature) {
1899 ++global_use_counts[feature];
1900}
1901}
1902
1903
1904// Test that ES2015 RegExp compatibility fixes are in place, that they
1905// are not overly broad, and the appropriate UseCounters are incremented
1906TEST(UseCountRegExp) {
1907 i::FLAG_harmony_regexps = true;
1908 v8::Isolate* isolate = CcTest::isolate();
1909 v8::HandleScope scope(isolate);
1910 LocalContext env;
1911 int use_counts[v8::Isolate::kUseCounterFeatureCount] = {};
1912 global_use_counts = use_counts;
1913 CcTest::isolate()->SetUseCounterCallback(MockUseCounterCallback);
1914
1915 // Compat fix: RegExp.prototype.sticky == undefined; UseCounter tracks it
1916 v8::Local<v8::Value> resultSticky = CompileRun("RegExp.prototype.sticky");
1917 CHECK_EQ(1, use_counts[v8::Isolate::kRegExpPrototypeStickyGetter]);
1918 CHECK_EQ(0, use_counts[v8::Isolate::kRegExpPrototypeToString]);
1919 CHECK(resultSticky->IsUndefined());
1920
1921 // re.sticky has approriate value and doesn't touch UseCounter
1922 v8::Local<v8::Value> resultReSticky = CompileRun("/a/.sticky");
1923 CHECK_EQ(1, use_counts[v8::Isolate::kRegExpPrototypeStickyGetter]);
1924 CHECK_EQ(0, use_counts[v8::Isolate::kRegExpPrototypeToString]);
1925 CHECK(resultReSticky->IsFalse());
1926
1927 // When the getter is caleld on another object, throw an exception
1928 // and don't increment the UseCounter
1929 v8::Local<v8::Value> resultStickyError = CompileRun(
1930 "var exception;"
1931 "try { "
1932 " Object.getOwnPropertyDescriptor(RegExp.prototype, 'sticky')"
1933 " .get.call(null);"
1934 "} catch (e) {"
1935 " exception = e;"
1936 "}"
1937 "exception");
1938 CHECK_EQ(1, use_counts[v8::Isolate::kRegExpPrototypeStickyGetter]);
1939 CHECK_EQ(0, use_counts[v8::Isolate::kRegExpPrototypeToString]);
1940 CHECK(resultStickyError->IsObject());
1941
1942 // RegExp.prototype.toString() returns '/(?:)/' as a compatibility fix;
1943 // a UseCounter is incremented to track it.
1944 v8::Local<v8::Value> resultToString =
1945 CompileRun("RegExp.prototype.toString().length");
1946 CHECK_EQ(1, use_counts[v8::Isolate::kRegExpPrototypeStickyGetter]);
1947 CHECK_EQ(1, use_counts[v8::Isolate::kRegExpPrototypeToString]);
1948 CHECK(resultToString->IsInt32());
1949 CHECK_EQ(6,
1950 resultToString->Int32Value(isolate->GetCurrentContext()).FromJust());
1951
1952 // .toString() works on normal RegExps
1953 v8::Local<v8::Value> resultReToString = CompileRun("/a/.toString().length");
1954 CHECK_EQ(1, use_counts[v8::Isolate::kRegExpPrototypeStickyGetter]);
1955 CHECK_EQ(1, use_counts[v8::Isolate::kRegExpPrototypeToString]);
1956 CHECK(resultReToString->IsInt32());
1957 CHECK_EQ(
1958 3, resultReToString->Int32Value(isolate->GetCurrentContext()).FromJust());
1959
1960 // .toString() throws on non-RegExps that aren't RegExp.prototype
1961 v8::Local<v8::Value> resultToStringError = CompileRun(
1962 "var exception;"
1963 "try { RegExp.prototype.toString.call(null) }"
1964 "catch (e) { exception = e; }"
1965 "exception");
1966 CHECK_EQ(1, use_counts[v8::Isolate::kRegExpPrototypeStickyGetter]);
1967 CHECK_EQ(1, use_counts[v8::Isolate::kRegExpPrototypeToString]);
1968 CHECK(resultToStringError->IsObject());
1969}
Ben Murdoch097c5b22016-05-18 11:27:45 +01001970
1971class UncachedExternalString
1972 : public v8::String::ExternalOneByteStringResource {
1973 public:
1974 const char* data() const override { return "abcdefghijklmnopqrstuvwxyz"; }
1975 size_t length() const override { return 26; }
1976 bool IsCompressible() const override { return true; }
1977};
1978
1979TEST(UncachedExternalString) {
1980 v8::Isolate* isolate = CcTest::isolate();
1981 v8::HandleScope scope(isolate);
1982 LocalContext env;
1983 v8::Local<v8::String> external =
1984 v8::String::NewExternalOneByte(isolate, new UncachedExternalString())
1985 .ToLocalChecked();
1986 CHECK(v8::Utils::OpenHandle(*external)->map() ==
1987 CcTest::i_isolate()->heap()->short_external_one_byte_string_map());
1988 v8::Local<v8::Object> global = env->Global();
1989 global->Set(env.local(), v8_str("external"), external).FromJust();
1990 CompileRun("var re = /y(.)/; re.test('ab');");
1991 ExpectString("external.substring(1).match(re)[1]", "z");
1992}