blob: 0a153b78e05b145d822ba65656bd42807a369232 [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
Ben Murdochda12d292016-06-02 14:46:10 +010057#if V8_TARGET_ARCH_S390
58#include "src/regexp/s390/regexp-macro-assembler-s390.h"
59#include "src/s390/assembler-s390.h"
60#include "src/s390/macro-assembler-s390.h"
61#endif
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000062#if V8_TARGET_ARCH_PPC
63#include "src/ppc/assembler-ppc.h"
64#include "src/ppc/macro-assembler-ppc.h"
65#include "src/regexp/ppc/regexp-macro-assembler-ppc.h"
Steve Block44f0eee2011-05-26 01:26:41 +010066#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +000067#if V8_TARGET_ARCH_MIPS
68#include "src/mips/assembler-mips.h"
69#include "src/mips/macro-assembler-mips.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000070#include "src/regexp/mips/regexp-macro-assembler-mips.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000071#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +000072#if V8_TARGET_ARCH_MIPS64
73#include "src/mips64/assembler-mips64.h"
74#include "src/mips64/macro-assembler-mips64.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000075#include "src/regexp/mips64/regexp-macro-assembler-mips64.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000076#endif
77#if V8_TARGET_ARCH_X64
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000078#include "src/regexp/x64/regexp-macro-assembler-x64.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000079#include "src/x64/assembler-x64.h"
80#include "src/x64/macro-assembler-x64.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000081#endif
82#if V8_TARGET_ARCH_IA32
83#include "src/ia32/assembler-ia32.h"
84#include "src/ia32/macro-assembler-ia32.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000085#include "src/regexp/ia32/regexp-macro-assembler-ia32.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000086#endif
87#if V8_TARGET_ARCH_X87
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000088#include "src/regexp/x87/regexp-macro-assembler-x87.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000089#include "src/x87/assembler-x87.h"
90#include "src/x87/macro-assembler-x87.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000091#endif
Steve Block6ded16b2010-05-10 14:33:55 +010092#endif // V8_INTERPRETED_REGEXP
Ben Murdochb8a8cc12014-11-26 15:28:44 +000093#include "test/cctest/cctest.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000094
95using namespace v8::internal;
96
97
Leon Clarkee46be812010-01-19 14:06:41 +000098static bool CheckParse(const char* input) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000099 v8::HandleScope scope(CcTest::isolate());
Ben Murdochda12d292016-06-02 14:46:10 +0100100 Zone zone(CcTest::i_isolate()->allocator());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000101 FlatStringReader reader(CcTest::i_isolate(), CStrVector(input));
Leon Clarkee46be812010-01-19 14:06:41 +0000102 RegExpCompileData result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000103 return v8::internal::RegExpParser::ParseRegExp(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100104 CcTest::i_isolate(), &zone, &reader, JSRegExp::kNone, &result);
Leon Clarkee46be812010-01-19 14:06:41 +0000105}
106
107
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000108static void CheckParseEq(const char* input, const char* expected,
109 bool unicode = false) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000110 v8::HandleScope scope(CcTest::isolate());
Ben Murdochda12d292016-06-02 14:46:10 +0100111 Zone zone(CcTest::i_isolate()->allocator());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000112 FlatStringReader reader(CcTest::i_isolate(), CStrVector(input));
Steve Blocka7e24c12009-10-30 11:49:00 +0000113 RegExpCompileData result;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100114 JSRegExp::Flags flags = JSRegExp::kNone;
115 if (unicode) flags |= JSRegExp::kUnicode;
116 CHECK(v8::internal::RegExpParser::ParseRegExp(CcTest::i_isolate(), &zone,
117 &reader, flags, &result));
Steve Blocka7e24c12009-10-30 11:49:00 +0000118 CHECK(result.tree != NULL);
119 CHECK(result.error.is_null());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400120 std::ostringstream os;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000121 result.tree->Print(os, &zone);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000122 if (strcmp(expected, os.str().c_str()) != 0) {
123 printf("%s | %s\n", expected, os.str().c_str());
124 }
125 CHECK_EQ(0, strcmp(expected, os.str().c_str()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000126}
127
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000128
Steve Blocka7e24c12009-10-30 11:49:00 +0000129static bool CheckSimple(const char* input) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000130 v8::HandleScope scope(CcTest::isolate());
Ben Murdochda12d292016-06-02 14:46:10 +0100131 Zone zone(CcTest::i_isolate()->allocator());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000132 FlatStringReader reader(CcTest::i_isolate(), CStrVector(input));
Steve Blocka7e24c12009-10-30 11:49:00 +0000133 RegExpCompileData result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000134 CHECK(v8::internal::RegExpParser::ParseRegExp(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100135 CcTest::i_isolate(), &zone, &reader, JSRegExp::kNone, &result));
Steve Blocka7e24c12009-10-30 11:49:00 +0000136 CHECK(result.tree != NULL);
137 CHECK(result.error.is_null());
138 return result.simple;
139}
140
141struct MinMaxPair {
142 int min_match;
143 int max_match;
144};
145
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000146
Steve Blocka7e24c12009-10-30 11:49:00 +0000147static MinMaxPair CheckMinMaxMatch(const char* input) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000148 v8::HandleScope scope(CcTest::isolate());
Ben Murdochda12d292016-06-02 14:46:10 +0100149 Zone zone(CcTest::i_isolate()->allocator());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000150 FlatStringReader reader(CcTest::i_isolate(), CStrVector(input));
Steve Blocka7e24c12009-10-30 11:49:00 +0000151 RegExpCompileData result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000152 CHECK(v8::internal::RegExpParser::ParseRegExp(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100153 CcTest::i_isolate(), &zone, &reader, JSRegExp::kNone, &result));
Steve Blocka7e24c12009-10-30 11:49:00 +0000154 CHECK(result.tree != NULL);
155 CHECK(result.error.is_null());
156 int min_match = result.tree->min_match();
157 int max_match = result.tree->max_match();
158 MinMaxPair pair = { min_match, max_match };
159 return pair;
160}
161
162
Leon Clarkee46be812010-01-19 14:06:41 +0000163#define CHECK_PARSE_ERROR(input) CHECK(!CheckParse(input))
Steve Blocka7e24c12009-10-30 11:49:00 +0000164#define CHECK_SIMPLE(input, simple) CHECK_EQ(simple, CheckSimple(input));
165#define CHECK_MIN_MAX(input, min, max) \
166 { MinMaxPair min_max = CheckMinMaxMatch(input); \
167 CHECK_EQ(min, min_max.min_match); \
168 CHECK_EQ(max, min_max.max_match); \
169 }
170
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000171
172void TestRegExpParser(bool lookbehind) {
173 FLAG_harmony_regexp_lookbehind = lookbehind;
174 FLAG_harmony_unicode_regexps = true;
175
Leon Clarkee46be812010-01-19 14:06:41 +0000176 CHECK_PARSE_ERROR("?");
177
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000178 CheckParseEq("abc", "'abc'");
179 CheckParseEq("", "%");
180 CheckParseEq("abc|def", "(| 'abc' 'def')");
181 CheckParseEq("abc|def|ghi", "(| 'abc' 'def' 'ghi')");
182 CheckParseEq("^xxx$", "(: @^i 'xxx' @$i)");
183 CheckParseEq("ab\\b\\d\\bcd", "(: 'ab' @b [0-9] @b 'cd')");
184 CheckParseEq("\\w|\\d", "(| [0-9 A-Z _ a-z] [0-9])");
185 CheckParseEq("a*", "(# 0 - g 'a')");
186 CheckParseEq("a*?", "(# 0 - n 'a')");
187 CheckParseEq("abc+", "(: 'ab' (# 1 - g 'c'))");
188 CheckParseEq("abc+?", "(: 'ab' (# 1 - n 'c'))");
189 CheckParseEq("xyz?", "(: 'xy' (# 0 1 g 'z'))");
190 CheckParseEq("xyz??", "(: 'xy' (# 0 1 n 'z'))");
191 CheckParseEq("xyz{0,1}", "(: 'xy' (# 0 1 g 'z'))");
192 CheckParseEq("xyz{0,1}?", "(: 'xy' (# 0 1 n 'z'))");
193 CheckParseEq("xyz{93}", "(: 'xy' (# 93 93 g 'z'))");
194 CheckParseEq("xyz{93}?", "(: 'xy' (# 93 93 n 'z'))");
195 CheckParseEq("xyz{1,32}", "(: 'xy' (# 1 32 g 'z'))");
196 CheckParseEq("xyz{1,32}?", "(: 'xy' (# 1 32 n 'z'))");
197 CheckParseEq("xyz{1,}", "(: 'xy' (# 1 - g 'z'))");
198 CheckParseEq("xyz{1,}?", "(: 'xy' (# 1 - n 'z'))");
199 CheckParseEq("a\\fb\\nc\\rd\\te\\vf", "'a\\x0cb\\x0ac\\x0dd\\x09e\\x0bf'");
200 CheckParseEq("a\\nb\\bc", "(: 'a\\x0ab' @b 'c')");
201 CheckParseEq("(?:foo)", "'foo'");
202 CheckParseEq("(?: foo )", "' foo '");
203 CheckParseEq("(foo|bar|baz)", "(^ (| 'foo' 'bar' 'baz'))");
204 CheckParseEq("foo|(bar|baz)|quux", "(| 'foo' (^ (| 'bar' 'baz')) 'quux')");
205 CheckParseEq("foo(?=bar)baz", "(: 'foo' (-> + 'bar') 'baz')");
206 CheckParseEq("foo(?!bar)baz", "(: 'foo' (-> - 'bar') 'baz')");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000207 if (lookbehind) {
208 CheckParseEq("foo(?<=bar)baz", "(: 'foo' (<- + 'bar') 'baz')");
209 CheckParseEq("foo(?<!bar)baz", "(: 'foo' (<- - 'bar') 'baz')");
210 } else {
211 CHECK_PARSE_ERROR("foo(?<=bar)baz");
212 CHECK_PARSE_ERROR("foo(?<!bar)baz");
213 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000214 CheckParseEq("()", "(^ %)");
215 CheckParseEq("(?=)", "(-> + %)");
Ben Murdoch097c5b22016-05-18 11:27:45 +0100216 CheckParseEq("[]", "^[\\x00-\\u{10ffff}]"); // Doesn't compile on windows
217 CheckParseEq("[^]", "[\\x00-\\u{10ffff}]"); // \uffff isn't in codepage 1252
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000218 CheckParseEq("[x]", "[x]");
219 CheckParseEq("[xyz]", "[x y z]");
220 CheckParseEq("[a-zA-Z0-9]", "[a-z A-Z 0-9]");
221 CheckParseEq("[-123]", "[- 1 2 3]");
222 CheckParseEq("[^123]", "^[1 2 3]");
223 CheckParseEq("]", "']'");
224 CheckParseEq("}", "'}'");
225 CheckParseEq("[a-b-c]", "[a-b - c]");
226 CheckParseEq("[\\d]", "[0-9]");
227 CheckParseEq("[x\\dz]", "[x 0-9 z]");
228 CheckParseEq("[\\d-z]", "[0-9 - z]");
229 CheckParseEq("[\\d-\\d]", "[0-9 - 0-9]");
230 CheckParseEq("[z-\\d]", "[z - 0-9]");
Ben Murdoch086aeea2011-05-13 15:57:08 +0100231 // Control character outside character class.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000232 CheckParseEq("\\cj\\cJ\\ci\\cI\\ck\\cK", "'\\x0a\\x0a\\x09\\x09\\x0b\\x0b'");
233 CheckParseEq("\\c!", "'\\c!'");
234 CheckParseEq("\\c_", "'\\c_'");
235 CheckParseEq("\\c~", "'\\c~'");
236 CheckParseEq("\\c1", "'\\c1'");
Ben Murdoch086aeea2011-05-13 15:57:08 +0100237 // Control character inside character class.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000238 CheckParseEq("[\\c!]", "[\\ c !]");
239 CheckParseEq("[\\c_]", "[\\x1f]");
240 CheckParseEq("[\\c~]", "[\\ c ~]");
241 CheckParseEq("[\\ca]", "[\\x01]");
242 CheckParseEq("[\\cz]", "[\\x1a]");
243 CheckParseEq("[\\cA]", "[\\x01]");
244 CheckParseEq("[\\cZ]", "[\\x1a]");
245 CheckParseEq("[\\c1]", "[\\x11]");
Ben Murdoch086aeea2011-05-13 15:57:08 +0100246
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000247 CheckParseEq("[a\\]c]", "[a ] c]");
248 CheckParseEq("\\[\\]\\{\\}\\(\\)\\%\\^\\#\\ ", "'[]{}()%^# '");
249 CheckParseEq("[\\[\\]\\{\\}\\(\\)\\%\\^\\#\\ ]", "[[ ] { } ( ) % ^ # ]");
250 CheckParseEq("\\0", "'\\x00'");
251 CheckParseEq("\\8", "'8'");
252 CheckParseEq("\\9", "'9'");
253 CheckParseEq("\\11", "'\\x09'");
254 CheckParseEq("\\11a", "'\\x09a'");
255 CheckParseEq("\\011", "'\\x09'");
256 CheckParseEq("\\00011", "'\\x0011'");
257 CheckParseEq("\\118", "'\\x098'");
258 CheckParseEq("\\111", "'I'");
259 CheckParseEq("\\1111", "'I1'");
260 CheckParseEq("(x)(x)(x)\\1", "(: (^ 'x') (^ 'x') (^ 'x') (<- 1))");
261 CheckParseEq("(x)(x)(x)\\2", "(: (^ 'x') (^ 'x') (^ 'x') (<- 2))");
262 CheckParseEq("(x)(x)(x)\\3", "(: (^ 'x') (^ 'x') (^ 'x') (<- 3))");
263 CheckParseEq("(x)(x)(x)\\4", "(: (^ 'x') (^ 'x') (^ 'x') '\\x04')");
264 CheckParseEq("(x)(x)(x)\\1*",
265 "(: (^ 'x') (^ 'x') (^ 'x')"
266 " (# 0 - g (<- 1)))");
267 CheckParseEq("(x)(x)(x)\\2*",
268 "(: (^ 'x') (^ 'x') (^ 'x')"
269 " (# 0 - g (<- 2)))");
270 CheckParseEq("(x)(x)(x)\\3*",
271 "(: (^ 'x') (^ 'x') (^ 'x')"
272 " (# 0 - g (<- 3)))");
273 CheckParseEq("(x)(x)(x)\\4*",
274 "(: (^ 'x') (^ 'x') (^ 'x')"
275 " (# 0 - g '\\x04'))");
276 CheckParseEq("(x)(x)(x)(x)(x)(x)(x)(x)(x)(x)\\10",
277 "(: (^ 'x') (^ 'x') (^ 'x') (^ 'x') (^ 'x') (^ 'x')"
278 " (^ 'x') (^ 'x') (^ 'x') (^ 'x') (<- 10))");
279 CheckParseEq("(x)(x)(x)(x)(x)(x)(x)(x)(x)(x)\\11",
280 "(: (^ 'x') (^ 'x') (^ 'x') (^ 'x') (^ 'x') (^ 'x')"
281 " (^ 'x') (^ 'x') (^ 'x') (^ 'x') '\\x09')");
282 CheckParseEq("(a)\\1", "(: (^ 'a') (<- 1))");
283 CheckParseEq("(a\\1)", "(^ 'a')");
284 CheckParseEq("(\\1a)", "(^ 'a')");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000285 CheckParseEq("(\\2)(\\1)", "(: (^ (<- 2)) (^ (<- 1)))");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000286 CheckParseEq("(?=a)?a", "'a'");
287 CheckParseEq("(?=a){0,10}a", "'a'");
288 CheckParseEq("(?=a){1,10}a", "(: (-> + 'a') 'a')");
289 CheckParseEq("(?=a){9,10}a", "(: (-> + 'a') 'a')");
290 CheckParseEq("(?!a)?a", "'a'");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000291 CheckParseEq("\\1(a)", "(: (<- 1) (^ 'a'))");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000292 CheckParseEq("(?!(a))\\1", "(: (-> - (^ 'a')) (<- 1))");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000293 CheckParseEq("(?!\\1(a\\1)\\1)\\1",
294 "(: (-> - (: (<- 1) (^ 'a') (<- 1))) (<- 1))");
295 CheckParseEq("\\1\\2(a(?:\\1(b\\1\\2))\\2)\\1",
296 "(: (<- 1) (<- 2) (^ (: 'a' (^ 'b') (<- 2))) (<- 1))");
297 if (lookbehind) {
298 CheckParseEq("\\1\\2(a(?<=\\1(b\\1\\2))\\2)\\1",
299 "(: (<- 1) (<- 2) (^ (: 'a' (<- + (^ 'b')) (<- 2))) (<- 1))");
300 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000301 CheckParseEq("[\\0]", "[\\x00]");
302 CheckParseEq("[\\11]", "[\\x09]");
303 CheckParseEq("[\\11a]", "[\\x09 a]");
304 CheckParseEq("[\\011]", "[\\x09]");
305 CheckParseEq("[\\00011]", "[\\x00 1 1]");
306 CheckParseEq("[\\118]", "[\\x09 8]");
307 CheckParseEq("[\\111]", "[I]");
308 CheckParseEq("[\\1111]", "[I 1]");
309 CheckParseEq("\\x34", "'\x34'");
310 CheckParseEq("\\x60", "'\x60'");
311 CheckParseEq("\\x3z", "'x3z'");
312 CheckParseEq("\\c", "'\\c'");
313 CheckParseEq("\\u0034", "'\x34'");
314 CheckParseEq("\\u003z", "'u003z'");
315 CheckParseEq("foo[z]*", "(: 'foo' (# 0 - g [z]))");
Steve Blocka7e24c12009-10-30 11:49:00 +0000316
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000317 // Unicode regexps
318 CheckParseEq("\\u{12345}", "'\\ud808\\udf45'", true);
319 CheckParseEq("\\u{12345}\\u{23456}", "(! '\\ud808\\udf45' '\\ud84d\\udc56')",
320 true);
321 CheckParseEq("\\u{12345}|\\u{23456}", "(| '\\ud808\\udf45' '\\ud84d\\udc56')",
322 true);
323 CheckParseEq("\\u{12345}{3}", "(# 3 3 g '\\ud808\\udf45')", true);
324 CheckParseEq("\\u{12345}*", "(# 0 - g '\\ud808\\udf45')", true);
325
Ben Murdoch097c5b22016-05-18 11:27:45 +0100326 CheckParseEq("\\ud808\\udf45*", "(# 0 - g '\\ud808\\udf45')", true);
327 CheckParseEq("[\\ud808\\udf45-\\ud809\\udccc]", "[\\u{012345}-\\u{0124cc}]",
328 true);
329
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000330 CHECK_SIMPLE("", false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000331 CHECK_SIMPLE("a", true);
332 CHECK_SIMPLE("a|b", false);
333 CHECK_SIMPLE("a\\n", false);
334 CHECK_SIMPLE("^a", false);
335 CHECK_SIMPLE("a$", false);
336 CHECK_SIMPLE("a\\b!", false);
337 CHECK_SIMPLE("a\\Bb", false);
338 CHECK_SIMPLE("a*", false);
339 CHECK_SIMPLE("a*?", false);
340 CHECK_SIMPLE("a?", false);
341 CHECK_SIMPLE("a??", false);
342 CHECK_SIMPLE("a{0,1}?", false);
343 CHECK_SIMPLE("a{1,1}?", false);
344 CHECK_SIMPLE("a{1,2}?", false);
345 CHECK_SIMPLE("a+?", false);
346 CHECK_SIMPLE("(a)", false);
347 CHECK_SIMPLE("(a)\\1", false);
348 CHECK_SIMPLE("(\\1a)", false);
349 CHECK_SIMPLE("\\1(a)", false);
350 CHECK_SIMPLE("a\\s", false);
351 CHECK_SIMPLE("a\\S", false);
352 CHECK_SIMPLE("a\\d", false);
353 CHECK_SIMPLE("a\\D", false);
354 CHECK_SIMPLE("a\\w", false);
355 CHECK_SIMPLE("a\\W", false);
356 CHECK_SIMPLE("a.", false);
357 CHECK_SIMPLE("a\\q", false);
358 CHECK_SIMPLE("a[a]", false);
359 CHECK_SIMPLE("a[^a]", false);
360 CHECK_SIMPLE("a[a-z]", false);
361 CHECK_SIMPLE("a[\\q]", false);
362 CHECK_SIMPLE("a(?:b)", false);
363 CHECK_SIMPLE("a(?=b)", false);
364 CHECK_SIMPLE("a(?!b)", false);
365 CHECK_SIMPLE("\\x60", false);
366 CHECK_SIMPLE("\\u0060", false);
367 CHECK_SIMPLE("\\cA", false);
368 CHECK_SIMPLE("\\q", false);
369 CHECK_SIMPLE("\\1112", false);
370 CHECK_SIMPLE("\\0", false);
371 CHECK_SIMPLE("(a)\\1", false);
372 CHECK_SIMPLE("(?=a)?a", false);
373 CHECK_SIMPLE("(?!a)?a\\1", false);
374 CHECK_SIMPLE("(?:(?=a))a\\1", false);
375
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000376 CheckParseEq("a{}", "'a{}'");
377 CheckParseEq("a{,}", "'a{,}'");
378 CheckParseEq("a{", "'a{'");
379 CheckParseEq("a{z}", "'a{z}'");
380 CheckParseEq("a{1z}", "'a{1z}'");
381 CheckParseEq("a{12z}", "'a{12z}'");
382 CheckParseEq("a{12,", "'a{12,'");
383 CheckParseEq("a{12,3b", "'a{12,3b'");
384 CheckParseEq("{}", "'{}'");
385 CheckParseEq("{,}", "'{,}'");
386 CheckParseEq("{", "'{'");
387 CheckParseEq("{z}", "'{z}'");
388 CheckParseEq("{1z}", "'{1z}'");
389 CheckParseEq("{12z}", "'{12z}'");
390 CheckParseEq("{12,", "'{12,'");
391 CheckParseEq("{12,3b", "'{12,3b'");
Steve Blocka7e24c12009-10-30 11:49:00 +0000392
393 CHECK_MIN_MAX("a", 1, 1);
394 CHECK_MIN_MAX("abc", 3, 3);
395 CHECK_MIN_MAX("a[bc]d", 3, 3);
396 CHECK_MIN_MAX("a|bc", 1, 2);
397 CHECK_MIN_MAX("ab|c", 1, 2);
398 CHECK_MIN_MAX("a||bc", 0, 2);
399 CHECK_MIN_MAX("|", 0, 0);
400 CHECK_MIN_MAX("(?:ab)", 2, 2);
401 CHECK_MIN_MAX("(?:ab|cde)", 2, 3);
402 CHECK_MIN_MAX("(?:ab)|cde", 2, 3);
403 CHECK_MIN_MAX("(ab)", 2, 2);
404 CHECK_MIN_MAX("(ab|cde)", 2, 3);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000405 CHECK_MIN_MAX("(ab)\\1", 2, RegExpTree::kInfinity);
406 CHECK_MIN_MAX("(ab|cde)\\1", 2, RegExpTree::kInfinity);
Steve Blocka7e24c12009-10-30 11:49:00 +0000407 CHECK_MIN_MAX("(?:ab)?", 0, 2);
408 CHECK_MIN_MAX("(?:ab)*", 0, RegExpTree::kInfinity);
409 CHECK_MIN_MAX("(?:ab)+", 2, RegExpTree::kInfinity);
410 CHECK_MIN_MAX("a?", 0, 1);
411 CHECK_MIN_MAX("a*", 0, RegExpTree::kInfinity);
412 CHECK_MIN_MAX("a+", 1, RegExpTree::kInfinity);
413 CHECK_MIN_MAX("a??", 0, 1);
414 CHECK_MIN_MAX("a*?", 0, RegExpTree::kInfinity);
415 CHECK_MIN_MAX("a+?", 1, RegExpTree::kInfinity);
416 CHECK_MIN_MAX("(?:a?)?", 0, 1);
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, RegExpTree::kInfinity);
421 CHECK_MIN_MAX("(?:a+)+", 1, RegExpTree::kInfinity);
422 CHECK_MIN_MAX("(?:a?)*", 0, RegExpTree::kInfinity);
423 CHECK_MIN_MAX("(?:a*)*", 0, RegExpTree::kInfinity);
424 CHECK_MIN_MAX("(?:a+)*", 0, RegExpTree::kInfinity);
425 CHECK_MIN_MAX("a{0}", 0, 0);
426 CHECK_MIN_MAX("(?:a+){0}", 0, 0);
427 CHECK_MIN_MAX("(?:a+){0,0}", 0, 0);
428 CHECK_MIN_MAX("a*b", 1, RegExpTree::kInfinity);
429 CHECK_MIN_MAX("a+b", 2, RegExpTree::kInfinity);
430 CHECK_MIN_MAX("a*b|c", 1, RegExpTree::kInfinity);
431 CHECK_MIN_MAX("a+b|c", 1, RegExpTree::kInfinity);
432 CHECK_MIN_MAX("(?:a{5,1000000}){3,1000000}", 15, RegExpTree::kInfinity);
433 CHECK_MIN_MAX("(?:ab){4,7}", 8, 14);
434 CHECK_MIN_MAX("a\\bc", 2, 2);
435 CHECK_MIN_MAX("a\\Bc", 2, 2);
436 CHECK_MIN_MAX("a\\sc", 3, 3);
437 CHECK_MIN_MAX("a\\Sc", 3, 3);
438 CHECK_MIN_MAX("a(?=b)c", 2, 2);
439 CHECK_MIN_MAX("a(?=bbb|bb)c", 2, 2);
440 CHECK_MIN_MAX("a(?!bbb|bb)c", 2, 2);
441}
442
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000443
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000444TEST(ParserWithLookbehind) {
445 TestRegExpParser(true); // Lookbehind enabled.
446}
447
448
449TEST(ParserWithoutLookbehind) {
450 TestRegExpParser(true); // Lookbehind enabled.
451}
452
453
Steve Blocka7e24c12009-10-30 11:49:00 +0000454TEST(ParserRegression) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000455 CheckParseEq("[A-Z$-][x]", "(! [A-Z $ -] [x])");
456 CheckParseEq("a{3,4*}", "(: 'a{3,' (# 0 - g '4') '}')");
457 CheckParseEq("{", "'{'");
458 CheckParseEq("a|", "(| 'a' %)");
Steve Blocka7e24c12009-10-30 11:49:00 +0000459}
460
461static void ExpectError(const char* input,
462 const char* expected) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000463 v8::HandleScope scope(CcTest::isolate());
Ben Murdochda12d292016-06-02 14:46:10 +0100464 Zone zone(CcTest::i_isolate()->allocator());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000465 FlatStringReader reader(CcTest::i_isolate(), CStrVector(input));
Steve Blocka7e24c12009-10-30 11:49:00 +0000466 RegExpCompileData result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000467 CHECK(!v8::internal::RegExpParser::ParseRegExp(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100468 CcTest::i_isolate(), &zone, &reader, JSRegExp::kNone, &result));
Steve Blocka7e24c12009-10-30 11:49:00 +0000469 CHECK(result.tree == NULL);
470 CHECK(!result.error.is_null());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000471 v8::base::SmartArrayPointer<char> str = result.error->ToCString(ALLOW_NULLS);
472 CHECK_EQ(0, strcmp(expected, str.get()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000473}
474
475
476TEST(Errors) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000477 const char* kEndBackslash = "\\ at end of pattern";
478 ExpectError("\\", kEndBackslash);
479 const char* kUnterminatedGroup = "Unterminated group";
480 ExpectError("(foo", kUnterminatedGroup);
481 const char* kInvalidGroup = "Invalid group";
482 ExpectError("(?", kInvalidGroup);
483 const char* kUnterminatedCharacterClass = "Unterminated character class";
484 ExpectError("[", kUnterminatedCharacterClass);
485 ExpectError("[a-", kUnterminatedCharacterClass);
486 const char* kNothingToRepeat = "Nothing to repeat";
487 ExpectError("*", kNothingToRepeat);
488 ExpectError("?", kNothingToRepeat);
489 ExpectError("+", kNothingToRepeat);
490 ExpectError("{1}", kNothingToRepeat);
491 ExpectError("{1,2}", kNothingToRepeat);
492 ExpectError("{1,}", kNothingToRepeat);
493
494 // Check that we don't allow more than kMaxCapture captures
495 const int kMaxCaptures = 1 << 16; // Must match RegExpParser::kMaxCaptures.
496 const char* kTooManyCaptures = "Too many captures";
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400497 std::ostringstream os;
Steve Blocka7e24c12009-10-30 11:49:00 +0000498 for (int i = 0; i <= kMaxCaptures; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000499 os << "()";
Steve Blocka7e24c12009-10-30 11:49:00 +0000500 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400501 ExpectError(os.str().c_str(), kTooManyCaptures);
Steve Blocka7e24c12009-10-30 11:49:00 +0000502}
503
504
505static bool IsDigit(uc16 c) {
506 return ('0' <= c && c <= '9');
507}
508
509
510static bool NotDigit(uc16 c) {
511 return !IsDigit(c);
512}
513
514
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000515static bool IsWhiteSpaceOrLineTerminator(uc16 c) {
516 // According to ECMA 5.1, 15.10.2.12 the CharacterClassEscape \s includes
517 // WhiteSpace (7.2) and LineTerminator (7.3) values.
518 return v8::internal::WhiteSpaceOrLineTerminator::Is(c);
Steve Blocka7e24c12009-10-30 11:49:00 +0000519}
520
521
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000522static bool NotWhiteSpaceNorLineTermiantor(uc16 c) {
523 return !IsWhiteSpaceOrLineTerminator(c);
Steve Blocka7e24c12009-10-30 11:49:00 +0000524}
525
526
527static bool NotWord(uc16 c) {
528 return !IsRegExpWord(c);
529}
530
531
532static void TestCharacterClassEscapes(uc16 c, bool (pred)(uc16 c)) {
Ben Murdochda12d292016-06-02 14:46:10 +0100533 Zone zone(CcTest::i_isolate()->allocator());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000534 ZoneList<CharacterRange>* ranges =
535 new(&zone) ZoneList<CharacterRange>(2, &zone);
536 CharacterRange::AddClassEscape(c, ranges, &zone);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100537 for (uc32 i = 0; i < (1 << 16); i++) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000538 bool in_class = false;
539 for (int j = 0; !in_class && j < ranges->length(); j++) {
540 CharacterRange& range = ranges->at(j);
541 in_class = (range.from() <= i && i <= range.to());
542 }
543 CHECK_EQ(pred(i), in_class);
544 }
545}
546
547
548TEST(CharacterClassEscapes) {
549 TestCharacterClassEscapes('.', IsRegExpNewline);
550 TestCharacterClassEscapes('d', IsDigit);
551 TestCharacterClassEscapes('D', NotDigit);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000552 TestCharacterClassEscapes('s', IsWhiteSpaceOrLineTerminator);
553 TestCharacterClassEscapes('S', NotWhiteSpaceNorLineTermiantor);
Steve Blocka7e24c12009-10-30 11:49:00 +0000554 TestCharacterClassEscapes('w', IsRegExpWord);
555 TestCharacterClassEscapes('W', NotWord);
556}
557
558
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000559static RegExpNode* Compile(const char* input, bool multiline, bool unicode,
560 bool is_one_byte, Zone* zone) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000561 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100562 FlatStringReader reader(isolate, CStrVector(input));
Steve Blocka7e24c12009-10-30 11:49:00 +0000563 RegExpCompileData compile_data;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100564 JSRegExp::Flags flags = JSRegExp::kNone;
565 if (multiline) flags = JSRegExp::kMultiline;
566 if (unicode) flags = JSRegExp::kUnicode;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000567 if (!v8::internal::RegExpParser::ParseRegExp(CcTest::i_isolate(), zone,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100568 &reader, flags, &compile_data))
Steve Blocka7e24c12009-10-30 11:49:00 +0000569 return NULL;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000570 Handle<String> pattern = isolate->factory()
571 ->NewStringFromUtf8(CStrVector(input))
572 .ToHandleChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000573 Handle<String> sample_subject =
574 isolate->factory()->NewStringFromUtf8(CStrVector("")).ToHandleChecked();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100575 RegExpEngine::Compile(isolate, zone, &compile_data, flags, pattern,
576 sample_subject, is_one_byte);
Steve Blocka7e24c12009-10-30 11:49:00 +0000577 return compile_data.node;
578}
579
580
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000581static void Execute(const char* input, bool multiline, bool unicode,
582 bool is_one_byte, bool dot_output = false) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000583 v8::HandleScope scope(CcTest::isolate());
Ben Murdochda12d292016-06-02 14:46:10 +0100584 Zone zone(CcTest::i_isolate()->allocator());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000585 RegExpNode* node = Compile(input, multiline, unicode, is_one_byte, &zone);
Steve Blocka7e24c12009-10-30 11:49:00 +0000586 USE(node);
587#ifdef DEBUG
588 if (dot_output) {
589 RegExpEngine::DotPrint(input, node, false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000590 }
591#endif // DEBUG
592}
593
594
595class TestConfig {
596 public:
597 typedef int Key;
598 typedef int Value;
599 static const int kNoKey;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100600 static int NoValue() { return 0; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000601 static inline int Compare(int a, int b) {
602 if (a < b)
603 return -1;
604 else if (a > b)
605 return 1;
606 else
607 return 0;
608 }
609};
610
611
612const int TestConfig::kNoKey = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000613
614
615static unsigned PseudoRandom(int i, int j) {
616 return ~(~((i * 781) ^ (j * 329)));
617}
618
619
620TEST(SplayTreeSimple) {
621 static const unsigned kLimit = 1000;
Ben Murdochda12d292016-06-02 14:46:10 +0100622 Zone zone(CcTest::i_isolate()->allocator());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000623 ZoneSplayTree<TestConfig> tree(&zone);
Steve Blocka7e24c12009-10-30 11:49:00 +0000624 bool seen[kLimit];
625 for (unsigned i = 0; i < kLimit; i++) seen[i] = false;
626#define CHECK_MAPS_EQUAL() do { \
627 for (unsigned k = 0; k < kLimit; k++) \
628 CHECK_EQ(seen[k], tree.Find(k, &loc)); \
629 } while (false)
630 for (int i = 0; i < 50; i++) {
631 for (int j = 0; j < 50; j++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000632 int next = PseudoRandom(i, j) % kLimit;
Steve Blocka7e24c12009-10-30 11:49:00 +0000633 if (seen[next]) {
634 // We've already seen this one. Check the value and remove
635 // it.
636 ZoneSplayTree<TestConfig>::Locator loc;
637 CHECK(tree.Find(next, &loc));
638 CHECK_EQ(next, loc.key());
639 CHECK_EQ(3 * next, loc.value());
640 tree.Remove(next);
641 seen[next] = false;
642 CHECK_MAPS_EQUAL();
643 } else {
644 // Check that it wasn't there already and then add it.
645 ZoneSplayTree<TestConfig>::Locator loc;
646 CHECK(!tree.Find(next, &loc));
647 CHECK(tree.Insert(next, &loc));
648 CHECK_EQ(next, loc.key());
649 loc.set_value(3 * next);
650 seen[next] = true;
651 CHECK_MAPS_EQUAL();
652 }
653 int val = PseudoRandom(j, i) % kLimit;
654 if (seen[val]) {
655 ZoneSplayTree<TestConfig>::Locator loc;
656 CHECK(tree.FindGreatestLessThan(val, &loc));
657 CHECK_EQ(loc.key(), val);
658 break;
659 }
660 val = PseudoRandom(i + j, i - j) % kLimit;
661 if (seen[val]) {
662 ZoneSplayTree<TestConfig>::Locator loc;
663 CHECK(tree.FindLeastGreaterThan(val, &loc));
664 CHECK_EQ(loc.key(), val);
665 break;
666 }
667 }
668 }
669}
670
671
672TEST(DispatchTableConstruction) {
673 // Initialize test data.
674 static const int kLimit = 1000;
675 static const int kRangeCount = 8;
676 static const int kRangeSize = 16;
677 uc16 ranges[kRangeCount][2 * kRangeSize];
678 for (int i = 0; i < kRangeCount; i++) {
679 Vector<uc16> range(ranges[i], 2 * kRangeSize);
680 for (int j = 0; j < 2 * kRangeSize; j++) {
681 range[j] = PseudoRandom(i + 25, j + 87) % kLimit;
682 }
683 range.Sort();
684 for (int j = 1; j < 2 * kRangeSize; j++) {
685 CHECK(range[j-1] <= range[j]);
686 }
687 }
688 // Enter test data into dispatch table.
Ben Murdochda12d292016-06-02 14:46:10 +0100689 Zone zone(CcTest::i_isolate()->allocator());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000690 DispatchTable table(&zone);
Steve Blocka7e24c12009-10-30 11:49:00 +0000691 for (int i = 0; i < kRangeCount; i++) {
692 uc16* range = ranges[i];
693 for (int j = 0; j < 2 * kRangeSize; j += 2)
Ben Murdoch097c5b22016-05-18 11:27:45 +0100694 table.AddRange(CharacterRange::Range(range[j], range[j + 1]), i, &zone);
Steve Blocka7e24c12009-10-30 11:49:00 +0000695 }
696 // Check that the table looks as we would expect
697 for (int p = 0; p < kLimit; p++) {
698 OutSet* outs = table.Get(p);
699 for (int j = 0; j < kRangeCount; j++) {
700 uc16* range = ranges[j];
701 bool is_on = false;
702 for (int k = 0; !is_on && (k < 2 * kRangeSize); k += 2)
703 is_on = (range[k] <= p && p <= range[k + 1]);
704 CHECK_EQ(is_on, outs->Get(j));
705 }
706 }
707}
708
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000709
Leon Clarkee46be812010-01-19 14:06:41 +0000710// Test of debug-only syntax.
711#ifdef DEBUG
712
713TEST(ParsePossessiveRepetition) {
714 bool old_flag_value = FLAG_regexp_possessive_quantifier;
715
716 // Enable possessive quantifier syntax.
717 FLAG_regexp_possessive_quantifier = true;
718
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000719 CheckParseEq("a*+", "(# 0 - p 'a')");
720 CheckParseEq("a++", "(# 1 - p 'a')");
721 CheckParseEq("a?+", "(# 0 1 p 'a')");
722 CheckParseEq("a{10,20}+", "(# 10 20 p 'a')");
723 CheckParseEq("za{10,20}+b", "(: 'z' (# 10 20 p 'a') 'b')");
Leon Clarkee46be812010-01-19 14:06:41 +0000724
725 // Disable possessive quantifier syntax.
726 FLAG_regexp_possessive_quantifier = false;
727
728 CHECK_PARSE_ERROR("a*+");
729 CHECK_PARSE_ERROR("a++");
730 CHECK_PARSE_ERROR("a?+");
731 CHECK_PARSE_ERROR("a{10,20}+");
732 CHECK_PARSE_ERROR("a{10,20}+b");
733
734 FLAG_regexp_possessive_quantifier = old_flag_value;
735}
736
737#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000738
739// Tests of interpreter.
740
741
Steve Block6ded16b2010-05-10 14:33:55 +0100742#ifndef V8_INTERPRETED_REGEXP
Steve Blocka7e24c12009-10-30 11:49:00 +0000743
744#if V8_TARGET_ARCH_IA32
745typedef RegExpMacroAssemblerIA32 ArchRegExpMacroAssembler;
746#elif V8_TARGET_ARCH_X64
747typedef RegExpMacroAssemblerX64 ArchRegExpMacroAssembler;
748#elif V8_TARGET_ARCH_ARM
749typedef RegExpMacroAssemblerARM ArchRegExpMacroAssembler;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000750#elif V8_TARGET_ARCH_ARM64
751typedef RegExpMacroAssemblerARM64 ArchRegExpMacroAssembler;
Ben Murdochda12d292016-06-02 14:46:10 +0100752#elif V8_TARGET_ARCH_S390
753typedef RegExpMacroAssemblerS390 ArchRegExpMacroAssembler;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000754#elif V8_TARGET_ARCH_PPC
755typedef RegExpMacroAssemblerPPC ArchRegExpMacroAssembler;
Andrei Popescu31002712010-02-23 13:46:05 +0000756#elif V8_TARGET_ARCH_MIPS
Steve Block44f0eee2011-05-26 01:26:41 +0100757typedef RegExpMacroAssemblerMIPS ArchRegExpMacroAssembler;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000758#elif V8_TARGET_ARCH_MIPS64
759typedef RegExpMacroAssemblerMIPS ArchRegExpMacroAssembler;
760#elif V8_TARGET_ARCH_X87
761typedef RegExpMacroAssemblerX87 ArchRegExpMacroAssembler;
Steve Blocka7e24c12009-10-30 11:49:00 +0000762#endif
763
764class ContextInitializer {
765 public:
766 ContextInitializer()
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000767 : scope_(CcTest::isolate()),
768 env_(v8::Context::New(CcTest::isolate())) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000769 env_->Enter();
770 }
771 ~ContextInitializer() {
772 env_->Exit();
Steve Blocka7e24c12009-10-30 11:49:00 +0000773 }
774 private:
Steve Blocka7e24c12009-10-30 11:49:00 +0000775 v8::HandleScope scope_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000776 v8::Local<v8::Context> env_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000777};
778
779
780static ArchRegExpMacroAssembler::Result Execute(Code* code,
781 String* input,
782 int start_offset,
783 const byte* input_start,
784 const byte* input_end,
Leon Clarked91b9f72010-01-27 17:25:45 +0000785 int* captures) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000786 return NativeRegExpMacroAssembler::Execute(
787 code,
788 input,
789 start_offset,
790 input_start,
791 input_end,
Steve Block44f0eee2011-05-26 01:26:41 +0100792 captures,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000793 0,
794 CcTest::i_isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000795}
796
797
798TEST(MacroAssemblerNativeSuccess) {
799 v8::V8::Initialize();
800 ContextInitializer initializer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000801 Isolate* isolate = CcTest::i_isolate();
802 Factory* factory = isolate->factory();
Ben Murdochda12d292016-06-02 14:46:10 +0100803 Zone zone(CcTest::i_isolate()->allocator());
Steve Blocka7e24c12009-10-30 11:49:00 +0000804
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000805 ArchRegExpMacroAssembler m(isolate, &zone, NativeRegExpMacroAssembler::LATIN1,
806 4);
Steve Blocka7e24c12009-10-30 11:49:00 +0000807
808 m.Succeed();
809
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000810 Handle<String> source = factory->NewStringFromStaticChars("");
Steve Blocka7e24c12009-10-30 11:49:00 +0000811 Handle<Object> code_object = m.GetCode(source);
812 Handle<Code> code = Handle<Code>::cast(code_object);
813
814 int captures[4] = {42, 37, 87, 117};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000815 Handle<String> input = factory->NewStringFromStaticChars("foofoo");
816 Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input);
Steve Blocka7e24c12009-10-30 11:49:00 +0000817 const byte* start_adr =
818 reinterpret_cast<const byte*>(seq_input->GetCharsAddress());
819
820 NativeRegExpMacroAssembler::Result result =
821 Execute(*code,
822 *input,
823 0,
824 start_adr,
825 start_adr + seq_input->length(),
Leon Clarked91b9f72010-01-27 17:25:45 +0000826 captures);
Steve Blocka7e24c12009-10-30 11:49:00 +0000827
828 CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
829 CHECK_EQ(-1, captures[0]);
830 CHECK_EQ(-1, captures[1]);
831 CHECK_EQ(-1, captures[2]);
832 CHECK_EQ(-1, captures[3]);
833}
834
835
836TEST(MacroAssemblerNativeSimple) {
837 v8::V8::Initialize();
838 ContextInitializer initializer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000839 Isolate* isolate = CcTest::i_isolate();
840 Factory* factory = isolate->factory();
Ben Murdochda12d292016-06-02 14:46:10 +0100841 Zone zone(CcTest::i_isolate()->allocator());
Steve Blocka7e24c12009-10-30 11:49:00 +0000842
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000843 ArchRegExpMacroAssembler m(isolate, &zone, NativeRegExpMacroAssembler::LATIN1,
844 4);
Steve Blocka7e24c12009-10-30 11:49:00 +0000845
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000846 Label fail, backtrack;
847 m.PushBacktrack(&fail);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000848 m.CheckNotAtStart(0, NULL);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000849 m.LoadCurrentCharacter(2, NULL);
850 m.CheckNotCharacter('o', NULL);
851 m.LoadCurrentCharacter(1, NULL, false);
852 m.CheckNotCharacter('o', NULL);
853 m.LoadCurrentCharacter(0, NULL, false);
854 m.CheckNotCharacter('f', NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000855 m.WriteCurrentPositionToRegister(0, 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000856 m.WriteCurrentPositionToRegister(1, 3);
Steve Blocka7e24c12009-10-30 11:49:00 +0000857 m.AdvanceCurrentPosition(3);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000858 m.PushBacktrack(&backtrack);
Steve Blocka7e24c12009-10-30 11:49:00 +0000859 m.Succeed();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000860 m.Bind(&backtrack);
861 m.Backtrack();
Steve Blocka7e24c12009-10-30 11:49:00 +0000862 m.Bind(&fail);
863 m.Fail();
864
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000865 Handle<String> source = factory->NewStringFromStaticChars("^foo");
Steve Blocka7e24c12009-10-30 11:49:00 +0000866 Handle<Object> code_object = m.GetCode(source);
867 Handle<Code> code = Handle<Code>::cast(code_object);
868
869 int captures[4] = {42, 37, 87, 117};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000870 Handle<String> input = factory->NewStringFromStaticChars("foofoo");
871 Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input);
Steve Blocka7e24c12009-10-30 11:49:00 +0000872 Address start_adr = seq_input->GetCharsAddress();
873
874 NativeRegExpMacroAssembler::Result result =
875 Execute(*code,
876 *input,
877 0,
878 start_adr,
879 start_adr + input->length(),
Leon Clarked91b9f72010-01-27 17:25:45 +0000880 captures);
Steve Blocka7e24c12009-10-30 11:49:00 +0000881
882 CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
883 CHECK_EQ(0, captures[0]);
884 CHECK_EQ(3, captures[1]);
885 CHECK_EQ(-1, captures[2]);
886 CHECK_EQ(-1, captures[3]);
887
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000888 input = factory->NewStringFromStaticChars("barbarbar");
889 seq_input = Handle<SeqOneByteString>::cast(input);
Steve Blocka7e24c12009-10-30 11:49:00 +0000890 start_adr = seq_input->GetCharsAddress();
891
892 result = Execute(*code,
893 *input,
894 0,
895 start_adr,
896 start_adr + input->length(),
Leon Clarked91b9f72010-01-27 17:25:45 +0000897 captures);
Steve Blocka7e24c12009-10-30 11:49:00 +0000898
899 CHECK_EQ(NativeRegExpMacroAssembler::FAILURE, result);
900}
901
902
903TEST(MacroAssemblerNativeSimpleUC16) {
904 v8::V8::Initialize();
905 ContextInitializer initializer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000906 Isolate* isolate = CcTest::i_isolate();
907 Factory* factory = isolate->factory();
Ben Murdochda12d292016-06-02 14:46:10 +0100908 Zone zone(CcTest::i_isolate()->allocator());
Steve Blocka7e24c12009-10-30 11:49:00 +0000909
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000910 ArchRegExpMacroAssembler m(isolate, &zone, NativeRegExpMacroAssembler::UC16,
911 4);
Steve Blocka7e24c12009-10-30 11:49:00 +0000912
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000913 Label fail, backtrack;
914 m.PushBacktrack(&fail);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000915 m.CheckNotAtStart(0, NULL);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000916 m.LoadCurrentCharacter(2, NULL);
917 m.CheckNotCharacter('o', NULL);
918 m.LoadCurrentCharacter(1, NULL, false);
919 m.CheckNotCharacter('o', NULL);
920 m.LoadCurrentCharacter(0, NULL, false);
921 m.CheckNotCharacter('f', NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000922 m.WriteCurrentPositionToRegister(0, 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000923 m.WriteCurrentPositionToRegister(1, 3);
Steve Blocka7e24c12009-10-30 11:49:00 +0000924 m.AdvanceCurrentPosition(3);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000925 m.PushBacktrack(&backtrack);
Steve Blocka7e24c12009-10-30 11:49:00 +0000926 m.Succeed();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000927 m.Bind(&backtrack);
928 m.Backtrack();
Steve Blocka7e24c12009-10-30 11:49:00 +0000929 m.Bind(&fail);
930 m.Fail();
931
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000932 Handle<String> source = factory->NewStringFromStaticChars("^foo");
Steve Blocka7e24c12009-10-30 11:49:00 +0000933 Handle<Object> code_object = m.GetCode(source);
934 Handle<Code> code = Handle<Code>::cast(code_object);
935
936 int captures[4] = {42, 37, 87, 117};
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100937 const uc16 input_data[6] = {'f', 'o', 'o', 'f', 'o',
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000938 static_cast<uc16>(0x2603)};
939 Handle<String> input = factory->NewStringFromTwoByte(
940 Vector<const uc16>(input_data, 6)).ToHandleChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +0000941 Handle<SeqTwoByteString> seq_input = Handle<SeqTwoByteString>::cast(input);
942 Address start_adr = seq_input->GetCharsAddress();
943
944 NativeRegExpMacroAssembler::Result result =
945 Execute(*code,
946 *input,
947 0,
948 start_adr,
949 start_adr + input->length(),
Leon Clarked91b9f72010-01-27 17:25:45 +0000950 captures);
Steve Blocka7e24c12009-10-30 11:49:00 +0000951
952 CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
953 CHECK_EQ(0, captures[0]);
954 CHECK_EQ(3, captures[1]);
955 CHECK_EQ(-1, captures[2]);
956 CHECK_EQ(-1, captures[3]);
957
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100958 const uc16 input_data2[9] = {'b', 'a', 'r', 'b', 'a', 'r', 'b', 'a',
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000959 static_cast<uc16>(0x2603)};
960 input = factory->NewStringFromTwoByte(
961 Vector<const uc16>(input_data2, 9)).ToHandleChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +0000962 seq_input = Handle<SeqTwoByteString>::cast(input);
963 start_adr = seq_input->GetCharsAddress();
964
965 result = Execute(*code,
966 *input,
967 0,
968 start_adr,
969 start_adr + input->length() * 2,
Leon Clarked91b9f72010-01-27 17:25:45 +0000970 captures);
Steve Blocka7e24c12009-10-30 11:49:00 +0000971
972 CHECK_EQ(NativeRegExpMacroAssembler::FAILURE, result);
973}
974
975
976TEST(MacroAssemblerNativeBacktrack) {
977 v8::V8::Initialize();
978 ContextInitializer initializer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000979 Isolate* isolate = CcTest::i_isolate();
980 Factory* factory = isolate->factory();
Ben Murdochda12d292016-06-02 14:46:10 +0100981 Zone zone(CcTest::i_isolate()->allocator());
Steve Blocka7e24c12009-10-30 11:49:00 +0000982
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000983 ArchRegExpMacroAssembler m(isolate, &zone, NativeRegExpMacroAssembler::LATIN1,
984 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000985
986 Label fail;
987 Label backtrack;
988 m.LoadCurrentCharacter(10, &fail);
989 m.Succeed();
990 m.Bind(&fail);
991 m.PushBacktrack(&backtrack);
992 m.LoadCurrentCharacter(10, NULL);
993 m.Succeed();
994 m.Bind(&backtrack);
995 m.Fail();
996
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000997 Handle<String> source = factory->NewStringFromStaticChars("..........");
Steve Blocka7e24c12009-10-30 11:49:00 +0000998 Handle<Object> code_object = m.GetCode(source);
999 Handle<Code> code = Handle<Code>::cast(code_object);
1000
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001001 Handle<String> input = factory->NewStringFromStaticChars("foofoo");
1002 Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input);
Steve Blocka7e24c12009-10-30 11:49:00 +00001003 Address start_adr = seq_input->GetCharsAddress();
1004
1005 NativeRegExpMacroAssembler::Result result =
1006 Execute(*code,
1007 *input,
1008 0,
1009 start_adr,
1010 start_adr + input->length(),
Leon Clarked91b9f72010-01-27 17:25:45 +00001011 NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001012
1013 CHECK_EQ(NativeRegExpMacroAssembler::FAILURE, result);
1014}
1015
1016
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001017TEST(MacroAssemblerNativeBackReferenceLATIN1) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001018 v8::V8::Initialize();
1019 ContextInitializer initializer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001020 Isolate* isolate = CcTest::i_isolate();
1021 Factory* factory = isolate->factory();
Ben Murdochda12d292016-06-02 14:46:10 +01001022 Zone zone(CcTest::i_isolate()->allocator());
Steve Blocka7e24c12009-10-30 11:49:00 +00001023
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001024 ArchRegExpMacroAssembler m(isolate, &zone, NativeRegExpMacroAssembler::LATIN1,
1025 4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001026
1027 m.WriteCurrentPositionToRegister(0, 0);
1028 m.AdvanceCurrentPosition(2);
1029 m.WriteCurrentPositionToRegister(1, 0);
1030 Label nomatch;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001031 m.CheckNotBackReference(0, false, &nomatch);
Steve Blocka7e24c12009-10-30 11:49:00 +00001032 m.Fail();
1033 m.Bind(&nomatch);
1034 m.AdvanceCurrentPosition(2);
1035 Label missing_match;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001036 m.CheckNotBackReference(0, false, &missing_match);
Steve Blocka7e24c12009-10-30 11:49:00 +00001037 m.WriteCurrentPositionToRegister(2, 0);
1038 m.Succeed();
1039 m.Bind(&missing_match);
1040 m.Fail();
1041
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001042 Handle<String> source = factory->NewStringFromStaticChars("^(..)..\1");
Steve Blocka7e24c12009-10-30 11:49:00 +00001043 Handle<Object> code_object = m.GetCode(source);
1044 Handle<Code> code = Handle<Code>::cast(code_object);
1045
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001046 Handle<String> input = factory->NewStringFromStaticChars("fooofo");
1047 Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input);
Steve Blocka7e24c12009-10-30 11:49:00 +00001048 Address start_adr = seq_input->GetCharsAddress();
1049
1050 int output[4];
1051 NativeRegExpMacroAssembler::Result result =
1052 Execute(*code,
1053 *input,
1054 0,
1055 start_adr,
1056 start_adr + input->length(),
Leon Clarked91b9f72010-01-27 17:25:45 +00001057 output);
Steve Blocka7e24c12009-10-30 11:49:00 +00001058
1059 CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
1060 CHECK_EQ(0, output[0]);
1061 CHECK_EQ(2, output[1]);
1062 CHECK_EQ(6, output[2]);
1063 CHECK_EQ(-1, output[3]);
1064}
1065
1066
1067TEST(MacroAssemblerNativeBackReferenceUC16) {
1068 v8::V8::Initialize();
1069 ContextInitializer initializer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001070 Isolate* isolate = CcTest::i_isolate();
1071 Factory* factory = isolate->factory();
Ben Murdochda12d292016-06-02 14:46:10 +01001072 Zone zone(CcTest::i_isolate()->allocator());
Steve Blocka7e24c12009-10-30 11:49:00 +00001073
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001074 ArchRegExpMacroAssembler m(isolate, &zone, NativeRegExpMacroAssembler::UC16,
1075 4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001076
1077 m.WriteCurrentPositionToRegister(0, 0);
1078 m.AdvanceCurrentPosition(2);
1079 m.WriteCurrentPositionToRegister(1, 0);
1080 Label nomatch;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001081 m.CheckNotBackReference(0, false, &nomatch);
Steve Blocka7e24c12009-10-30 11:49:00 +00001082 m.Fail();
1083 m.Bind(&nomatch);
1084 m.AdvanceCurrentPosition(2);
1085 Label missing_match;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001086 m.CheckNotBackReference(0, false, &missing_match);
Steve Blocka7e24c12009-10-30 11:49:00 +00001087 m.WriteCurrentPositionToRegister(2, 0);
1088 m.Succeed();
1089 m.Bind(&missing_match);
1090 m.Fail();
1091
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001092 Handle<String> source = factory->NewStringFromStaticChars("^(..)..\1");
Steve Blocka7e24c12009-10-30 11:49:00 +00001093 Handle<Object> code_object = m.GetCode(source);
1094 Handle<Code> code = Handle<Code>::cast(code_object);
1095
1096 const uc16 input_data[6] = {'f', 0x2028, 'o', 'o', 'f', 0x2028};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001097 Handle<String> input = factory->NewStringFromTwoByte(
1098 Vector<const uc16>(input_data, 6)).ToHandleChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001099 Handle<SeqTwoByteString> seq_input = Handle<SeqTwoByteString>::cast(input);
1100 Address start_adr = seq_input->GetCharsAddress();
1101
1102 int output[4];
1103 NativeRegExpMacroAssembler::Result result =
1104 Execute(*code,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001105 *input,
1106 0,
1107 start_adr,
1108 start_adr + input->length() * 2,
1109 output);
Steve Blocka7e24c12009-10-30 11:49:00 +00001110
1111 CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
1112 CHECK_EQ(0, output[0]);
1113 CHECK_EQ(2, output[1]);
1114 CHECK_EQ(6, output[2]);
1115 CHECK_EQ(-1, output[3]);
1116}
1117
1118
1119
1120TEST(MacroAssemblernativeAtStart) {
1121 v8::V8::Initialize();
1122 ContextInitializer initializer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001123 Isolate* isolate = CcTest::i_isolate();
1124 Factory* factory = isolate->factory();
Ben Murdochda12d292016-06-02 14:46:10 +01001125 Zone zone(CcTest::i_isolate()->allocator());
Steve Blocka7e24c12009-10-30 11:49:00 +00001126
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001127 ArchRegExpMacroAssembler m(isolate, &zone, NativeRegExpMacroAssembler::LATIN1,
1128 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001129
1130 Label not_at_start, newline, fail;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001131 m.CheckNotAtStart(0, &not_at_start);
Steve Blocka7e24c12009-10-30 11:49:00 +00001132 // Check that prevchar = '\n' and current = 'f'.
1133 m.CheckCharacter('\n', &newline);
1134 m.Bind(&fail);
1135 m.Fail();
1136 m.Bind(&newline);
1137 m.LoadCurrentCharacter(0, &fail);
1138 m.CheckNotCharacter('f', &fail);
1139 m.Succeed();
1140
1141 m.Bind(&not_at_start);
1142 // Check that prevchar = 'o' and current = 'b'.
1143 Label prevo;
1144 m.CheckCharacter('o', &prevo);
1145 m.Fail();
1146 m.Bind(&prevo);
1147 m.LoadCurrentCharacter(0, &fail);
1148 m.CheckNotCharacter('b', &fail);
1149 m.Succeed();
1150
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001151 Handle<String> source = factory->NewStringFromStaticChars("(^f|ob)");
Steve Blocka7e24c12009-10-30 11:49:00 +00001152 Handle<Object> code_object = m.GetCode(source);
1153 Handle<Code> code = Handle<Code>::cast(code_object);
1154
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001155 Handle<String> input = factory->NewStringFromStaticChars("foobar");
1156 Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input);
Steve Blocka7e24c12009-10-30 11:49:00 +00001157 Address start_adr = seq_input->GetCharsAddress();
1158
1159 NativeRegExpMacroAssembler::Result result =
1160 Execute(*code,
1161 *input,
1162 0,
1163 start_adr,
1164 start_adr + input->length(),
Leon Clarked91b9f72010-01-27 17:25:45 +00001165 NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001166
1167 CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
1168
1169 result = Execute(*code,
1170 *input,
1171 3,
1172 start_adr + 3,
1173 start_adr + input->length(),
Leon Clarked91b9f72010-01-27 17:25:45 +00001174 NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001175
1176 CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
1177}
1178
1179
1180TEST(MacroAssemblerNativeBackRefNoCase) {
1181 v8::V8::Initialize();
1182 ContextInitializer initializer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001183 Isolate* isolate = CcTest::i_isolate();
1184 Factory* factory = isolate->factory();
Ben Murdochda12d292016-06-02 14:46:10 +01001185 Zone zone(CcTest::i_isolate()->allocator());
Steve Blocka7e24c12009-10-30 11:49:00 +00001186
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001187 ArchRegExpMacroAssembler m(isolate, &zone, NativeRegExpMacroAssembler::LATIN1,
1188 4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001189
1190 Label fail, succ;
1191
1192 m.WriteCurrentPositionToRegister(0, 0);
1193 m.WriteCurrentPositionToRegister(2, 0);
1194 m.AdvanceCurrentPosition(3);
1195 m.WriteCurrentPositionToRegister(3, 0);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001196 m.CheckNotBackReferenceIgnoreCase(2, false, false, &fail); // Match "AbC".
1197 m.CheckNotBackReferenceIgnoreCase(2, false, false, &fail); // Match "ABC".
Steve Blocka7e24c12009-10-30 11:49:00 +00001198 Label expected_fail;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001199 m.CheckNotBackReferenceIgnoreCase(2, false, false, &expected_fail);
Steve Blocka7e24c12009-10-30 11:49:00 +00001200 m.Bind(&fail);
1201 m.Fail();
1202
1203 m.Bind(&expected_fail);
1204 m.AdvanceCurrentPosition(3); // Skip "xYz"
Ben Murdoch097c5b22016-05-18 11:27:45 +01001205 m.CheckNotBackReferenceIgnoreCase(2, false, false, &succ);
Steve Blocka7e24c12009-10-30 11:49:00 +00001206 m.Fail();
1207
1208 m.Bind(&succ);
1209 m.WriteCurrentPositionToRegister(1, 0);
1210 m.Succeed();
1211
1212 Handle<String> source =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001213 factory->NewStringFromStaticChars("^(abc)\1\1(?!\1)...(?!\1)");
Steve Blocka7e24c12009-10-30 11:49:00 +00001214 Handle<Object> code_object = m.GetCode(source);
1215 Handle<Code> code = Handle<Code>::cast(code_object);
1216
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001217 Handle<String> input = factory->NewStringFromStaticChars("aBcAbCABCxYzab");
1218 Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input);
Steve Blocka7e24c12009-10-30 11:49:00 +00001219 Address start_adr = seq_input->GetCharsAddress();
1220
1221 int output[4];
1222 NativeRegExpMacroAssembler::Result result =
1223 Execute(*code,
1224 *input,
1225 0,
1226 start_adr,
1227 start_adr + input->length(),
Leon Clarked91b9f72010-01-27 17:25:45 +00001228 output);
Steve Blocka7e24c12009-10-30 11:49:00 +00001229
1230 CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
1231 CHECK_EQ(0, output[0]);
1232 CHECK_EQ(12, output[1]);
1233 CHECK_EQ(0, output[2]);
1234 CHECK_EQ(3, output[3]);
1235}
1236
1237
1238
1239TEST(MacroAssemblerNativeRegisters) {
1240 v8::V8::Initialize();
1241 ContextInitializer initializer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001242 Isolate* isolate = CcTest::i_isolate();
1243 Factory* factory = isolate->factory();
Ben Murdochda12d292016-06-02 14:46:10 +01001244 Zone zone(CcTest::i_isolate()->allocator());
Steve Blocka7e24c12009-10-30 11:49:00 +00001245
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001246 ArchRegExpMacroAssembler m(isolate, &zone, NativeRegExpMacroAssembler::LATIN1,
1247 6);
Steve Blocka7e24c12009-10-30 11:49:00 +00001248
1249 uc16 foo_chars[3] = {'f', 'o', 'o'};
1250 Vector<const uc16> foo(foo_chars, 3);
1251
1252 enum registers { out1, out2, out3, out4, out5, out6, sp, loop_cnt };
1253 Label fail;
1254 Label backtrack;
1255 m.WriteCurrentPositionToRegister(out1, 0); // Output: [0]
1256 m.PushRegister(out1, RegExpMacroAssembler::kNoStackLimitCheck);
1257 m.PushBacktrack(&backtrack);
1258 m.WriteStackPointerToRegister(sp);
1259 // Fill stack and registers
1260 m.AdvanceCurrentPosition(2);
1261 m.WriteCurrentPositionToRegister(out1, 0);
1262 m.PushRegister(out1, RegExpMacroAssembler::kNoStackLimitCheck);
1263 m.PushBacktrack(&fail);
1264 // Drop backtrack stack frames.
1265 m.ReadStackPointerFromRegister(sp);
1266 // And take the first backtrack (to &backtrack)
1267 m.Backtrack();
1268
1269 m.PushCurrentPosition();
1270 m.AdvanceCurrentPosition(2);
1271 m.PopCurrentPosition();
1272
1273 m.Bind(&backtrack);
1274 m.PopRegister(out1);
1275 m.ReadCurrentPositionFromRegister(out1);
1276 m.AdvanceCurrentPosition(3);
1277 m.WriteCurrentPositionToRegister(out2, 0); // [0,3]
1278
1279 Label loop;
1280 m.SetRegister(loop_cnt, 0); // loop counter
1281 m.Bind(&loop);
1282 m.AdvanceRegister(loop_cnt, 1);
1283 m.AdvanceCurrentPosition(1);
1284 m.IfRegisterLT(loop_cnt, 3, &loop);
1285 m.WriteCurrentPositionToRegister(out3, 0); // [0,3,6]
1286
1287 Label loop2;
1288 m.SetRegister(loop_cnt, 2); // loop counter
1289 m.Bind(&loop2);
1290 m.AdvanceRegister(loop_cnt, -1);
1291 m.AdvanceCurrentPosition(1);
1292 m.IfRegisterGE(loop_cnt, 0, &loop2);
1293 m.WriteCurrentPositionToRegister(out4, 0); // [0,3,6,9]
1294
1295 Label loop3;
1296 Label exit_loop3;
1297 m.PushRegister(out4, RegExpMacroAssembler::kNoStackLimitCheck);
1298 m.PushRegister(out4, RegExpMacroAssembler::kNoStackLimitCheck);
1299 m.ReadCurrentPositionFromRegister(out3);
1300 m.Bind(&loop3);
1301 m.AdvanceCurrentPosition(1);
1302 m.CheckGreedyLoop(&exit_loop3);
1303 m.GoTo(&loop3);
1304 m.Bind(&exit_loop3);
1305 m.PopCurrentPosition();
1306 m.WriteCurrentPositionToRegister(out5, 0); // [0,3,6,9,9,-1]
1307
1308 m.Succeed();
1309
1310 m.Bind(&fail);
1311 m.Fail();
1312
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001313 Handle<String> source = factory->NewStringFromStaticChars("<loop test>");
Steve Blocka7e24c12009-10-30 11:49:00 +00001314 Handle<Object> code_object = m.GetCode(source);
1315 Handle<Code> code = Handle<Code>::cast(code_object);
1316
1317 // String long enough for test (content doesn't matter).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001318 Handle<String> input = factory->NewStringFromStaticChars("foofoofoofoofoo");
1319 Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input);
Steve Blocka7e24c12009-10-30 11:49:00 +00001320 Address start_adr = seq_input->GetCharsAddress();
1321
1322 int output[6];
1323 NativeRegExpMacroAssembler::Result result =
1324 Execute(*code,
1325 *input,
1326 0,
1327 start_adr,
1328 start_adr + input->length(),
Leon Clarked91b9f72010-01-27 17:25:45 +00001329 output);
Steve Blocka7e24c12009-10-30 11:49:00 +00001330
1331 CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
1332 CHECK_EQ(0, output[0]);
1333 CHECK_EQ(3, output[1]);
1334 CHECK_EQ(6, output[2]);
1335 CHECK_EQ(9, output[3]);
1336 CHECK_EQ(9, output[4]);
1337 CHECK_EQ(-1, output[5]);
1338}
1339
1340
1341TEST(MacroAssemblerStackOverflow) {
1342 v8::V8::Initialize();
1343 ContextInitializer initializer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001344 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch8b112d22011-06-08 16:22:53 +01001345 Factory* factory = isolate->factory();
Ben Murdochda12d292016-06-02 14:46:10 +01001346 Zone zone(CcTest::i_isolate()->allocator());
Steve Blocka7e24c12009-10-30 11:49:00 +00001347
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001348 ArchRegExpMacroAssembler m(isolate, &zone, NativeRegExpMacroAssembler::LATIN1,
1349 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001350
1351 Label loop;
1352 m.Bind(&loop);
1353 m.PushBacktrack(&loop);
1354 m.GoTo(&loop);
1355
1356 Handle<String> source =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001357 factory->NewStringFromStaticChars("<stack overflow test>");
Steve Blocka7e24c12009-10-30 11:49:00 +00001358 Handle<Object> code_object = m.GetCode(source);
1359 Handle<Code> code = Handle<Code>::cast(code_object);
1360
1361 // String long enough for test (content doesn't matter).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001362 Handle<String> input = factory->NewStringFromStaticChars("dummy");
1363 Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input);
Steve Blocka7e24c12009-10-30 11:49:00 +00001364 Address start_adr = seq_input->GetCharsAddress();
1365
1366 NativeRegExpMacroAssembler::Result result =
1367 Execute(*code,
1368 *input,
1369 0,
1370 start_adr,
1371 start_adr + input->length(),
Leon Clarked91b9f72010-01-27 17:25:45 +00001372 NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001373
1374 CHECK_EQ(NativeRegExpMacroAssembler::EXCEPTION, result);
Ben Murdoch8b112d22011-06-08 16:22:53 +01001375 CHECK(isolate->has_pending_exception());
1376 isolate->clear_pending_exception();
Steve Blocka7e24c12009-10-30 11:49:00 +00001377}
1378
1379
1380TEST(MacroAssemblerNativeLotsOfRegisters) {
1381 v8::V8::Initialize();
1382 ContextInitializer initializer;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001383 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch8b112d22011-06-08 16:22:53 +01001384 Factory* factory = isolate->factory();
Ben Murdochda12d292016-06-02 14:46:10 +01001385 Zone zone(CcTest::i_isolate()->allocator());
Steve Blocka7e24c12009-10-30 11:49:00 +00001386
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001387 ArchRegExpMacroAssembler m(isolate, &zone, NativeRegExpMacroAssembler::LATIN1,
1388 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001389
1390 // At least 2048, to ensure the allocated space for registers
1391 // span one full page.
1392 const int large_number = 8000;
1393 m.WriteCurrentPositionToRegister(large_number, 42);
1394 m.WriteCurrentPositionToRegister(0, 0);
1395 m.WriteCurrentPositionToRegister(1, 1);
1396 Label done;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001397 m.CheckNotBackReference(0, false, &done); // Performs a system-stack push.
Steve Blocka7e24c12009-10-30 11:49:00 +00001398 m.Bind(&done);
1399 m.PushRegister(large_number, RegExpMacroAssembler::kNoStackLimitCheck);
1400 m.PopRegister(1);
1401 m.Succeed();
1402
1403 Handle<String> source =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001404 factory->NewStringFromStaticChars("<huge register space test>");
Steve Blocka7e24c12009-10-30 11:49:00 +00001405 Handle<Object> code_object = m.GetCode(source);
1406 Handle<Code> code = Handle<Code>::cast(code_object);
1407
1408 // String long enough for test (content doesn't matter).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001409 Handle<String> input = factory->NewStringFromStaticChars("sample text");
1410 Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input);
Steve Blocka7e24c12009-10-30 11:49:00 +00001411 Address start_adr = seq_input->GetCharsAddress();
1412
1413 int captures[2];
1414 NativeRegExpMacroAssembler::Result result =
1415 Execute(*code,
1416 *input,
1417 0,
1418 start_adr,
1419 start_adr + input->length(),
Leon Clarked91b9f72010-01-27 17:25:45 +00001420 captures);
Steve Blocka7e24c12009-10-30 11:49:00 +00001421
1422 CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
1423 CHECK_EQ(0, captures[0]);
1424 CHECK_EQ(42, captures[1]);
1425
Ben Murdoch8b112d22011-06-08 16:22:53 +01001426 isolate->clear_pending_exception();
Steve Blocka7e24c12009-10-30 11:49:00 +00001427}
1428
Steve Block6ded16b2010-05-10 14:33:55 +01001429#else // V8_INTERPRETED_REGEXP
Steve Blocka7e24c12009-10-30 11:49:00 +00001430
1431TEST(MacroAssembler) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001432 byte codes[1024];
Ben Murdochda12d292016-06-02 14:46:10 +01001433 Zone zone(CcTest::i_isolate()->allocator());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001434 RegExpMacroAssemblerIrregexp m(CcTest::i_isolate(), Vector<byte>(codes, 1024),
1435 &zone);
Steve Blocka7e24c12009-10-30 11:49:00 +00001436 // ^f(o)o.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001437 Label start, fail, backtrack;
1438
Steve Blocka7e24c12009-10-30 11:49:00 +00001439 m.SetRegister(4, 42);
1440 m.PushRegister(4, RegExpMacroAssembler::kNoStackLimitCheck);
1441 m.AdvanceRegister(4, 42);
1442 m.GoTo(&start);
1443 m.Fail();
1444 m.Bind(&start);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001445 m.PushBacktrack(&fail);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001446 m.CheckNotAtStart(0, NULL);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001447 m.LoadCurrentCharacter(0, NULL);
1448 m.CheckNotCharacter('f', NULL);
1449 m.LoadCurrentCharacter(1, NULL);
1450 m.CheckNotCharacter('o', NULL);
1451 m.LoadCurrentCharacter(2, NULL);
1452 m.CheckNotCharacter('o', NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001453 m.WriteCurrentPositionToRegister(0, 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001454 m.WriteCurrentPositionToRegister(1, 3);
1455 m.WriteCurrentPositionToRegister(2, 1);
1456 m.WriteCurrentPositionToRegister(3, 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001457 m.AdvanceCurrentPosition(3);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001458 m.PushBacktrack(&backtrack);
Steve Blocka7e24c12009-10-30 11:49:00 +00001459 m.Succeed();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001460 m.Bind(&backtrack);
1461 m.ClearRegisters(2, 3);
Steve Blocka7e24c12009-10-30 11:49:00 +00001462 m.Backtrack();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001463 m.Bind(&fail);
Steve Blocka7e24c12009-10-30 11:49:00 +00001464 m.PopRegister(0);
1465 m.Fail();
1466
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001467 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch8b112d22011-06-08 16:22:53 +01001468 Factory* factory = isolate->factory();
1469 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001470
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001471 Handle<String> source = factory->NewStringFromStaticChars("^f(o)o");
Steve Blocka7e24c12009-10-30 11:49:00 +00001472 Handle<ByteArray> array = Handle<ByteArray>::cast(m.GetCode(source));
1473 int captures[5];
1474
1475 const uc16 str1[] = {'f', 'o', 'o', 'b', 'a', 'r'};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001476 Handle<String> f1_16 = factory->NewStringFromTwoByte(
1477 Vector<const uc16>(str1, 6)).ToHandleChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001478
Ben Murdoch8b112d22011-06-08 16:22:53 +01001479 CHECK(IrregexpInterpreter::Match(isolate, array, f1_16, captures, 0));
Steve Blocka7e24c12009-10-30 11:49:00 +00001480 CHECK_EQ(0, captures[0]);
1481 CHECK_EQ(3, captures[1]);
1482 CHECK_EQ(1, captures[2]);
1483 CHECK_EQ(2, captures[3]);
1484 CHECK_EQ(84, captures[4]);
1485
1486 const uc16 str2[] = {'b', 'a', 'r', 'f', 'o', 'o'};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001487 Handle<String> f2_16 = factory->NewStringFromTwoByte(
1488 Vector<const uc16>(str2, 6)).ToHandleChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001489
Ben Murdoch8b112d22011-06-08 16:22:53 +01001490 CHECK(!IrregexpInterpreter::Match(isolate, array, f2_16, captures, 0));
Steve Blocka7e24c12009-10-30 11:49:00 +00001491 CHECK_EQ(42, captures[0]);
1492}
1493
Steve Block6ded16b2010-05-10 14:33:55 +01001494#endif // V8_INTERPRETED_REGEXP
Steve Blocka7e24c12009-10-30 11:49:00 +00001495
1496
1497TEST(AddInverseToTable) {
1498 static const int kLimit = 1000;
1499 static const int kRangeCount = 16;
1500 for (int t = 0; t < 10; t++) {
Ben Murdochda12d292016-06-02 14:46:10 +01001501 Zone zone(CcTest::i_isolate()->allocator());
Steve Blocka7e24c12009-10-30 11:49:00 +00001502 ZoneList<CharacterRange>* ranges =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001503 new(&zone) ZoneList<CharacterRange>(kRangeCount, &zone);
Steve Blocka7e24c12009-10-30 11:49:00 +00001504 for (int i = 0; i < kRangeCount; i++) {
1505 int from = PseudoRandom(t + 87, i + 25) % kLimit;
1506 int to = from + (PseudoRandom(i + 87, t + 25) % (kLimit / 20));
1507 if (to > kLimit) to = kLimit;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001508 ranges->Add(CharacterRange::Range(from, to), &zone);
Steve Blocka7e24c12009-10-30 11:49:00 +00001509 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001510 DispatchTable table(&zone);
1511 DispatchTableConstructor cons(&table, false, &zone);
Steve Blocka7e24c12009-10-30 11:49:00 +00001512 cons.set_choice_index(0);
1513 cons.AddInverse(ranges);
1514 for (int i = 0; i < kLimit; i++) {
1515 bool is_on = false;
1516 for (int j = 0; !is_on && j < kRangeCount; j++)
1517 is_on = ranges->at(j).Contains(i);
1518 OutSet* set = table.Get(i);
1519 CHECK_EQ(is_on, set->Get(0) == false);
1520 }
1521 }
Ben Murdochda12d292016-06-02 14:46:10 +01001522 Zone zone(CcTest::i_isolate()->allocator());
Steve Blocka7e24c12009-10-30 11:49:00 +00001523 ZoneList<CharacterRange>* ranges =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001524 new(&zone) ZoneList<CharacterRange>(1, &zone);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001525 ranges->Add(CharacterRange::Range(0xFFF0, 0xFFFE), &zone);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001526 DispatchTable table(&zone);
1527 DispatchTableConstructor cons(&table, false, &zone);
Steve Blocka7e24c12009-10-30 11:49:00 +00001528 cons.set_choice_index(0);
1529 cons.AddInverse(ranges);
1530 CHECK(!table.Get(0xFFFE)->Get(0));
1531 CHECK(table.Get(0xFFFF)->Get(0));
1532}
1533
1534
1535static uc32 canonicalize(uc32 c) {
1536 unibrow::uchar canon[unibrow::Ecma262Canonicalize::kMaxWidth];
1537 int count = unibrow::Ecma262Canonicalize::Convert(c, '\0', canon, NULL);
1538 if (count == 0) {
1539 return c;
1540 } else {
1541 CHECK_EQ(1, count);
1542 return canon[0];
1543 }
1544}
1545
1546
1547TEST(LatinCanonicalize) {
1548 unibrow::Mapping<unibrow::Ecma262UnCanonicalize> un_canonicalize;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001549 for (unibrow::uchar lower = 'a'; lower <= 'z'; lower++) {
1550 unibrow::uchar upper = lower + ('A' - 'a');
Steve Blocka7e24c12009-10-30 11:49:00 +00001551 CHECK_EQ(canonicalize(lower), canonicalize(upper));
1552 unibrow::uchar uncanon[unibrow::Ecma262UnCanonicalize::kMaxWidth];
1553 int length = un_canonicalize.get(lower, '\0', uncanon);
1554 CHECK_EQ(2, length);
1555 CHECK_EQ(upper, uncanon[0]);
1556 CHECK_EQ(lower, uncanon[1]);
1557 }
1558 for (uc32 c = 128; c < (1 << 21); c++)
1559 CHECK_GE(canonicalize(c), 128);
1560 unibrow::Mapping<unibrow::ToUppercase> to_upper;
Ben Murdochbb769b22010-08-11 14:56:33 +01001561 // Canonicalization is only defined for the Basic Multilingual Plane.
1562 for (uc32 c = 0; c < (1 << 16); c++) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001563 unibrow::uchar upper[unibrow::ToUppercase::kMaxWidth];
1564 int length = to_upper.get(c, '\0', upper);
1565 if (length == 0) {
1566 length = 1;
1567 upper[0] = c;
1568 }
1569 uc32 u = upper[0];
1570 if (length > 1 || (c >= 128 && u < 128))
1571 u = c;
1572 CHECK_EQ(u, canonicalize(c));
1573 }
1574}
1575
1576
Ben Murdochbb769b22010-08-11 14:56:33 +01001577static uc32 CanonRangeEnd(uc32 c) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001578 unibrow::uchar canon[unibrow::CanonicalizationRange::kMaxWidth];
1579 int count = unibrow::CanonicalizationRange::Convert(c, '\0', canon, NULL);
1580 if (count == 0) {
1581 return c;
1582 } else {
1583 CHECK_EQ(1, count);
1584 return canon[0];
1585 }
1586}
1587
1588
1589TEST(RangeCanonicalization) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001590 // Check that we arrive at the same result when using the basic
1591 // range canonicalization primitives as when using immediate
1592 // canonicalization.
1593 unibrow::Mapping<unibrow::Ecma262UnCanonicalize> un_canonicalize;
Ben Murdochbb769b22010-08-11 14:56:33 +01001594 int block_start = 0;
1595 while (block_start <= 0xFFFF) {
1596 uc32 block_end = CanonRangeEnd(block_start);
1597 unsigned block_length = block_end - block_start + 1;
1598 if (block_length > 1) {
1599 unibrow::uchar first[unibrow::Ecma262UnCanonicalize::kMaxWidth];
1600 int first_length = un_canonicalize.get(block_start, '\0', first);
1601 for (unsigned i = 1; i < block_length; i++) {
1602 unibrow::uchar succ[unibrow::Ecma262UnCanonicalize::kMaxWidth];
1603 int succ_length = un_canonicalize.get(block_start + i, '\0', succ);
1604 CHECK_EQ(first_length, succ_length);
1605 for (int j = 0; j < succ_length; j++) {
1606 int calc = first[j] + i;
1607 int found = succ[j];
1608 CHECK_EQ(calc, found);
1609 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001610 }
1611 }
Ben Murdochbb769b22010-08-11 14:56:33 +01001612 block_start = block_start + block_length;
Steve Blocka7e24c12009-10-30 11:49:00 +00001613 }
1614}
1615
1616
1617TEST(UncanonicalizeEquivalence) {
1618 unibrow::Mapping<unibrow::Ecma262UnCanonicalize> un_canonicalize;
1619 unibrow::uchar chars[unibrow::Ecma262UnCanonicalize::kMaxWidth];
1620 for (int i = 0; i < (1 << 16); i++) {
1621 int length = un_canonicalize.get(i, '\0', chars);
1622 for (int j = 0; j < length; j++) {
1623 unibrow::uchar chars2[unibrow::Ecma262UnCanonicalize::kMaxWidth];
1624 int length2 = un_canonicalize.get(chars[j], '\0', chars2);
1625 CHECK_EQ(length, length2);
1626 for (int k = 0; k < length; k++)
1627 CHECK_EQ(static_cast<int>(chars[k]), static_cast<int>(chars2[k]));
1628 }
1629 }
1630}
1631
1632
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001633static void TestRangeCaseIndependence(Isolate* isolate, CharacterRange input,
Steve Blocka7e24c12009-10-30 11:49:00 +00001634 Vector<CharacterRange> expected) {
Ben Murdochda12d292016-06-02 14:46:10 +01001635 Zone zone(CcTest::i_isolate()->allocator());
Steve Blocka7e24c12009-10-30 11:49:00 +00001636 int count = expected.length();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001637 ZoneList<CharacterRange>* list =
1638 new(&zone) ZoneList<CharacterRange>(count, &zone);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001639 list->Add(input, &zone);
1640 CharacterRange::AddCaseEquivalents(isolate, &zone, list, false);
1641 list->Remove(0); // Remove the input before checking results.
Steve Blocka7e24c12009-10-30 11:49:00 +00001642 CHECK_EQ(count, list->length());
1643 for (int i = 0; i < list->length(); i++) {
1644 CHECK_EQ(expected[i].from(), list->at(i).from());
1645 CHECK_EQ(expected[i].to(), list->at(i).to());
1646 }
1647}
1648
1649
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001650static void TestSimpleRangeCaseIndependence(Isolate* isolate,
1651 CharacterRange input,
Steve Blocka7e24c12009-10-30 11:49:00 +00001652 CharacterRange expected) {
1653 EmbeddedVector<CharacterRange, 1> vector;
1654 vector[0] = expected;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001655 TestRangeCaseIndependence(isolate, input, vector);
Steve Blocka7e24c12009-10-30 11:49:00 +00001656}
1657
1658
1659TEST(CharacterRangeCaseIndependence) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001660 Isolate* isolate = CcTest::i_isolate();
1661 TestSimpleRangeCaseIndependence(isolate, CharacterRange::Singleton('a'),
Steve Blocka7e24c12009-10-30 11:49:00 +00001662 CharacterRange::Singleton('A'));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001663 TestSimpleRangeCaseIndependence(isolate, CharacterRange::Singleton('z'),
Steve Blocka7e24c12009-10-30 11:49:00 +00001664 CharacterRange::Singleton('Z'));
Ben Murdoch097c5b22016-05-18 11:27:45 +01001665 TestSimpleRangeCaseIndependence(isolate, CharacterRange::Range('a', 'z'),
1666 CharacterRange::Range('A', 'Z'));
1667 TestSimpleRangeCaseIndependence(isolate, CharacterRange::Range('c', 'f'),
1668 CharacterRange::Range('C', 'F'));
1669 TestSimpleRangeCaseIndependence(isolate, CharacterRange::Range('a', 'b'),
1670 CharacterRange::Range('A', 'B'));
1671 TestSimpleRangeCaseIndependence(isolate, CharacterRange::Range('y', 'z'),
1672 CharacterRange::Range('Y', 'Z'));
1673 TestSimpleRangeCaseIndependence(isolate,
1674 CharacterRange::Range('a' - 1, 'z' + 1),
1675 CharacterRange::Range('A', 'Z'));
1676 TestSimpleRangeCaseIndependence(isolate, CharacterRange::Range('A', 'Z'),
1677 CharacterRange::Range('a', 'z'));
1678 TestSimpleRangeCaseIndependence(isolate, CharacterRange::Range('C', 'F'),
1679 CharacterRange::Range('c', 'f'));
1680 TestSimpleRangeCaseIndependence(isolate,
1681 CharacterRange::Range('A' - 1, 'Z' + 1),
1682 CharacterRange::Range('a', 'z'));
Steve Blocka7e24c12009-10-30 11:49:00 +00001683 // Here we need to add [l-z] to complete the case independence of
1684 // [A-Za-z] but we expect [a-z] to be added since we always add a
1685 // whole block at a time.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001686 TestSimpleRangeCaseIndependence(isolate, CharacterRange::Range('A', 'k'),
1687 CharacterRange::Range('a', 'z'));
Steve Blocka7e24c12009-10-30 11:49:00 +00001688}
1689
1690
Ben Murdoch097c5b22016-05-18 11:27:45 +01001691static bool InClass(uc32 c, ZoneList<CharacterRange>* ranges) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001692 if (ranges == NULL)
1693 return false;
1694 for (int i = 0; i < ranges->length(); i++) {
1695 CharacterRange range = ranges->at(i);
1696 if (range.from() <= c && c <= range.to())
1697 return true;
1698 }
1699 return false;
1700}
1701
1702
Ben Murdoch097c5b22016-05-18 11:27:45 +01001703TEST(UnicodeRangeSplitter) {
Ben Murdochda12d292016-06-02 14:46:10 +01001704 Zone zone(CcTest::i_isolate()->allocator());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001705 ZoneList<CharacterRange>* base =
1706 new(&zone) ZoneList<CharacterRange>(1, &zone);
1707 base->Add(CharacterRange::Everything(), &zone);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001708 UnicodeRangeSplitter splitter(&zone, base);
1709 // BMP
1710 for (uc32 c = 0; c < 0xd800; 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 // Lead surrogates
1717 for (uc32 c = 0xd800; c < 0xdbff; 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 // Trail surrogates
1724 for (uc32 c = 0xdc00; c < 0xdfff; 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 // BMP
1731 for (uc32 c = 0xe000; c < 0xffff; 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()));
1736 }
1737 // Non-BMP
1738 for (uc32 c = 0x10000; c < 0x10ffff; c++) {
1739 CHECK(!InClass(c, splitter.bmp()));
1740 CHECK(!InClass(c, splitter.lead_surrogates()));
1741 CHECK(!InClass(c, splitter.trail_surrogates()));
1742 CHECK(InClass(c, splitter.non_bmp()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001743 }
1744}
1745
1746
Leon Clarkee46be812010-01-19 14:06:41 +00001747TEST(CanonicalizeCharacterSets) {
Ben Murdochda12d292016-06-02 14:46:10 +01001748 Zone zone(CcTest::i_isolate()->allocator());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001749 ZoneList<CharacterRange>* list =
1750 new(&zone) ZoneList<CharacterRange>(4, &zone);
Leon Clarkee46be812010-01-19 14:06:41 +00001751 CharacterSet set(list);
1752
Ben Murdoch097c5b22016-05-18 11:27:45 +01001753 list->Add(CharacterRange::Range(10, 20), &zone);
1754 list->Add(CharacterRange::Range(30, 40), &zone);
1755 list->Add(CharacterRange::Range(50, 60), &zone);
Leon Clarkee46be812010-01-19 14:06:41 +00001756 set.Canonicalize();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001757 CHECK_EQ(3, list->length());
1758 CHECK_EQ(10, list->at(0).from());
1759 CHECK_EQ(20, list->at(0).to());
1760 CHECK_EQ(30, list->at(1).from());
1761 CHECK_EQ(40, list->at(1).to());
1762 CHECK_EQ(50, list->at(2).from());
1763 CHECK_EQ(60, list->at(2).to());
Leon Clarkee46be812010-01-19 14:06:41 +00001764
1765 list->Rewind(0);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001766 list->Add(CharacterRange::Range(10, 20), &zone);
1767 list->Add(CharacterRange::Range(50, 60), &zone);
1768 list->Add(CharacterRange::Range(30, 40), &zone);
Leon Clarkee46be812010-01-19 14:06:41 +00001769 set.Canonicalize();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001770 CHECK_EQ(3, list->length());
1771 CHECK_EQ(10, list->at(0).from());
1772 CHECK_EQ(20, list->at(0).to());
1773 CHECK_EQ(30, list->at(1).from());
1774 CHECK_EQ(40, list->at(1).to());
1775 CHECK_EQ(50, list->at(2).from());
1776 CHECK_EQ(60, list->at(2).to());
Leon Clarkee46be812010-01-19 14:06:41 +00001777
1778 list->Rewind(0);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001779 list->Add(CharacterRange::Range(30, 40), &zone);
1780 list->Add(CharacterRange::Range(10, 20), &zone);
1781 list->Add(CharacterRange::Range(25, 25), &zone);
1782 list->Add(CharacterRange::Range(100, 100), &zone);
1783 list->Add(CharacterRange::Range(1, 1), &zone);
Leon Clarkee46be812010-01-19 14:06:41 +00001784 set.Canonicalize();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001785 CHECK_EQ(5, list->length());
1786 CHECK_EQ(1, list->at(0).from());
1787 CHECK_EQ(1, list->at(0).to());
1788 CHECK_EQ(10, list->at(1).from());
1789 CHECK_EQ(20, list->at(1).to());
1790 CHECK_EQ(25, list->at(2).from());
1791 CHECK_EQ(25, list->at(2).to());
1792 CHECK_EQ(30, list->at(3).from());
1793 CHECK_EQ(40, list->at(3).to());
1794 CHECK_EQ(100, list->at(4).from());
1795 CHECK_EQ(100, list->at(4).to());
Leon Clarkee46be812010-01-19 14:06:41 +00001796
1797 list->Rewind(0);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001798 list->Add(CharacterRange::Range(10, 19), &zone);
1799 list->Add(CharacterRange::Range(21, 30), &zone);
1800 list->Add(CharacterRange::Range(20, 20), &zone);
Leon Clarkee46be812010-01-19 14:06:41 +00001801 set.Canonicalize();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001802 CHECK_EQ(1, list->length());
1803 CHECK_EQ(10, list->at(0).from());
1804 CHECK_EQ(30, list->at(0).to());
Leon Clarkee46be812010-01-19 14:06:41 +00001805}
1806
Leon Clarked91b9f72010-01-27 17:25:45 +00001807
1808TEST(CharacterRangeMerge) {
Ben Murdochda12d292016-06-02 14:46:10 +01001809 Zone zone(CcTest::i_isolate()->allocator());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001810 ZoneList<CharacterRange> l1(4, &zone);
1811 ZoneList<CharacterRange> l2(4, &zone);
Leon Clarked91b9f72010-01-27 17:25:45 +00001812 // Create all combinations of intersections of ranges, both singletons and
1813 // longer.
1814
1815 int offset = 0;
1816
1817 // The five kinds of singleton intersections:
1818 // X
1819 // Y - outside before
1820 // Y - outside touching start
1821 // Y - overlap
1822 // Y - outside touching end
1823 // Y - outside after
1824
1825 for (int i = 0; i < 5; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001826 l1.Add(CharacterRange::Singleton(offset + 2), &zone);
1827 l2.Add(CharacterRange::Singleton(offset + i), &zone);
Leon Clarked91b9f72010-01-27 17:25:45 +00001828 offset += 6;
1829 }
1830
1831 // The seven kinds of singleton/non-singleton intersections:
1832 // XXX
1833 // Y - outside before
1834 // Y - outside touching start
1835 // Y - inside touching start
1836 // Y - entirely inside
1837 // Y - inside touching end
1838 // Y - outside touching end
1839 // Y - disjoint after
1840
1841 for (int i = 0; i < 7; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001842 l1.Add(CharacterRange::Range(offset + 2, offset + 4), &zone);
1843 l2.Add(CharacterRange::Singleton(offset + i), &zone);
Leon Clarked91b9f72010-01-27 17:25:45 +00001844 offset += 8;
1845 }
1846
1847 // The eleven kinds of non-singleton intersections:
1848 //
1849 // XXXXXXXX
1850 // YYYY - outside before.
1851 // YYYY - outside touching start.
1852 // YYYY - overlapping start
1853 // YYYY - inside touching start
1854 // YYYY - entirely inside
1855 // YYYY - inside touching end
1856 // YYYY - overlapping end
1857 // YYYY - outside touching end
1858 // YYYY - outside after
1859 // YYYYYYYY - identical
1860 // YYYYYYYYYYYY - containing entirely.
1861
1862 for (int i = 0; i < 9; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001863 l1.Add(CharacterRange::Range(offset + 6, offset + 15), &zone); // Length 8.
1864 l2.Add(CharacterRange::Range(offset + 2 * i, offset + 2 * i + 3), &zone);
Leon Clarked91b9f72010-01-27 17:25:45 +00001865 offset += 22;
1866 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001867 l1.Add(CharacterRange::Range(offset + 6, offset + 15), &zone);
1868 l2.Add(CharacterRange::Range(offset + 6, offset + 15), &zone);
Leon Clarked91b9f72010-01-27 17:25:45 +00001869 offset += 22;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001870 l1.Add(CharacterRange::Range(offset + 6, offset + 15), &zone);
1871 l2.Add(CharacterRange::Range(offset + 4, offset + 17), &zone);
Leon Clarked91b9f72010-01-27 17:25:45 +00001872 offset += 22;
1873
1874 // Different kinds of multi-range overlap:
1875 // XXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXX
1876 // YYYY Y YYYY Y YYYY Y YYYY Y YYYY Y YYYY Y
1877
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001878 l1.Add(CharacterRange::Range(offset, offset + 21), &zone);
1879 l1.Add(CharacterRange::Range(offset + 31, offset + 52), &zone);
Leon Clarked91b9f72010-01-27 17:25:45 +00001880 for (int i = 0; i < 6; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001881 l2.Add(CharacterRange::Range(offset + 2, offset + 5), &zone);
1882 l2.Add(CharacterRange::Singleton(offset + 8), &zone);
Leon Clarked91b9f72010-01-27 17:25:45 +00001883 offset += 9;
1884 }
1885
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001886 CHECK(CharacterRange::IsCanonical(&l1));
1887 CHECK(CharacterRange::IsCanonical(&l2));
Leon Clarked91b9f72010-01-27 17:25:45 +00001888
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001889 ZoneList<CharacterRange> first_only(4, &zone);
1890 ZoneList<CharacterRange> second_only(4, &zone);
1891 ZoneList<CharacterRange> both(4, &zone);
Leon Clarked91b9f72010-01-27 17:25:45 +00001892}
Leon Clarkee46be812010-01-19 14:06:41 +00001893
1894
Steve Blocka7e24c12009-10-30 11:49:00 +00001895TEST(Graph) {
Leon Clarkee46be812010-01-19 14:06:41 +00001896 Execute("\\b\\w+\\b", false, true, true);
Steve Blocka7e24c12009-10-30 11:49:00 +00001897}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001898
1899
1900namespace {
1901
1902int* global_use_counts = NULL;
1903
1904void MockUseCounterCallback(v8::Isolate* isolate,
1905 v8::Isolate::UseCounterFeature feature) {
1906 ++global_use_counts[feature];
1907}
1908}
1909
1910
1911// Test that ES2015 RegExp compatibility fixes are in place, that they
1912// are not overly broad, and the appropriate UseCounters are incremented
1913TEST(UseCountRegExp) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001914 v8::Isolate* isolate = CcTest::isolate();
1915 v8::HandleScope scope(isolate);
1916 LocalContext env;
1917 int use_counts[v8::Isolate::kUseCounterFeatureCount] = {};
1918 global_use_counts = use_counts;
1919 CcTest::isolate()->SetUseCounterCallback(MockUseCounterCallback);
1920
1921 // Compat fix: RegExp.prototype.sticky == undefined; UseCounter tracks it
1922 v8::Local<v8::Value> resultSticky = CompileRun("RegExp.prototype.sticky");
1923 CHECK_EQ(1, use_counts[v8::Isolate::kRegExpPrototypeStickyGetter]);
1924 CHECK_EQ(0, use_counts[v8::Isolate::kRegExpPrototypeToString]);
1925 CHECK(resultSticky->IsUndefined());
1926
1927 // re.sticky has approriate value and doesn't touch UseCounter
1928 v8::Local<v8::Value> resultReSticky = CompileRun("/a/.sticky");
1929 CHECK_EQ(1, use_counts[v8::Isolate::kRegExpPrototypeStickyGetter]);
1930 CHECK_EQ(0, use_counts[v8::Isolate::kRegExpPrototypeToString]);
1931 CHECK(resultReSticky->IsFalse());
1932
1933 // When the getter is caleld on another object, throw an exception
1934 // and don't increment the UseCounter
1935 v8::Local<v8::Value> resultStickyError = CompileRun(
1936 "var exception;"
1937 "try { "
1938 " Object.getOwnPropertyDescriptor(RegExp.prototype, 'sticky')"
1939 " .get.call(null);"
1940 "} catch (e) {"
1941 " exception = e;"
1942 "}"
1943 "exception");
1944 CHECK_EQ(1, use_counts[v8::Isolate::kRegExpPrototypeStickyGetter]);
1945 CHECK_EQ(0, use_counts[v8::Isolate::kRegExpPrototypeToString]);
1946 CHECK(resultStickyError->IsObject());
1947
1948 // RegExp.prototype.toString() returns '/(?:)/' as a compatibility fix;
1949 // a UseCounter is incremented to track it.
1950 v8::Local<v8::Value> resultToString =
1951 CompileRun("RegExp.prototype.toString().length");
Ben Murdochda12d292016-06-02 14:46:10 +01001952 CHECK_EQ(2, use_counts[v8::Isolate::kRegExpPrototypeStickyGetter]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001953 CHECK_EQ(1, use_counts[v8::Isolate::kRegExpPrototypeToString]);
1954 CHECK(resultToString->IsInt32());
1955 CHECK_EQ(6,
1956 resultToString->Int32Value(isolate->GetCurrentContext()).FromJust());
1957
1958 // .toString() works on normal RegExps
1959 v8::Local<v8::Value> resultReToString = CompileRun("/a/.toString().length");
Ben Murdochda12d292016-06-02 14:46:10 +01001960 CHECK_EQ(2, use_counts[v8::Isolate::kRegExpPrototypeStickyGetter]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001961 CHECK_EQ(1, use_counts[v8::Isolate::kRegExpPrototypeToString]);
1962 CHECK(resultReToString->IsInt32());
1963 CHECK_EQ(
1964 3, resultReToString->Int32Value(isolate->GetCurrentContext()).FromJust());
1965
1966 // .toString() throws on non-RegExps that aren't RegExp.prototype
1967 v8::Local<v8::Value> resultToStringError = CompileRun(
1968 "var exception;"
1969 "try { RegExp.prototype.toString.call(null) }"
1970 "catch (e) { exception = e; }"
1971 "exception");
Ben Murdochda12d292016-06-02 14:46:10 +01001972 CHECK_EQ(2, use_counts[v8::Isolate::kRegExpPrototypeStickyGetter]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001973 CHECK_EQ(1, use_counts[v8::Isolate::kRegExpPrototypeToString]);
1974 CHECK(resultToStringError->IsObject());
1975}
Ben Murdoch097c5b22016-05-18 11:27:45 +01001976
1977class UncachedExternalString
1978 : public v8::String::ExternalOneByteStringResource {
1979 public:
1980 const char* data() const override { return "abcdefghijklmnopqrstuvwxyz"; }
1981 size_t length() const override { return 26; }
1982 bool IsCompressible() const override { return true; }
1983};
1984
1985TEST(UncachedExternalString) {
1986 v8::Isolate* isolate = CcTest::isolate();
1987 v8::HandleScope scope(isolate);
1988 LocalContext env;
1989 v8::Local<v8::String> external =
1990 v8::String::NewExternalOneByte(isolate, new UncachedExternalString())
1991 .ToLocalChecked();
1992 CHECK(v8::Utils::OpenHandle(*external)->map() ==
1993 CcTest::i_isolate()->heap()->short_external_one_byte_string_map());
1994 v8::Local<v8::Object> global = env->Global();
1995 global->Set(env.local(), v8_str("external"), external).FromJust();
1996 CompileRun("var re = /y(.)/; re.test('ab');");
1997 ExpectString("external.substring(1).match(re)[1]", "z");
1998}