• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/regexp/regexp-macro-assembler.h"
6 
7 #include "src/codegen/assembler.h"
8 #include "src/codegen/label.h"
9 #include "src/execution/isolate-inl.h"
10 #include "src/execution/pointer-authentication.h"
11 #include "src/execution/simulator.h"
12 #include "src/regexp/regexp-stack.h"
13 #include "src/regexp/special-case.h"
14 #include "src/strings/unicode-inl.h"
15 
16 #ifdef V8_INTL_SUPPORT
17 #include "unicode/uchar.h"
18 #include "unicode/unistr.h"
19 #endif  // V8_INTL_SUPPORT
20 
21 namespace v8 {
22 namespace internal {
23 
RegExpMacroAssembler(Isolate * isolate,Zone * zone)24 RegExpMacroAssembler::RegExpMacroAssembler(Isolate* isolate, Zone* zone)
25     : slow_safe_compiler_(false),
26       backtrack_limit_(JSRegExp::kNoBacktrackLimit),
27       global_mode_(NOT_GLOBAL),
28       isolate_(isolate),
29       zone_(zone) {}
30 
has_backtrack_limit() const31 bool RegExpMacroAssembler::has_backtrack_limit() const {
32   return backtrack_limit_ != JSRegExp::kNoBacktrackLimit;
33 }
34 
35 // static
CaseInsensitiveCompareNonUnicode(Address byte_offset1,Address byte_offset2,size_t byte_length,Isolate * isolate)36 int RegExpMacroAssembler::CaseInsensitiveCompareNonUnicode(Address byte_offset1,
37                                                            Address byte_offset2,
38                                                            size_t byte_length,
39                                                            Isolate* isolate) {
40 #ifdef V8_INTL_SUPPORT
41   // This function is not allowed to cause a garbage collection.
42   // A GC might move the calling generated code and invalidate the
43   // return address on the stack.
44   DisallowGarbageCollection no_gc;
45   DCHECK_EQ(0, byte_length % 2);
46   size_t length = byte_length / 2;
47   base::uc16* substring1 = reinterpret_cast<base::uc16*>(byte_offset1);
48   base::uc16* substring2 = reinterpret_cast<base::uc16*>(byte_offset2);
49 
50   for (size_t i = 0; i < length; i++) {
51     UChar32 c1 = RegExpCaseFolding::Canonicalize(substring1[i]);
52     UChar32 c2 = RegExpCaseFolding::Canonicalize(substring2[i]);
53     if (c1 != c2) {
54       return 0;
55     }
56   }
57   return 1;
58 #else
59   return CaseInsensitiveCompareUnicode(byte_offset1, byte_offset2, byte_length,
60                                        isolate);
61 #endif
62 }
63 
64 // static
CaseInsensitiveCompareUnicode(Address byte_offset1,Address byte_offset2,size_t byte_length,Isolate * isolate)65 int RegExpMacroAssembler::CaseInsensitiveCompareUnicode(Address byte_offset1,
66                                                         Address byte_offset2,
67                                                         size_t byte_length,
68                                                         Isolate* isolate) {
69   // This function is not allowed to cause a garbage collection.
70   // A GC might move the calling generated code and invalidate the
71   // return address on the stack.
72   DisallowGarbageCollection no_gc;
73   DCHECK_EQ(0, byte_length % 2);
74 
75 #ifdef V8_INTL_SUPPORT
76   int32_t length = static_cast<int32_t>(byte_length >> 1);
77   icu::UnicodeString uni_str_1(reinterpret_cast<const char16_t*>(byte_offset1),
78                                length);
79   return uni_str_1.caseCompare(reinterpret_cast<const char16_t*>(byte_offset2),
80                                length, U_FOLD_CASE_DEFAULT) == 0;
81 #else
82   base::uc16* substring1 = reinterpret_cast<base::uc16*>(byte_offset1);
83   base::uc16* substring2 = reinterpret_cast<base::uc16*>(byte_offset2);
84   size_t length = byte_length >> 1;
85   DCHECK_NOT_NULL(isolate);
86   unibrow::Mapping<unibrow::Ecma262Canonicalize>* canonicalize =
87       isolate->regexp_macro_assembler_canonicalize();
88   for (size_t i = 0; i < length; i++) {
89     unibrow::uchar c1 = substring1[i];
90     unibrow::uchar c2 = substring2[i];
91     if (c1 != c2) {
92       unibrow::uchar s1[1] = {c1};
93       canonicalize->get(c1, '\0', s1);
94       if (s1[0] != c2) {
95         unibrow::uchar s2[1] = {c2};
96         canonicalize->get(c2, '\0', s2);
97         if (s1[0] != s2[0]) {
98           return 0;
99         }
100       }
101     }
102   }
103   return 1;
104 #endif  // V8_INTL_SUPPORT
105 }
106 
107 namespace {
108 
Hash(const ZoneList<CharacterRange> * ranges)109 uint32_t Hash(const ZoneList<CharacterRange>* ranges) {
110   size_t seed = 0;
111   for (int i = 0; i < ranges->length(); i++) {
112     const CharacterRange& r = ranges->at(i);
113     seed = base::hash_combine(seed, r.from(), r.to());
114   }
115   return static_cast<uint32_t>(seed);
116 }
117 
MaskEndOfRangeMarker(base::uc32 c)118 constexpr base::uc32 MaskEndOfRangeMarker(base::uc32 c) {
119   // CharacterRanges may use 0x10ffff as the end-of-range marker irrespective
120   // of whether the regexp IsUnicode or not; translate the marker value here.
121   DCHECK_IMPLIES(c > kMaxUInt16, c == String::kMaxCodePoint);
122   return c & 0xffff;
123 }
124 
RangeArrayLengthFor(const ZoneList<CharacterRange> * ranges)125 int RangeArrayLengthFor(const ZoneList<CharacterRange>* ranges) {
126   const int ranges_length = ranges->length();
127   return MaskEndOfRangeMarker(ranges->at(ranges_length - 1).to()) == kMaxUInt16
128              ? ranges_length * 2 - 1
129              : ranges_length * 2;
130 }
131 
Equals(const ZoneList<CharacterRange> * lhs,const Handle<ByteArray> & rhs)132 bool Equals(const ZoneList<CharacterRange>* lhs, const Handle<ByteArray>& rhs) {
133   DCHECK_EQ(rhs->length() % kUInt16Size, 0);  // uc16 elements.
134   const int rhs_length = rhs->length() / kUInt16Size;
135   if (rhs_length != RangeArrayLengthFor(lhs)) return false;
136   for (int i = 0; i < lhs->length(); i++) {
137     const CharacterRange& r = lhs->at(i);
138     if (rhs->get_uint16(i * 2 + 0) != r.from()) return false;
139     if (i * 2 + 1 == rhs_length) break;
140     if (rhs->get_uint16(i * 2 + 1) != r.to() + 1) return false;
141   }
142   return true;
143 }
144 
MakeRangeArray(Isolate * isolate,const ZoneList<CharacterRange> * ranges)145 Handle<ByteArray> MakeRangeArray(Isolate* isolate,
146                                  const ZoneList<CharacterRange>* ranges) {
147   const int ranges_length = ranges->length();
148   const int byte_array_length = RangeArrayLengthFor(ranges);
149   const int size_in_bytes = byte_array_length * kUInt16Size;
150   Handle<ByteArray> range_array =
151       isolate->factory()->NewByteArray(size_in_bytes);
152   for (int i = 0; i < ranges_length; i++) {
153     const CharacterRange& r = ranges->at(i);
154     DCHECK_LE(r.from(), kMaxUInt16);
155     range_array->set_uint16(i * 2 + 0, r.from());
156     const base::uc32 to = MaskEndOfRangeMarker(r.to());
157     if (i == ranges_length - 1 && to == kMaxUInt16) {
158       DCHECK_EQ(byte_array_length, ranges_length * 2 - 1);
159       break;  // Avoid overflow by leaving the last range open-ended.
160     }
161     DCHECK_LT(to, kMaxUInt16);
162     range_array->set_uint16(i * 2 + 1, to + 1);  // Exclusive.
163   }
164   return range_array;
165 }
166 
167 }  // namespace
168 
GetOrAddRangeArray(const ZoneList<CharacterRange> * ranges)169 Handle<ByteArray> NativeRegExpMacroAssembler::GetOrAddRangeArray(
170     const ZoneList<CharacterRange>* ranges) {
171   const uint32_t hash = Hash(ranges);
172 
173   if (range_array_cache_.count(hash) != 0) {
174     Handle<ByteArray> range_array = range_array_cache_[hash];
175     if (Equals(ranges, range_array)) return range_array;
176   }
177 
178   Handle<ByteArray> range_array = MakeRangeArray(isolate(), ranges);
179   range_array_cache_[hash] = range_array;
180   return range_array;
181 }
182 
183 // static
IsCharacterInRangeArray(uint32_t current_char,Address raw_byte_array,Isolate * isolate)184 uint32_t RegExpMacroAssembler::IsCharacterInRangeArray(uint32_t current_char,
185                                                        Address raw_byte_array,
186                                                        Isolate* isolate) {
187   // Use uint32_t to avoid complexity around bool return types (which may be
188   // optimized to use only the least significant byte).
189   static constexpr uint32_t kTrue = 1;
190   static constexpr uint32_t kFalse = 0;
191 
192   ByteArray ranges = ByteArray::cast(Object(raw_byte_array));
193 
194   DCHECK_EQ(ranges.length() % kUInt16Size, 0);  // uc16 elements.
195   const int length = ranges.length() / kUInt16Size;
196   DCHECK_GE(length, 1);
197 
198   // Shortcut for fully out of range chars.
199   if (current_char < ranges.get_uint16(0)) return kFalse;
200   if (current_char >= ranges.get_uint16(length - 1)) {
201     // The last range may be open-ended.
202     return (length % 2) == 0 ? kFalse : kTrue;
203   }
204 
205   // Binary search for the matching range. `ranges` is encoded as
206   // [from0, to0, from1, to1, ..., fromN, toN], or
207   // [from0, to0, from1, to1, ..., fromN] (open-ended last interval).
208 
209   int mid, lower = 0, upper = length;
210   do {
211     mid = lower + (upper - lower) / 2;
212     const base::uc16 elem = ranges.get_uint16(mid);
213     if (current_char < elem) {
214       upper = mid;
215     } else if (current_char > elem) {
216       lower = mid + 1;
217     } else {
218       DCHECK_EQ(current_char, elem);
219       break;
220     }
221   } while (lower < upper);
222 
223   const bool current_char_ge_last_elem = current_char >= ranges.get_uint16(mid);
224   const int current_range_start_index =
225       current_char_ge_last_elem ? mid : mid - 1;
226 
227   // Ranges start at even indices and end at odd indices.
228   return (current_range_start_index % 2) == 0 ? kTrue : kFalse;
229 }
230 
CheckNotInSurrogatePair(int cp_offset,Label * on_failure)231 void RegExpMacroAssembler::CheckNotInSurrogatePair(int cp_offset,
232                                                    Label* on_failure) {
233   Label ok;
234   // Check that current character is not a trail surrogate.
235   LoadCurrentCharacter(cp_offset, &ok);
236   CheckCharacterNotInRange(kTrailSurrogateStart, kTrailSurrogateEnd, &ok);
237   // Check that previous character is not a lead surrogate.
238   LoadCurrentCharacter(cp_offset - 1, &ok);
239   CheckCharacterInRange(kLeadSurrogateStart, kLeadSurrogateEnd, on_failure);
240   Bind(&ok);
241 }
242 
CheckPosition(int cp_offset,Label * on_outside_input)243 void RegExpMacroAssembler::CheckPosition(int cp_offset,
244                                          Label* on_outside_input) {
245   LoadCurrentCharacter(cp_offset, on_outside_input, true);
246 }
247 
LoadCurrentCharacter(int cp_offset,Label * on_end_of_input,bool check_bounds,int characters,int eats_at_least)248 void RegExpMacroAssembler::LoadCurrentCharacter(int cp_offset,
249                                                 Label* on_end_of_input,
250                                                 bool check_bounds,
251                                                 int characters,
252                                                 int eats_at_least) {
253   // By default, eats_at_least = characters.
254   if (eats_at_least == kUseCharactersValue) {
255     eats_at_least = characters;
256   }
257 
258   LoadCurrentCharacterImpl(cp_offset, on_end_of_input, check_bounds, characters,
259                            eats_at_least);
260 }
261 
LoadCurrentCharacterImpl(int cp_offset,Label * on_end_of_input,bool check_bounds,int characters,int eats_at_least)262 void NativeRegExpMacroAssembler::LoadCurrentCharacterImpl(
263     int cp_offset, Label* on_end_of_input, bool check_bounds, int characters,
264     int eats_at_least) {
265   // It's possible to preload a small number of characters when each success
266   // path requires a large number of characters, but not the reverse.
267   DCHECK_GE(eats_at_least, characters);
268 
269   DCHECK(base::IsInRange(cp_offset, kMinCPOffset, kMaxCPOffset));
270   if (check_bounds) {
271     if (cp_offset >= 0) {
272       CheckPosition(cp_offset + eats_at_least - 1, on_end_of_input);
273     } else {
274       CheckPosition(cp_offset, on_end_of_input);
275     }
276   }
277   LoadCurrentCharacterUnchecked(cp_offset, characters);
278 }
279 
CanReadUnaligned() const280 bool NativeRegExpMacroAssembler::CanReadUnaligned() const {
281   return FLAG_enable_regexp_unaligned_accesses && !slow_safe();
282 }
283 
284 #ifndef COMPILING_IRREGEXP_FOR_EXTERNAL_EMBEDDER
285 
286 // This method may only be called after an interrupt.
287 // static
CheckStackGuardState(Isolate * isolate,int start_index,RegExp::CallOrigin call_origin,Address * return_address,Code re_code,Address * subject,const byte ** input_start,const byte ** input_end)288 int NativeRegExpMacroAssembler::CheckStackGuardState(
289     Isolate* isolate, int start_index, RegExp::CallOrigin call_origin,
290     Address* return_address, Code re_code, Address* subject,
291     const byte** input_start, const byte** input_end) {
292   DisallowGarbageCollection no_gc;
293   Address old_pc = PointerAuthentication::AuthenticatePC(return_address, 0);
294   DCHECK_LE(re_code.raw_instruction_start(), old_pc);
295   DCHECK_LE(old_pc, re_code.raw_instruction_end());
296 
297   StackLimitCheck check(isolate);
298   bool js_has_overflowed = check.JsHasOverflowed();
299 
300   if (call_origin == RegExp::CallOrigin::kFromJs) {
301     // Direct calls from JavaScript can be interrupted in two ways:
302     // 1. A real stack overflow, in which case we let the caller throw the
303     //    exception.
304     // 2. The stack guard was used to interrupt execution for another purpose,
305     //    forcing the call through the runtime system.
306 
307     // Bug(v8:9540) Investigate why this method is called from JS although no
308     // stackoverflow or interrupt is pending on ARM64. We return 0 in this case
309     // to continue execution normally.
310     if (js_has_overflowed) {
311       return EXCEPTION;
312     } else if (check.InterruptRequested()) {
313       return RETRY;
314     } else {
315       return 0;
316     }
317   }
318   DCHECK(call_origin == RegExp::CallOrigin::kFromRuntime);
319 
320   // Prepare for possible GC.
321   HandleScope handles(isolate);
322   Handle<Code> code_handle(re_code, isolate);
323   Handle<String> subject_handle(String::cast(Object(*subject)), isolate);
324   bool is_one_byte = String::IsOneByteRepresentationUnderneath(*subject_handle);
325   int return_value = 0;
326 
327   {
328     DisableGCMole no_gc_mole;
329     if (js_has_overflowed) {
330       AllowGarbageCollection yes_gc;
331       isolate->StackOverflow();
332       return_value = EXCEPTION;
333     } else if (check.InterruptRequested()) {
334       AllowGarbageCollection yes_gc;
335       Object result = isolate->stack_guard()->HandleInterrupts();
336       if (result.IsException(isolate)) return_value = EXCEPTION;
337     }
338 
339     if (*code_handle != re_code) {  // Return address no longer valid
340       // Overwrite the return address on the stack.
341       intptr_t delta = code_handle->address() - re_code.address();
342       Address new_pc = old_pc + delta;
343       // TODO(v8:10026): avoid replacing a signed pointer.
344       PointerAuthentication::ReplacePC(return_address, new_pc, 0);
345     }
346   }
347 
348   // If we continue, we need to update the subject string addresses.
349   if (return_value == 0) {
350     // String encoding might have changed.
351     if (String::IsOneByteRepresentationUnderneath(*subject_handle) !=
352         is_one_byte) {
353       // If we changed between an LATIN1 and an UC16 string, the specialized
354       // code cannot be used, and we need to restart regexp matching from
355       // scratch (including, potentially, compiling a new version of the code).
356       return_value = RETRY;
357     } else {
358       *subject = subject_handle->ptr();
359       intptr_t byte_length = *input_end - *input_start;
360       *input_start = subject_handle->AddressOfCharacterAt(start_index, no_gc);
361       *input_end = *input_start + byte_length;
362     }
363   }
364   return return_value;
365 }
366 
367 // Returns a {Result} sentinel, or the number of successful matches.
Match(Handle<JSRegExp> regexp,Handle<String> subject,int * offsets_vector,int offsets_vector_length,int previous_index,Isolate * isolate)368 int NativeRegExpMacroAssembler::Match(Handle<JSRegExp> regexp,
369                                       Handle<String> subject,
370                                       int* offsets_vector,
371                                       int offsets_vector_length,
372                                       int previous_index, Isolate* isolate) {
373   DCHECK(subject->IsFlat());
374   DCHECK_LE(0, previous_index);
375   DCHECK_LE(previous_index, subject->length());
376 
377   // No allocations before calling the regexp, but we can't use
378   // DisallowGarbageCollection, since regexps might be preempted, and another
379   // thread might do allocation anyway.
380 
381   String subject_ptr = *subject;
382   // Character offsets into string.
383   int start_offset = previous_index;
384   int char_length = subject_ptr.length() - start_offset;
385   int slice_offset = 0;
386 
387   // The string has been flattened, so if it is a cons string it contains the
388   // full string in the first part.
389   if (StringShape(subject_ptr).IsCons()) {
390     DCHECK_EQ(0, ConsString::cast(subject_ptr).second().length());
391     subject_ptr = ConsString::cast(subject_ptr).first();
392   } else if (StringShape(subject_ptr).IsSliced()) {
393     SlicedString slice = SlicedString::cast(subject_ptr);
394     subject_ptr = slice.parent();
395     slice_offset = slice.offset();
396   }
397   if (StringShape(subject_ptr).IsThin()) {
398     subject_ptr = ThinString::cast(subject_ptr).actual();
399   }
400   // Ensure that an underlying string has the same representation.
401   bool is_one_byte = subject_ptr.IsOneByteRepresentation();
402   DCHECK(subject_ptr.IsExternalString() || subject_ptr.IsSeqString());
403   // String is now either Sequential or External
404   int char_size_shift = is_one_byte ? 0 : 1;
405 
406   DisallowGarbageCollection no_gc;
407   const byte* input_start =
408       subject_ptr.AddressOfCharacterAt(start_offset + slice_offset, no_gc);
409   int byte_length = char_length << char_size_shift;
410   const byte* input_end = input_start + byte_length;
411   return Execute(*subject, start_offset, input_start, input_end, offsets_vector,
412                  offsets_vector_length, isolate, *regexp);
413 }
414 
415 // static
ExecuteForTesting(String input,int start_offset,const byte * input_start,const byte * input_end,int * output,int output_size,Isolate * isolate,JSRegExp regexp)416 int NativeRegExpMacroAssembler::ExecuteForTesting(
417     String input, int start_offset, const byte* input_start,
418     const byte* input_end, int* output, int output_size, Isolate* isolate,
419     JSRegExp regexp) {
420   return Execute(input, start_offset, input_start, input_end, output,
421                  output_size, isolate, regexp);
422 }
423 
424 // Returns a {Result} sentinel, or the number of successful matches.
425 // TODO(pthier): The JSRegExp object is passed to native irregexp code to match
426 // the signature of the interpreter. We should get rid of JS objects passed to
427 // internal methods.
Execute(String input,int start_offset,const byte * input_start,const byte * input_end,int * output,int output_size,Isolate * isolate,JSRegExp regexp)428 int NativeRegExpMacroAssembler::Execute(
429     String input,  // This needs to be the unpacked (sliced, cons) string.
430     int start_offset, const byte* input_start, const byte* input_end,
431     int* output, int output_size, Isolate* isolate, JSRegExp regexp) {
432   RegExpStackScope stack_scope(isolate);
433 
434   bool is_one_byte = String::IsOneByteRepresentationUnderneath(input);
435   Code code = FromCodeT(CodeT::cast(regexp.code(is_one_byte)));
436   RegExp::CallOrigin call_origin = RegExp::CallOrigin::kFromRuntime;
437 
438   using RegexpMatcherSig =
439       // NOLINTNEXTLINE(readability/casting)
440       int(Address input_string, int start_offset, const byte* input_start,
441           const byte* input_end, int* output, int output_size, int call_origin,
442           Isolate* isolate, Address regexp);
443 
444   auto fn = GeneratedCode<RegexpMatcherSig>::FromCode(code);
445   int result = fn.Call(input.ptr(), start_offset, input_start, input_end,
446                        output, output_size, call_origin, isolate, regexp.ptr());
447   DCHECK_GE(result, SMALLEST_REGEXP_RESULT);
448 
449   if (result == EXCEPTION && !isolate->has_pending_exception()) {
450     // We detected a stack overflow (on the backtrack stack) in RegExp code,
451     // but haven't created the exception yet. Additionally, we allow heap
452     // allocation because even though it invalidates {input_start} and
453     // {input_end}, we are about to return anyway.
454     AllowGarbageCollection allow_allocation;
455     isolate->StackOverflow();
456   }
457   return result;
458 }
459 
460 #endif  // !COMPILING_IRREGEXP_FOR_EXTERNAL_EMBEDDER
461 
462 // clang-format off
463 const byte NativeRegExpMacroAssembler::word_character_map[] = {
464     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
465     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
466     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
467     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
468 
469     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
470     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
471     0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu,  // '0' - '7'
472     0xFFu, 0xFFu, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,  // '8' - '9'
473 
474     0x00u, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu,  // 'A' - 'G'
475     0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu,  // 'H' - 'O'
476     0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu,  // 'P' - 'W'
477     0xFFu, 0xFFu, 0xFFu, 0x00u, 0x00u, 0x00u, 0x00u, 0xFFu,  // 'X' - 'Z', '_'
478 
479     0x00u, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu,  // 'a' - 'g'
480     0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu,  // 'h' - 'o'
481     0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu, 0xFFu,  // 'p' - 'w'
482     0xFFu, 0xFFu, 0xFFu, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,  // 'x' - 'z'
483     // Latin-1 range
484     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
485     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
486     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
487     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
488 
489     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
490     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
491     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
492     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
493 
494     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
495     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
496     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
497     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
498 
499     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
500     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
501     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
502     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
503 };
504 // clang-format on
505 
506 // static
GrowStack(Isolate * isolate)507 Address NativeRegExpMacroAssembler::GrowStack(Isolate* isolate) {
508   DisallowGarbageCollection no_gc;
509 
510   RegExpStack* regexp_stack = isolate->regexp_stack();
511   const size_t old_size = regexp_stack->memory_size();
512 
513 #ifdef DEBUG
514   const Address old_stack_top = regexp_stack->memory_top();
515   const Address old_stack_pointer = regexp_stack->stack_pointer();
516   CHECK_LE(old_stack_pointer, old_stack_top);
517   CHECK_LE(static_cast<size_t>(old_stack_top - old_stack_pointer), old_size);
518 #endif  // DEBUG
519 
520   Address new_stack_base = regexp_stack->EnsureCapacity(old_size * 2);
521   if (new_stack_base == kNullAddress) return kNullAddress;
522 
523   return regexp_stack->stack_pointer();
524 }
525 
526 }  // namespace internal
527 }  // namespace v8
528