1 // Copyright 2015 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/init/v8.h"
6 
7 #if V8_TARGET_ARCH_S390
8 
9 #include "src/codegen/macro-assembler.h"
10 #include "src/codegen/s390/assembler-s390-inl.h"
11 #include "src/heap/factory.h"
12 #include "src/logging/log.h"
13 #include "src/objects/code-inl.h"
14 #include "src/regexp/regexp-stack.h"
15 #include "src/regexp/s390/regexp-macro-assembler-s390.h"
16 #include "src/snapshot/embedded/embedded-data-inl.h"
17 
18 namespace v8 {
19 namespace internal {
20 
21 /*
22  * This assembler uses the following register assignment convention
23  * - r6: Temporarily stores the index of capture start after a matching pass
24  *        for a global regexp.
25  * - r7: Pointer to current Code object including heap object tag.
26  * - r8: Current position in input, as negative offset from end of string.
27  *        Please notice that this is the byte offset, not the character offset!
28  * - r9: Currently loaded character. Must be loaded using
29  *        LoadCurrentCharacter before using any of the dispatch methods.
30  * - r13: Points to tip of backtrack stack
31  * - r10: End of input (points to byte after last character in input).
32  * - r11: Frame pointer. Used to access arguments, local variables and
33  *         RegExp registers.
34  * - r12: IP register, used by assembler. Very volatile.
35  * - r15/sp : Points to tip of C stack.
36  *
37  * The remaining registers are free for computations.
38  * Each call to a public method should retain this convention.
39  *
40  * The stack will have the following structure
41  *  - fp[112]  Address regexp     (address of the JSRegExp object; unused in
42  *                                native code, passed to match signature of
43  *                                the interpreter)
44  *  - fp[108] Isolate* isolate   (address of the current isolate)
45  *  - fp[104] direct_call        (if 1, direct call from JavaScript code,
46  *                                if 0, call through the runtime system).
47  *  - fp[100] stack_area_base    (high end of the memory area to use as
48  *                                backtracking stack).
49  *  - fp[96]  capture array size (may fit multiple sets of matches)
50  *  - fp[0..96] zLinux ABI register saving area
51  *  --- sp when called ---
52  *  --- frame pointer ----
53  *  - fp[-4]  direct_call        (if 1, direct call from JavaScript code,
54  *                                if 0, call through the runtime system).
55  *  - fp[-8]  stack_area_base    (high end of the memory area to use as
56  *                                backtracking stack).
57  *  - fp[-12] capture array size (may fit multiple sets of matches)
58  *  - fp[-16] int* capture_array (int[num_saved_registers_], for output).
59  *  - fp[-20] end of input       (address of end of string).
60  *  - fp[-24] start of input     (address of first character in string).
61  *  - fp[-28] start index        (character index of start).
62  *  - fp[-32] void* input_string (location of a handle containing the string).
63  *  - fp[-36] success counter    (only for global regexps to count matches).
64  *  - fp[-40] Offset of location before start of input (effectively character
65  *            string start - 1). Used to initialize capture registers to a
66  *            non-position.
67  *  - fp[-44] At start (if 1, we are starting at the start of the
68  *    string, otherwise 0)
69  *  - fp[-48] register 0         (Only positions must be stored in the first
70  *  -         register 1          num_saved_registers_ registers)
71  *  -         ...
72  *  -         register num_registers-1
73  *  --- sp ---
74  *
75  * The first num_saved_registers_ registers are initialized to point to
76  * "character -1" in the string (i.e., char_size() bytes before the first
77  * character of the string). The remaining registers start out as garbage.
78  *
79  * The data up to the return address must be placed there by the calling
80  * code and the remaining arguments are passed in registers, e.g. by calling the
81  * code entry as cast to a function with the signature:
82  * int (*match)(String input_string,
83  *              int start_index,
84  *              Address start,
85  *              Address end,
86  *              int* capture_output_array,
87  *              int num_capture_registers,
88  *              byte* stack_area_base,
89  *              bool direct_call = false,
90  *              Isolate* isolate,
91  *              Address regexp);
92  * The call is performed by NativeRegExpMacroAssembler::Execute()
93  * (in regexp-macro-assembler.cc) via the GeneratedCode wrapper.
94  */
95 
96 #define __ ACCESS_MASM(masm_)
97 
98 const int RegExpMacroAssemblerS390::kRegExpCodeSize;
99 
RegExpMacroAssemblerS390(Isolate* isolate, Zone* zone, Mode mode, int registers_to_save)100 RegExpMacroAssemblerS390::RegExpMacroAssemblerS390(Isolate* isolate, Zone* zone,
101                                                    Mode mode,
102                                                    int registers_to_save)
103     : NativeRegExpMacroAssembler(isolate, zone),
104       masm_(std::make_unique<MacroAssembler>(
105           isolate, CodeObjectRequired::kYes,
106           NewAssemblerBuffer(kRegExpCodeSize))),
107       no_root_array_scope_(masm_.get()),
108       mode_(mode),
109       num_registers_(registers_to_save),
110       num_saved_registers_(registers_to_save),
111       entry_label_(),
112       start_label_(),
113       success_label_(),
114       backtrack_label_(),
115       exit_label_(),
116       internal_failure_label_() {
117   DCHECK_EQ(0, registers_to_save % 2);
118 
119   __ b(&entry_label_);  // We'll write the entry code later.
120   // If the code gets too big or corrupted, an internal exception will be
121   // raised, and we will exit right away.
122   __ bind(&internal_failure_label_);
123   __ mov(r2, Operand(FAILURE));
124   __ Ret();
125   __ bind(&start_label_);  // And then continue from here.
126 }
127 
~RegExpMacroAssemblerS390()128 RegExpMacroAssemblerS390::~RegExpMacroAssemblerS390() {
129   // Unuse labels in case we throw away the assembler without calling GetCode.
130   entry_label_.Unuse();
131   start_label_.Unuse();
132   success_label_.Unuse();
133   backtrack_label_.Unuse();
134   exit_label_.Unuse();
135   check_preempt_label_.Unuse();
136   stack_overflow_label_.Unuse();
137   internal_failure_label_.Unuse();
138   fallback_label_.Unuse();
139 }
140 
stack_limit_slack()141 int RegExpMacroAssemblerS390::stack_limit_slack() {
142   return RegExpStack::kStackLimitSlack;
143 }
144 
AdvanceCurrentPosition(int by)145 void RegExpMacroAssemblerS390::AdvanceCurrentPosition(int by) {
146   if (by != 0) {
147     __ AddS64(current_input_offset(), Operand(by * char_size()));
148   }
149 }
150 
AdvanceRegister(int reg, int by)151 void RegExpMacroAssemblerS390::AdvanceRegister(int reg, int by) {
152   DCHECK_LE(0, reg);
153   DCHECK_GT(num_registers_, reg);
154   if (by != 0) {
155     if (CpuFeatures::IsSupported(GENERAL_INSTR_EXT) && is_int8(by)) {
156       __ agsi(register_location(reg), Operand(by));
157     } else {
158       __ LoadU64(r2, register_location(reg), r0);
159       __ mov(r0, Operand(by));
160       __ agr(r2, r0);
161       __ StoreU64(r2, register_location(reg));
162     }
163   }
164 }
165 
Backtrack()166 void RegExpMacroAssemblerS390::Backtrack() {
167   CheckPreemption();
168   if (has_backtrack_limit()) {
169     Label next;
170     __ LoadU64(r2, MemOperand(frame_pointer(), kBacktrackCount), r0);
171     __ AddS64(r2, r2, Operand(1));
172     __ StoreU64(r2, MemOperand(frame_pointer(), kBacktrackCount), r0);
173     __ CmpU64(r2, Operand(backtrack_limit()));
174     __ bne(&next);
175 
176     // Backtrack limit exceeded.
177     if (can_fallback()) {
178       __ jmp(&fallback_label_);
179     } else {
180       // Can't fallback, so we treat it as a failed match.
181       Fail();
182     }
183 
184     __ bind(&next);
185   }
186   // Pop Code offset from backtrack stack, add Code and jump to location.
187   Pop(r2);
188   __ AddS64(r2, code_pointer());
189   __ b(r2);
190 }
191 
Bind(Label* label)192 void RegExpMacroAssemblerS390::Bind(Label* label) { __ bind(label); }
193 
CheckCharacter(uint32_t c, Label* on_equal)194 void RegExpMacroAssemblerS390::CheckCharacter(uint32_t c, Label* on_equal) {
195   __ CmpU64(current_character(), Operand(c));
196   BranchOrBacktrack(eq, on_equal);
197 }
198 
CheckCharacterGT(base::uc16 limit, Label* on_greater)199 void RegExpMacroAssemblerS390::CheckCharacterGT(base::uc16 limit,
200                                                 Label* on_greater) {
201   __ CmpU64(current_character(), Operand(limit));
202   BranchOrBacktrack(gt, on_greater);
203 }
204 
CheckAtStart(int cp_offset, Label* on_at_start)205 void RegExpMacroAssemblerS390::CheckAtStart(int cp_offset, Label* on_at_start) {
206   __ LoadU64(r3, MemOperand(frame_pointer(), kStringStartMinusOne));
207   __ AddS64(r2, current_input_offset(),
208             Operand(-char_size() + cp_offset * char_size()));
209   __ CmpS64(r2, r3);
210   BranchOrBacktrack(eq, on_at_start);
211 }
212 
CheckNotAtStart(int cp_offset, Label* on_not_at_start)213 void RegExpMacroAssemblerS390::CheckNotAtStart(int cp_offset,
214                                                Label* on_not_at_start) {
215   __ LoadU64(r3, MemOperand(frame_pointer(), kStringStartMinusOne));
216   __ AddS64(r2, current_input_offset(),
217             Operand(-char_size() + cp_offset * char_size()));
218   __ CmpS64(r2, r3);
219   BranchOrBacktrack(ne, on_not_at_start);
220 }
221 
CheckCharacterLT(base::uc16 limit, Label* on_less)222 void RegExpMacroAssemblerS390::CheckCharacterLT(base::uc16 limit,
223                                                 Label* on_less) {
224   __ CmpU64(current_character(), Operand(limit));
225   BranchOrBacktrack(lt, on_less);
226 }
227 
CheckGreedyLoop(Label* on_equal)228 void RegExpMacroAssemblerS390::CheckGreedyLoop(Label* on_equal) {
229   Label backtrack_non_equal;
230   __ CmpS64(current_input_offset(), MemOperand(backtrack_stackpointer(), 0));
231   __ bne(&backtrack_non_equal);
232   __ AddS64(backtrack_stackpointer(), Operand(kSystemPointerSize));
233 
234   BranchOrBacktrack(al, on_equal);
235   __ bind(&backtrack_non_equal);
236 }
237 
CheckNotBackReferenceIgnoreCase( int start_reg, bool read_backward, bool unicode, Label* on_no_match)238 void RegExpMacroAssemblerS390::CheckNotBackReferenceIgnoreCase(
239     int start_reg, bool read_backward, bool unicode, Label* on_no_match) {
240   Label fallthrough;
241   __ LoadU64(r2, register_location(start_reg));      // Index of start of
242                                                      // capture
243   __ LoadU64(r3, register_location(start_reg + 1));  // Index of end
244   __ SubS64(r3, r3, r2);
245 
246   // At this point, the capture registers are either both set or both cleared.
247   // If the capture length is zero, then the capture is either empty or cleared.
248   // Fall through in both cases.
249   __ beq(&fallthrough);
250 
251   // Check that there are enough characters left in the input.
252   if (read_backward) {
253     __ LoadU64(r5, MemOperand(frame_pointer(), kStringStartMinusOne));
254     __ AddS64(r5, r5, r3);
255     __ CmpS64(current_input_offset(), r5);
256     BranchOrBacktrack(le, on_no_match);
257   } else {
258     __ AddS64(r0, r3, current_input_offset());
259     BranchOrBacktrack(gt, on_no_match);
260   }
261 
262   if (mode_ == LATIN1) {
263     Label success;
264     Label fail;
265     Label loop_check;
266 
267     // r2 - offset of start of capture
268     // r3 - length of capture
269     __ AddS64(r2, end_of_input_address());
270     __ AddS64(r4, current_input_offset(), end_of_input_address());
271     if (read_backward) {
272       __ SubS64(r4, r4, r3);  // Offset by length when matching backwards.
273     }
274     __ mov(r1, Operand::Zero());
275 
276     // r1 - Loop index
277     // r2 - Address of start of capture.
278     // r4 - Address of current input position.
279 
280     Label loop;
281     __ bind(&loop);
282     __ LoadU8(r5, MemOperand(r2, r1));
283     __ LoadU8(r6, MemOperand(r4, r1));
284 
285     __ CmpS64(r6, r5);
286     __ beq(&loop_check);
287 
288     // Mismatch, try case-insensitive match (converting letters to lower-case).
289     __ Or(r5, Operand(0x20));  // Convert capture character to lower-case.
290     __ Or(r6, Operand(0x20));  // Also convert input character.
291     __ CmpS64(r6, r5);
292     __ bne(&fail);
293     __ SubS64(r5, Operand('a'));
294     __ CmpU64(r5, Operand('z' - 'a'));       // Is r5 a lowercase letter?
295     __ ble(&loop_check);                     // In range 'a'-'z'.
296     // Latin-1: Check for values in range [224,254] but not 247.
297     __ SubS64(r5, Operand(224 - 'a'));
298     __ CmpU64(r5, Operand(254 - 224));
299     __ bgt(&fail);                           // Weren't Latin-1 letters.
300     __ CmpU64(r5, Operand(247 - 224));       // Check for 247.
301     __ beq(&fail);
302 
303     __ bind(&loop_check);
304     __ la(r1, MemOperand(r1, char_size()));
305     __ CmpS64(r1, r3);
306     __ blt(&loop);
307     __ b(&success);
308 
309     __ bind(&fail);
310     BranchOrBacktrack(al, on_no_match);
311 
312     __ bind(&success);
313     // Compute new value of character position after the matched part.
314     __ SubS64(current_input_offset(), r4, end_of_input_address());
315     if (read_backward) {
316       __ LoadU64(r2,
317                  register_location(start_reg));  // Index of start of capture
318       __ LoadU64(r3,
319                  register_location(start_reg + 1));  // Index of end of capture
320       __ AddS64(current_input_offset(), current_input_offset(), r2);
321       __ SubS64(current_input_offset(), current_input_offset(), r3);
322     }
323     __ AddS64(current_input_offset(), r1);
324   } else {
325     DCHECK(mode_ == UC16);
326     int argument_count = 4;
327     __ PrepareCallCFunction(argument_count, r4);
328 
329     // r2 - offset of start of capture
330     // r3 - length of capture
331 
332     // Put arguments into arguments registers.
333     // Parameters are
334     //   r2: Address byte_offset1 - Address captured substring's start.
335     //   r3: Address byte_offset2 - Address of current character position.
336     //   r4: size_t byte_length - length of capture in bytes(!)
337     //   r5: Isolate* isolate.
338 
339     // Address of start of capture.
340     __ AddS64(r2, end_of_input_address());
341     // Length of capture.
342     __ mov(r4, r3);
343     // Save length in callee-save register for use on return.
344     __ mov(r6, r3);
345     // Address of current input position.
346     __ AddS64(r3, current_input_offset(), end_of_input_address());
347     if (read_backward) {
348       __ SubS64(r3, r3, r6);
349     }
350 // Isolate.
351     __ mov(r5, Operand(ExternalReference::isolate_address(isolate())));
352 
353     {
354       AllowExternalCallThatCantCauseGC scope(masm_.get());
355       ExternalReference function =
356           unicode
357               ? ExternalReference::re_case_insensitive_compare_unicode()
358               : ExternalReference::re_case_insensitive_compare_non_unicode();
359       __ CallCFunction(function, argument_count);
360     }
361 
362     // Check if function returned non-zero for success or zero for failure.
363     __ CmpS64(r2, Operand::Zero());
364     BranchOrBacktrack(eq, on_no_match);
365 
366     // On success, advance position by length of capture.
367     if (read_backward) {
368       __ SubS64(current_input_offset(), current_input_offset(), r6);
369     } else {
370       __ AddS64(current_input_offset(), current_input_offset(), r6);
371     }
372   }
373 
374   __ bind(&fallthrough);
375 }
376 
CheckNotBackReference(int start_reg, bool read_backward, Label* on_no_match)377 void RegExpMacroAssemblerS390::CheckNotBackReference(int start_reg,
378                                                      bool read_backward,
379                                                      Label* on_no_match) {
380   Label fallthrough;
381 
382   // Find length of back-referenced capture.
383   __ LoadU64(r2, register_location(start_reg));
384   __ LoadU64(r3, register_location(start_reg + 1));
385   __ SubS64(r3, r3, r2);  // Length to check.
386 
387   // At this point, the capture registers are either both set or both cleared.
388   // If the capture length is zero, then the capture is either empty or cleared.
389   // Fall through in both cases.
390   __ beq(&fallthrough);
391 
392   // Check that there are enough characters left in the input.
393   if (read_backward) {
394     __ LoadU64(r5, MemOperand(frame_pointer(), kStringStartMinusOne));
395     __ AddS64(r5, r5, r3);
396     __ CmpS64(current_input_offset(), r5);
397     BranchOrBacktrack(le, on_no_match);
398   } else {
399     __ AddS64(r0, r3, current_input_offset());
400     BranchOrBacktrack(gt, on_no_match, cr0);
401   }
402 
403   // r2 - offset of start of capture
404   // r3 - length of capture
405   __ la(r2, MemOperand(r2, end_of_input_address()));
406   __ la(r4, MemOperand(current_input_offset(), end_of_input_address()));
407   if (read_backward) {
408     __ SubS64(r4, r4, r3);  // Offset by length when matching backwards.
409   }
410   __ mov(r1, Operand::Zero());
411 
412   Label loop;
413   __ bind(&loop);
414   if (mode_ == LATIN1) {
415     __ LoadU8(r5, MemOperand(r2, r1));
416     __ LoadU8(r6, MemOperand(r4, r1));
417   } else {
418     DCHECK(mode_ == UC16);
419     __ LoadU16(r5, MemOperand(r2, r1));
420     __ LoadU16(r6, MemOperand(r4, r1));
421   }
422   __ la(r1, MemOperand(r1, char_size()));
423   __ CmpS64(r5, r6);
424   BranchOrBacktrack(ne, on_no_match);
425   __ CmpS64(r1, r3);
426   __ blt(&loop);
427 
428   // Move current character position to position after match.
429   __ SubS64(current_input_offset(), r4, end_of_input_address());
430   if (read_backward) {
431     __ LoadU64(r2, register_location(start_reg));  // Index of start of capture
432     __ LoadU64(r3,
433                register_location(start_reg + 1));  // Index of end of capture
434     __ AddS64(current_input_offset(), current_input_offset(), r2);
435     __ SubS64(current_input_offset(), current_input_offset(), r3);
436   }
437   __ AddS64(current_input_offset(), r1);
438 
439   __ bind(&fallthrough);
440 }
441 
CheckNotCharacter(unsigned c, Label* on_not_equal)442 void RegExpMacroAssemblerS390::CheckNotCharacter(unsigned c,
443                                                  Label* on_not_equal) {
444   __ CmpU64(current_character(), Operand(c));
445   BranchOrBacktrack(ne, on_not_equal);
446 }
447 
CheckCharacterAfterAnd(uint32_t c, uint32_t mask, Label* on_equal)448 void RegExpMacroAssemblerS390::CheckCharacterAfterAnd(uint32_t c, uint32_t mask,
449                                                       Label* on_equal) {
450   __ AndP(r2, current_character(), Operand(mask));
451   if (c != 0) {
452     __ CmpU64(r2, Operand(c));
453   }
454   BranchOrBacktrack(eq, on_equal);
455 }
456 
CheckNotCharacterAfterAnd(unsigned c, unsigned mask, Label* on_not_equal)457 void RegExpMacroAssemblerS390::CheckNotCharacterAfterAnd(unsigned c,
458                                                          unsigned mask,
459                                                          Label* on_not_equal) {
460   __ AndP(r2, current_character(), Operand(mask));
461   if (c != 0) {
462     __ CmpU64(r2, Operand(c));
463   }
464   BranchOrBacktrack(ne, on_not_equal);
465 }
466 
CheckNotCharacterAfterMinusAnd( base::uc16 c, base::uc16 minus, base::uc16 mask, Label* on_not_equal)467 void RegExpMacroAssemblerS390::CheckNotCharacterAfterMinusAnd(
468     base::uc16 c, base::uc16 minus, base::uc16 mask, Label* on_not_equal) {
469   DCHECK_GT(String::kMaxUtf16CodeUnit, minus);
470   __ lay(r2, MemOperand(current_character(), -minus));
471   __ And(r2, Operand(mask));
472   if (c != 0) {
473     __ CmpU64(r2, Operand(c));
474   }
475   BranchOrBacktrack(ne, on_not_equal);
476 }
477 
CheckCharacterInRange(base::uc16 from, base::uc16 to, Label* on_in_range)478 void RegExpMacroAssemblerS390::CheckCharacterInRange(base::uc16 from,
479                                                      base::uc16 to,
480                                                      Label* on_in_range) {
481   __ lay(r2, MemOperand(current_character(), -from));
482   __ CmpU64(r2, Operand(to - from));
483   BranchOrBacktrack(le, on_in_range);  // Unsigned lower-or-same condition.
484 }
485 
CheckCharacterNotInRange( base::uc16 from, base::uc16 to, Label* on_not_in_range)486 void RegExpMacroAssemblerS390::CheckCharacterNotInRange(
487     base::uc16 from, base::uc16 to, Label* on_not_in_range) {
488   __ lay(r2, MemOperand(current_character(), -from));
489   __ CmpU64(r2, Operand(to - from));
490   BranchOrBacktrack(gt, on_not_in_range);  // Unsigned higher condition.
491 }
492 
CallIsCharacterInRangeArray( const ZoneList<CharacterRange>* ranges)493 void RegExpMacroAssemblerS390::CallIsCharacterInRangeArray(
494     const ZoneList<CharacterRange>* ranges) {
495   static const int kNumArguments = 3;
496   __ PrepareCallCFunction(kNumArguments, r0);
497 
498   __ mov(r2, current_character());
499   __ mov(r3, Operand(GetOrAddRangeArray(ranges)));
500   __ mov(r4, Operand(ExternalReference::isolate_address(isolate())));
501 
502   {
503     // We have a frame (set up in GetCode), but the assembler doesn't know.
504     FrameScope scope(masm_.get(), StackFrame::MANUAL);
505     __ CallCFunction(ExternalReference::re_is_character_in_range_array(),
506                      kNumArguments);
507   }
508 
509   __ mov(code_pointer(), Operand(masm_->CodeObject()));
510 }
511 
CheckCharacterInRangeArray( const ZoneList<CharacterRange>* ranges, Label* on_in_range)512 bool RegExpMacroAssemblerS390::CheckCharacterInRangeArray(
513     const ZoneList<CharacterRange>* ranges, Label* on_in_range) {
514   CallIsCharacterInRangeArray(ranges);
515   __ CmpS64(r2, Operand::Zero());
516   BranchOrBacktrack(ne, on_in_range);
517   return true;
518 }
519 
CheckCharacterNotInRangeArray( const ZoneList<CharacterRange>* ranges, Label* on_not_in_range)520 bool RegExpMacroAssemblerS390::CheckCharacterNotInRangeArray(
521     const ZoneList<CharacterRange>* ranges, Label* on_not_in_range) {
522   CallIsCharacterInRangeArray(ranges);
523   __ CmpS64(r2, Operand::Zero());
524   BranchOrBacktrack(eq, on_not_in_range);
525   return true;
526 }
527 
CheckBitInTable(Handle<ByteArray> table, Label* on_bit_set)528 void RegExpMacroAssemblerS390::CheckBitInTable(Handle<ByteArray> table,
529                                                Label* on_bit_set) {
530   __ mov(r2, Operand(table));
531   Register index = current_character();
532   if (mode_ != LATIN1 || kTableMask != String::kMaxOneByteCharCode) {
533     __ AndP(r3, current_character(), Operand(kTableSize - 1));
534     index = r3;
535   }
536   __ LoadU8(r2,
537             MemOperand(r2, index, (ByteArray::kHeaderSize - kHeapObjectTag)));
538   __ CmpS64(r2, Operand::Zero());
539   BranchOrBacktrack(ne, on_bit_set);
540 }
541 
CheckSpecialCharacterClass( StandardCharacterSet type, Label* on_no_match)542 bool RegExpMacroAssemblerS390::CheckSpecialCharacterClass(
543     StandardCharacterSet type, Label* on_no_match) {
544   // Range checks (c in min..max) are generally implemented by an unsigned
545   // (c - min) <= (max - min) check
546   // TODO(jgruber): No custom implementation (yet): s(UC16), S(UC16).
547   switch (type) {
548     case StandardCharacterSet::kWhitespace:
549       // Match space-characters.
550       if (mode_ == LATIN1) {
551         // One byte space characters are '\t'..'\r', ' ' and \u00a0.
552         Label success;
553         __ CmpS64(current_character(), Operand(' '));
554         __ beq(&success);
555         // Check range 0x09..0x0D.
556         __ SubS64(r2, current_character(), Operand('\t'));
557         __ CmpU64(r2, Operand('\r' - '\t'));
558         __ ble(&success);
559         // \u00a0 (NBSP).
560         __ CmpU64(r2, Operand(0x00A0 - '\t'));
561         BranchOrBacktrack(ne, on_no_match);
562         __ bind(&success);
563         return true;
564       }
565       return false;
566     case StandardCharacterSet::kNotWhitespace:
567       // The emitted code for generic character classes is good enough.
568       return false;
569     case StandardCharacterSet::kDigit:
570       // Match ASCII digits ('0'..'9')
571       __ SubS64(r2, current_character(), Operand('0'));
572       __ CmpU64(r2, Operand('9' - '0'));
573       BranchOrBacktrack(gt, on_no_match);
574       return true;
575     case StandardCharacterSet::kNotDigit:
576       // Match non ASCII-digits
577       __ SubS64(r2, current_character(), Operand('0'));
578       __ CmpU64(r2, Operand('9' - '0'));
579       BranchOrBacktrack(le, on_no_match);
580       return true;
581     case StandardCharacterSet::kNotLineTerminator: {
582       // Match non-newlines (not 0x0A('\n'), 0x0D('\r'), 0x2028 and 0x2029)
583       __ XorP(r2, current_character(), Operand(0x01));
584       // See if current character is '\n'^1 or '\r'^1, i.e., 0x0B or 0x0C
585       __ SubS64(r2, Operand(0x0B));
586       __ CmpU64(r2, Operand(0x0C - 0x0B));
587       BranchOrBacktrack(le, on_no_match);
588       if (mode_ == UC16) {
589         // Compare original value to 0x2028 and 0x2029, using the already
590         // computed (current_char ^ 0x01 - 0x0B). I.e., check for
591         // 0x201D (0x2028 - 0x0B) or 0x201E.
592         __ SubS64(r2, Operand(0x2028 - 0x0B));
593         __ CmpU64(r2, Operand(1));
594         BranchOrBacktrack(le, on_no_match);
595       }
596       return true;
597     }
598     case StandardCharacterSet::kLineTerminator: {
599       // Match newlines (0x0A('\n'), 0x0D('\r'), 0x2028 and 0x2029)
600       __ XorP(r2, current_character(), Operand(0x01));
601       // See if current character is '\n'^1 or '\r'^1, i.e., 0x0B or 0x0C
602       __ SubS64(r2, Operand(0x0B));
603       __ CmpU64(r2, Operand(0x0C - 0x0B));
604       if (mode_ == LATIN1) {
605         BranchOrBacktrack(gt, on_no_match);
606       } else {
607         Label done;
608         __ ble(&done);
609         // Compare original value to 0x2028 and 0x2029, using the already
610         // computed (current_char ^ 0x01 - 0x0B). I.e., check for
611         // 0x201D (0x2028 - 0x0B) or 0x201E.
612         __ SubS64(r2, Operand(0x2028 - 0x0B));
613         __ CmpU64(r2, Operand(1));
614         BranchOrBacktrack(gt, on_no_match);
615         __ bind(&done);
616       }
617       return true;
618     }
619     case StandardCharacterSet::kWord: {
620       if (mode_ != LATIN1) {
621         // Table is 1256 entries, so all LATIN1 characters can be tested.
622         __ CmpS64(current_character(), Operand('z'));
623         BranchOrBacktrack(gt, on_no_match);
624       }
625       ExternalReference map = ExternalReference::re_word_character_map();
626       __ mov(r2, Operand(map));
627       __ LoadU8(r2, MemOperand(r2, current_character()));
628       __ CmpU64(r2, Operand::Zero());
629       BranchOrBacktrack(eq, on_no_match);
630       return true;
631     }
632     case StandardCharacterSet::kNotWord: {
633       Label done;
634       if (mode_ != LATIN1) {
635         // Table is 256 entries, so all LATIN characters can be tested.
636         __ CmpU64(current_character(), Operand('z'));
637         __ bgt(&done);
638       }
639       ExternalReference map = ExternalReference::re_word_character_map();
640       __ mov(r2, Operand(map));
641       __ LoadU8(r2, MemOperand(r2, current_character()));
642       __ CmpU64(r2, Operand::Zero());
643       BranchOrBacktrack(ne, on_no_match);
644       if (mode_ != LATIN1) {
645         __ bind(&done);
646       }
647       return true;
648     }
649     case StandardCharacterSet::kEverything:
650       // Match any character.
651       return true;
652   }
653 }
654 
Fail()655 void RegExpMacroAssemblerS390::Fail() {
656   __ mov(r2, Operand(FAILURE));
657   __ b(&exit_label_);
658 }
659 
LoadRegExpStackPointerFromMemory(Register dst)660 void RegExpMacroAssemblerS390::LoadRegExpStackPointerFromMemory(Register dst) {
661   ExternalReference ref =
662       ExternalReference::address_of_regexp_stack_stack_pointer(isolate());
663   __ mov(dst, Operand(ref));
664   __ LoadU64(dst, MemOperand(dst));
665 }
666 
StoreRegExpStackPointerToMemory( Register src, Register scratch)667 void RegExpMacroAssemblerS390::StoreRegExpStackPointerToMemory(
668     Register src, Register scratch) {
669   ExternalReference ref =
670       ExternalReference::address_of_regexp_stack_stack_pointer(isolate());
671   __ mov(scratch, Operand(ref));
672   __ StoreU64(src, MemOperand(scratch));
673 }
674 
PushRegExpBasePointer(Register stack_pointer, Register scratch)675 void RegExpMacroAssemblerS390::PushRegExpBasePointer(Register stack_pointer,
676                                                      Register scratch) {
677   ExternalReference ref =
678       ExternalReference::address_of_regexp_stack_memory_top_address(isolate());
679   __ mov(scratch, Operand(ref));
680   __ LoadU64(scratch, MemOperand(scratch));
681   __ SubS64(scratch, stack_pointer, scratch);
682   __ StoreU64(scratch, MemOperand(frame_pointer(), kRegExpStackBasePointer));
683 }
684 
PopRegExpBasePointer(Register stack_pointer_out, Register scratch)685 void RegExpMacroAssemblerS390::PopRegExpBasePointer(Register stack_pointer_out,
686                                                     Register scratch) {
687   ExternalReference ref =
688       ExternalReference::address_of_regexp_stack_memory_top_address(isolate());
689   __ LoadU64(stack_pointer_out,
690              MemOperand(frame_pointer(), kRegExpStackBasePointer));
691   __ mov(scratch, Operand(ref));
692   __ LoadU64(scratch, MemOperand(scratch));
693   __ AddS64(stack_pointer_out, stack_pointer_out, scratch);
694   StoreRegExpStackPointerToMemory(stack_pointer_out, scratch);
695 }
696 
GetCode(Handle<String> source)697 Handle<HeapObject> RegExpMacroAssemblerS390::GetCode(Handle<String> source) {
698   Label return_r2;
699 
700   // Finalize code - write the entry point code now we know how many
701   // registers we need.
702 
703   // Entry code:
704   __ bind(&entry_label_);
705 
706   // Tell the system that we have a stack frame.  Because the type
707   // is MANUAL, no is generated.
708   FrameScope scope(masm_.get(), StackFrame::MANUAL);
709 
710   // Ensure register assigments are consistent with callee save mask
711   DCHECK(kRegExpCalleeSaved.has(r6));
712   DCHECK(kRegExpCalleeSaved.has(code_pointer()));
713   DCHECK(kRegExpCalleeSaved.has(current_input_offset()));
714   DCHECK(kRegExpCalleeSaved.has(current_character()));
715   DCHECK(kRegExpCalleeSaved.has(backtrack_stackpointer()));
716   DCHECK(kRegExpCalleeSaved.has(end_of_input_address()));
717   DCHECK(kRegExpCalleeSaved.has(frame_pointer()));
718 
719   // zLinux ABI
720   //    Incoming parameters:
721   //          r2: input_string
722   //          r3: start_index
723   //          r4: start addr
724   //          r5: end addr
725   //          r6: capture output arrray
726   //    Requires us to save the callee-preserved registers r6-r13
727   //    General convention is to also save r14 (return addr) and
728   //    sp/r15 as well in a single STM/STMG
729   __ StoreMultipleP(r6, sp, MemOperand(sp, 6 * kSystemPointerSize));
730 
731   // Load stack parameters from caller stack frame
732   __ LoadMultipleP(
733       r7, r9, MemOperand(sp, kStackFrameExtraParamSlot * kSystemPointerSize));
734   // r7 = capture array size
735   // r8 = stack area base
736   // r9 = direct call
737 
738   // Actually emit code to start a new stack frame.
739   // Push arguments
740   // Save callee-save registers.
741   // Start new stack frame.
742   // Store link register in existing stack-cell.
743   // Order here should correspond to order of offset constants in header file.
744   //
745   // Set frame pointer in space for it if this is not a direct call
746   // from generated code.
747   __ mov(frame_pointer(), sp);
748   __ lay(sp, MemOperand(sp, -10 * kSystemPointerSize));
749   STATIC_ASSERT(kSuccessfulCaptures == kInputString - kSystemPointerSize);
750   __ mov(r1, Operand::Zero());  // success counter
751   STATIC_ASSERT(kStringStartMinusOne ==
752                 kSuccessfulCaptures - kSystemPointerSize);
753   __ mov(r0, r1);  // offset of location
754   __ StoreMultipleP(r0, r9, MemOperand(sp, 0));
755   STATIC_ASSERT(kBacktrackCount == kStringStartMinusOne - kSystemPointerSize);
756   __ Push(r1);  // The backtrack counter.
757   STATIC_ASSERT(kRegExpStackBasePointer ==
758                 kBacktrackCount - kSystemPointerSize);
759   __ push(r1);  // The regexp stack base ptr.
760 
761   // Initialize backtrack stack pointer. It must not be clobbered from here on.
762   // Note the backtrack_stackpointer is callee-saved.
763   STATIC_ASSERT(backtrack_stackpointer() == r13);
764   LoadRegExpStackPointerFromMemory(backtrack_stackpointer());
765 
766   // Store the regexp base pointer - we'll later restore it / write it to
767   // memory when returning from this irregexp code object.
768   PushRegExpBasePointer(backtrack_stackpointer(), r3);
769 
770   {
771     // Check if we have space on the stack for registers.
772     Label stack_limit_hit, stack_ok;
773 
774     ExternalReference stack_limit =
775         ExternalReference::address_of_jslimit(isolate());
776     __ mov(r2, Operand(stack_limit));
777     __ LoadU64(r2, MemOperand(r2));
778     __ SubS64(r2, sp, r2);
779     // Handle it if the stack pointer is already below the stack limit.
780     __ ble(&stack_limit_hit);
781     // Check if there is room for the variable number of registers above
782     // the stack limit.
783     __ CmpU64(r2, Operand(num_registers_ * kSystemPointerSize));
784     __ bge(&stack_ok);
785     // Exit with OutOfMemory exception. There is not enough space on the stack
786     // for our working registers.
787     __ mov(r2, Operand(EXCEPTION));
788     __ b(&return_r2);
789 
790     __ bind(&stack_limit_hit);
791     CallCheckStackGuardState(r2);
792     __ CmpS64(r2, Operand::Zero());
793     // If returned value is non-zero, we exit with the returned value as result.
794     __ bne(&return_r2);
795 
796     __ bind(&stack_ok);
797   }
798 
799   // Allocate space on stack for registers.
800   __ lay(sp, MemOperand(sp, (-num_registers_ * kSystemPointerSize)));
801   // Load string end.
802   __ LoadU64(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
803   // Load input start.
804   __ LoadU64(r4, MemOperand(frame_pointer(), kInputStart));
805   // Find negative length (offset of start relative to end).
806   __ SubS64(current_input_offset(), r4, end_of_input_address());
807   __ LoadU64(r3, MemOperand(frame_pointer(), kStartIndex));
808   // Set r1 to address of char before start of the input string
809   // (effectively string position -1).
810   __ mov(r1, r4);
811   __ SubS64(r1, current_input_offset(), Operand(char_size()));
812   if (mode_ == UC16) {
813     __ ShiftLeftU64(r0, r3, Operand(1));
814     __ SubS64(r1, r1, r0);
815   } else {
816     __ SubS64(r1, r1, r3);
817   }
818   // Store this value in a local variable, for use when clearing
819   // position registers.
820   __ StoreU64(r1, MemOperand(frame_pointer(), kStringStartMinusOne));
821 
822   // Initialize code pointer register
823   __ mov(code_pointer(), Operand(masm_->CodeObject()));
824 
825   Label load_char_start_regexp;
826   {
827     Label start_regexp;
828     // Load newline if index is at start, previous character otherwise.
829     __ CmpS64(r3, Operand::Zero());
830     __ bne(&load_char_start_regexp);
831     __ mov(current_character(), Operand('\n'));
832     __ b(&start_regexp);
833 
834     // Global regexp restarts matching here.
835     __ bind(&load_char_start_regexp);
836     // Load previous char as initial value of current character register.
837     LoadCurrentCharacterUnchecked(-1, 1);
838     __ bind(&start_regexp);
839   }
840 
841   // Initialize on-stack registers.
842   if (num_saved_registers_ > 0) {  // Always is, if generated from a regexp.
843     // Fill saved registers with initial value = start offset - 1
844     if (num_saved_registers_ > 8) {
845       // One slot beyond address of register 0.
846       __ lay(r3,
847              MemOperand(frame_pointer(), kRegisterZero + kSystemPointerSize));
848       __ mov(r4, Operand(num_saved_registers_));
849       Label init_loop;
850       __ bind(&init_loop);
851       __ StoreU64(r1, MemOperand(r3, -kSystemPointerSize));
852       __ lay(r3, MemOperand(r3, -kSystemPointerSize));
853       __ BranchOnCount(r4, &init_loop);
854     } else {
855       for (int i = 0; i < num_saved_registers_; i++) {
856         __ StoreU64(r1, register_location(i));
857       }
858     }
859   }
860 
861   __ b(&start_label_);
862 
863   // Exit code:
864   if (success_label_.is_linked()) {
865     // Save captures when successful.
866     __ bind(&success_label_);
867     if (num_saved_registers_ > 0) {
868       // copy captures to output
869       __ LoadU64(r0, MemOperand(frame_pointer(), kInputStart));
870       __ LoadU64(r2, MemOperand(frame_pointer(), kRegisterOutput));
871       __ LoadU64(r4, MemOperand(frame_pointer(), kStartIndex));
872       __ SubS64(r0, end_of_input_address(), r0);
873       // r0 is length of input in bytes.
874       if (mode_ == UC16) {
875         __ ShiftRightU64(r0, r0, Operand(1));
876       }
877       // r0 is length of input in characters.
878       __ AddS64(r0, r4);
879       // r0 is length of string in characters.
880 
881       DCHECK_EQ(0, num_saved_registers_ % 2);
882       // Always an even number of capture registers. This allows us to
883       // unroll the loop once to add an operation between a load of a register
884       // and the following use of that register.
885       __ lay(r2, MemOperand(r2, num_saved_registers_ * kIntSize));
886       for (int i = 0; i < num_saved_registers_;) {
887         if ((false) && i < num_saved_registers_ - 4) {
888           // TODO(john.yan): Can be optimized by SIMD instructions
889           __ LoadMultipleP(r3, r6, register_location(i + 3));
890           if (mode_ == UC16) {
891             __ ShiftRightS64(r3, r3, Operand(1));
892             __ ShiftRightS64(r4, r4, Operand(1));
893             __ ShiftRightS64(r5, r5, Operand(1));
894             __ ShiftRightS64(r6, r6, Operand(1));
895           }
896           __ AddS64(r3, r0);
897           __ AddS64(r4, r0);
898           __ AddS64(r5, r0);
899           __ AddS64(r6, r0);
900           __ StoreU32(
901               r3, MemOperand(r2, -(num_saved_registers_ - i - 3) * kIntSize));
902           __ StoreU32(
903               r4, MemOperand(r2, -(num_saved_registers_ - i - 2) * kIntSize));
904           __ StoreU32(
905               r5, MemOperand(r2, -(num_saved_registers_ - i - 1) * kIntSize));
906           __ StoreU32(r6,
907                       MemOperand(r2, -(num_saved_registers_ - i) * kIntSize));
908           i += 4;
909         } else {
910           __ LoadMultipleP(r3, r4, register_location(i + 1));
911           if (mode_ == UC16) {
912             __ ShiftRightS64(r3, r3, Operand(1));
913             __ ShiftRightS64(r4, r4, Operand(1));
914           }
915           __ AddS64(r3, r0);
916           __ AddS64(r4, r0);
917           __ StoreU32(
918               r3, MemOperand(r2, -(num_saved_registers_ - i - 1) * kIntSize));
919           __ StoreU32(r4,
920                       MemOperand(r2, -(num_saved_registers_ - i) * kIntSize));
921           i += 2;
922         }
923       }
924       if (global_with_zero_length_check()) {
925         // Keep capture start in r6 for the zero-length check later.
926         __ LoadU64(r6, register_location(0));
927       }
928     }
929 
930     if (global()) {
931       // Restart matching if the regular expression is flagged as global.
932       __ LoadU64(r2, MemOperand(frame_pointer(), kSuccessfulCaptures));
933       __ LoadU64(r3, MemOperand(frame_pointer(), kNumOutputRegisters));
934       __ LoadU64(r4, MemOperand(frame_pointer(), kRegisterOutput));
935       // Increment success counter.
936       __ AddS64(r2, Operand(1));
937       __ StoreU64(r2, MemOperand(frame_pointer(), kSuccessfulCaptures));
938       // Capture results have been stored, so the number of remaining global
939       // output registers is reduced by the number of stored captures.
940       __ SubS64(r3, Operand(num_saved_registers_));
941       // Check whether we have enough room for another set of capture results.
942       __ CmpS64(r3, Operand(num_saved_registers_));
943       __ blt(&return_r2);
944 
945       __ StoreU64(r3, MemOperand(frame_pointer(), kNumOutputRegisters));
946       // Advance the location for output.
947       __ AddS64(r4, Operand(num_saved_registers_ * kIntSize));
948       __ StoreU64(r4, MemOperand(frame_pointer(), kRegisterOutput));
949 
950       // Prepare r2 to initialize registers with its value in the next run.
951       __ LoadU64(r2, MemOperand(frame_pointer(), kStringStartMinusOne));
952 
953       // Restore the original regexp stack pointer value (effectively, pop the
954       // stored base pointer).
955       PopRegExpBasePointer(backtrack_stackpointer(), r4);
956 
957       if (global_with_zero_length_check()) {
958         // Special case for zero-length matches.
959         // r6: capture start index
960         __ CmpS64(current_input_offset(), r6);
961         // Not a zero-length match, restart.
962         __ bne(&load_char_start_regexp);
963         // Offset from the end is zero if we already reached the end.
964         __ CmpS64(current_input_offset(), Operand::Zero());
965         __ beq(&exit_label_);
966         // Advance current position after a zero-length match.
967         Label advance;
968         __ bind(&advance);
969         __ AddS64(current_input_offset(), Operand((mode_ == UC16) ? 2 : 1));
970         if (global_unicode()) CheckNotInSurrogatePair(0, &advance);
971       }
972 
973       __ b(&load_char_start_regexp);
974     } else {
975       __ mov(r2, Operand(SUCCESS));
976     }
977   }
978 
979   // Exit and return r2
980   __ bind(&exit_label_);
981   if (global()) {
982     __ LoadU64(r2, MemOperand(frame_pointer(), kSuccessfulCaptures));
983   }
984 
985   __ bind(&return_r2);
986   // Restore the original regexp stack pointer value (effectively, pop the
987   // stored base pointer).
988   PopRegExpBasePointer(backtrack_stackpointer(), r4);
989 
990   // Skip sp past regexp registers and local variables..
991   __ mov(sp, frame_pointer());
992   // Restore registers r6..r15.
993   __ LoadMultipleP(r6, sp, MemOperand(sp, 6 * kSystemPointerSize));
994 
995   __ b(r14);
996 
997   // Backtrack code (branch target for conditional backtracks).
998   if (backtrack_label_.is_linked()) {
999     __ bind(&backtrack_label_);
1000     Backtrack();
1001   }
1002 
1003   Label exit_with_exception;
1004 
1005   // Preempt-code
1006   if (check_preempt_label_.is_linked()) {
1007     SafeCallTarget(&check_preempt_label_);
1008 
1009     StoreRegExpStackPointerToMemory(backtrack_stackpointer(), r3);
1010 
1011     CallCheckStackGuardState(r2);
1012     __ CmpS64(r2, Operand::Zero());
1013     // If returning non-zero, we should end execution with the given
1014     // result as return value.
1015     __ bne(&return_r2);
1016 
1017     LoadRegExpStackPointerFromMemory(backtrack_stackpointer());
1018 
1019     // String might have moved: Reload end of string from frame.
1020     __ LoadU64(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
1021     SafeReturn();
1022   }
1023 
1024   // Backtrack stack overflow code.
1025   if (stack_overflow_label_.is_linked()) {
1026     SafeCallTarget(&stack_overflow_label_);
1027     // Reached if the backtrack-stack limit has been hit.
1028 
1029     // Call GrowStack(isolate).
1030 
1031     StoreRegExpStackPointerToMemory(backtrack_stackpointer(), r3);
1032 
1033     static constexpr int kNumArguments = 1;
1034     __ PrepareCallCFunction(kNumArguments, r2);
1035     __ mov(r2, Operand(ExternalReference::isolate_address(isolate())));
1036     ExternalReference grow_stack = ExternalReference::re_grow_stack();
1037     __ CallCFunction(grow_stack, kNumArguments);
1038     // If nullptr is returned, we have failed to grow the stack, and must exit
1039     // with a stack-overflow exception.
1040     __ CmpS64(r2, Operand::Zero());
1041     __ beq(&exit_with_exception);
1042     // Otherwise use return value as new stack pointer.
1043     __ mov(backtrack_stackpointer(), r2);
1044     // Restore saved registers and continue.
1045     SafeReturn();
1046   }
1047 
1048   if (exit_with_exception.is_linked()) {
1049     // If any of the code above needed to exit with an exception.
1050     __ bind(&exit_with_exception);
1051     // Exit with Result EXCEPTION(-1) to signal thrown exception.
1052     __ mov(r2, Operand(EXCEPTION));
1053     __ b(&return_r2);
1054   }
1055 
1056   if (fallback_label_.is_linked()) {
1057     __ bind(&fallback_label_);
1058     __ mov(r2, Operand(FALLBACK_TO_EXPERIMENTAL));
1059     __ b(&return_r2);
1060   }
1061 
1062   CodeDesc code_desc;
1063   masm_->GetCode(isolate(), &code_desc);
1064   Handle<Code> code =
1065       Factory::CodeBuilder(isolate(), code_desc, CodeKind::REGEXP)
1066           .set_self_reference(masm_->CodeObject())
1067           .Build();
1068   PROFILE(masm_->isolate(),
1069           RegExpCodeCreateEvent(Handle<AbstractCode>::cast(code), source));
1070   return Handle<HeapObject>::cast(code);
1071 }
1072 
GoTo(Label* to)1073 void RegExpMacroAssemblerS390::GoTo(Label* to) { BranchOrBacktrack(al, to); }
1074 
IfRegisterGE(int reg, int comparand, Label* if_ge)1075 void RegExpMacroAssemblerS390::IfRegisterGE(int reg, int comparand,
1076                                             Label* if_ge) {
1077   __ LoadU64(r2, register_location(reg), r0);
1078   __ CmpS64(r2, Operand(comparand));
1079   BranchOrBacktrack(ge, if_ge);
1080 }
1081 
IfRegisterLT(int reg, int comparand, Label* if_lt)1082 void RegExpMacroAssemblerS390::IfRegisterLT(int reg, int comparand,
1083                                             Label* if_lt) {
1084   __ LoadU64(r2, register_location(reg), r0);
1085   __ CmpS64(r2, Operand(comparand));
1086   BranchOrBacktrack(lt, if_lt);
1087 }
1088 
IfRegisterEqPos(int reg, Label* if_eq)1089 void RegExpMacroAssemblerS390::IfRegisterEqPos(int reg, Label* if_eq) {
1090   __ LoadU64(r2, register_location(reg), r0);
1091   __ CmpS64(r2, current_input_offset());
1092   BranchOrBacktrack(eq, if_eq);
1093 }
1094 
1095 RegExpMacroAssembler::IrregexpImplementation
Implementation()1096 RegExpMacroAssemblerS390::Implementation() {
1097   return kS390Implementation;
1098 }
1099 
PopCurrentPosition()1100 void RegExpMacroAssemblerS390::PopCurrentPosition() {
1101   Pop(current_input_offset());
1102 }
1103 
PopRegister(int register_index)1104 void RegExpMacroAssemblerS390::PopRegister(int register_index) {
1105   Pop(r2);
1106   __ StoreU64(r2, register_location(register_index));
1107 }
1108 
PushBacktrack(Label* label)1109 void RegExpMacroAssemblerS390::PushBacktrack(Label* label) {
1110   if (label->is_bound()) {
1111     int target = label->pos();
1112     __ mov(r2, Operand(target + Code::kHeaderSize - kHeapObjectTag));
1113   } else {
1114     masm_->load_label_offset(r2, label);
1115   }
1116   Push(r2);
1117   CheckStackLimit();
1118 }
1119 
PushCurrentPosition()1120 void RegExpMacroAssemblerS390::PushCurrentPosition() {
1121   Push(current_input_offset());
1122 }
1123 
PushRegister(int register_index, StackCheckFlag check_stack_limit)1124 void RegExpMacroAssemblerS390::PushRegister(int register_index,
1125                                             StackCheckFlag check_stack_limit) {
1126   __ LoadU64(r2, register_location(register_index), r0);
1127   Push(r2);
1128   if (check_stack_limit) CheckStackLimit();
1129 }
1130 
ReadCurrentPositionFromRegister(int reg)1131 void RegExpMacroAssemblerS390::ReadCurrentPositionFromRegister(int reg) {
1132   __ LoadU64(current_input_offset(), register_location(reg), r0);
1133 }
1134 
WriteStackPointerToRegister(int reg)1135 void RegExpMacroAssemblerS390::WriteStackPointerToRegister(int reg) {
1136   ExternalReference ref =
1137       ExternalReference::address_of_regexp_stack_memory_top_address(isolate());
1138   __ mov(r3, Operand(ref));
1139   __ LoadU64(r3, MemOperand(r3));
1140   __ SubS64(r2, backtrack_stackpointer(), r3);
1141   __ StoreU64(r2, register_location(reg));
1142 }
1143 
ReadStackPointerFromRegister(int reg)1144 void RegExpMacroAssemblerS390::ReadStackPointerFromRegister(int reg) {
1145   ExternalReference ref =
1146       ExternalReference::address_of_regexp_stack_memory_top_address(isolate());
1147   __ mov(r2, Operand(ref));
1148   __ LoadU64(r2, MemOperand(r2));
1149   __ LoadU64(backtrack_stackpointer(), register_location(reg));
1150   __ AddS64(backtrack_stackpointer(), backtrack_stackpointer(), r2);
1151 }
1152 
SetCurrentPositionFromEnd(int by)1153 void RegExpMacroAssemblerS390::SetCurrentPositionFromEnd(int by) {
1154   Label after_position;
1155   __ CmpS64(current_input_offset(), Operand(-by * char_size()));
1156   __ bge(&after_position);
1157   __ mov(current_input_offset(), Operand(-by * char_size()));
1158   // On RegExp code entry (where this operation is used), the character before
1159   // the current position is expected to be already loaded.
1160   // We have advanced the position, so it's safe to read backwards.
1161   LoadCurrentCharacterUnchecked(-1, 1);
1162   __ bind(&after_position);
1163 }
1164 
SetRegister(int register_index, int to)1165 void RegExpMacroAssemblerS390::SetRegister(int register_index, int to) {
1166   DCHECK(register_index >= num_saved_registers_);  // Reserved for positions!
1167   __ mov(r2, Operand(to));
1168   __ StoreU64(r2, register_location(register_index));
1169 }
1170 
Succeed()1171 bool RegExpMacroAssemblerS390::Succeed() {
1172   __ b(&success_label_);
1173   return global();
1174 }
1175 
WriteCurrentPositionToRegister(int reg, int cp_offset)1176 void RegExpMacroAssemblerS390::WriteCurrentPositionToRegister(int reg,
1177                                                               int cp_offset) {
1178   if (cp_offset == 0) {
1179     __ StoreU64(current_input_offset(), register_location(reg));
1180   } else {
1181     __ AddS64(r2, current_input_offset(), Operand(cp_offset * char_size()));
1182     __ StoreU64(r2, register_location(reg));
1183   }
1184 }
1185 
ClearRegisters(int reg_from, int reg_to)1186 void RegExpMacroAssemblerS390::ClearRegisters(int reg_from, int reg_to) {
1187   DCHECK(reg_from <= reg_to);
1188   __ LoadU64(r2, MemOperand(frame_pointer(), kStringStartMinusOne));
1189   for (int reg = reg_from; reg <= reg_to; reg++) {
1190     __ StoreU64(r2, register_location(reg));
1191   }
1192 }
1193 
1194 // Private methods:
1195 
CallCheckStackGuardState(Register scratch)1196 void RegExpMacroAssemblerS390::CallCheckStackGuardState(Register scratch) {
1197   DCHECK(!isolate()->IsGeneratingEmbeddedBuiltins());
1198   DCHECK(!masm_->options().isolate_independent_code);
1199 
1200   static constexpr int num_arguments = 3;
1201   __ PrepareCallCFunction(num_arguments, scratch);
1202   // RegExp code frame pointer.
1203   __ mov(r4, frame_pointer());
1204   // Code of self.
1205   __ mov(r3, Operand(masm_->CodeObject()));
1206   // r2 becomes return address pointer.
1207   __ lay(r2, MemOperand(sp, kStackFrameRASlot * kSystemPointerSize));
1208   ExternalReference stack_guard_check =
1209       ExternalReference::re_check_stack_guard_state();
1210 
1211   __ mov(ip, Operand(stack_guard_check));
1212   __ StoreReturnAddressAndCall(ip);
1213 
1214   if (base::OS::ActivationFrameAlignment() > kSystemPointerSize) {
1215     __ LoadU64(
1216         sp, MemOperand(sp, (kNumRequiredStackFrameSlots * kSystemPointerSize)));
1217   } else {
1218     __ la(sp,
1219           MemOperand(sp, (kNumRequiredStackFrameSlots * kSystemPointerSize)));
1220   }
1221 
1222   __ mov(code_pointer(), Operand(masm_->CodeObject()));
1223 }
1224 
1225 // Helper function for reading a value out of a stack frame.
1226 template <typename T>
frame_entry(Address re_frame, int frame_offset)1227 static T& frame_entry(Address re_frame, int frame_offset) {
1228   DCHECK_EQ(kSystemPointerSize, sizeof(T));
1229 #ifdef V8_TARGET_ARCH_S390X
1230   return reinterpret_cast<T&>(Memory<uint64_t>(re_frame + frame_offset));
1231 #else
1232   return reinterpret_cast<T&>(Memory<uint32_t>(re_frame + frame_offset));
1233 #endif
1234 }
1235 
1236 template <typename T>
frame_entry_address(Address re_frame, int frame_offset)1237 static T* frame_entry_address(Address re_frame, int frame_offset) {
1238   return reinterpret_cast<T*>(re_frame + frame_offset);
1239 }
1240 
CheckStackGuardState(Address* return_address, Address raw_code, Address re_frame)1241 int RegExpMacroAssemblerS390::CheckStackGuardState(Address* return_address,
1242                                                    Address raw_code,
1243                                                    Address re_frame) {
1244   Code re_code = Code::cast(Object(raw_code));
1245   return NativeRegExpMacroAssembler::CheckStackGuardState(
1246       frame_entry<Isolate*>(re_frame, kIsolate),
1247       frame_entry<intptr_t>(re_frame, kStartIndex),
1248       static_cast<RegExp::CallOrigin>(
1249           frame_entry<intptr_t>(re_frame, kDirectCall)),
1250       return_address, re_code,
1251       frame_entry_address<Address>(re_frame, kInputString),
1252       frame_entry_address<const byte*>(re_frame, kInputStart),
1253       frame_entry_address<const byte*>(re_frame, kInputEnd));
1254 }
1255 
register_location(int register_index)1256 MemOperand RegExpMacroAssemblerS390::register_location(int register_index) {
1257   DCHECK(register_index < (1 << 30));
1258   if (num_registers_ <= register_index) {
1259     num_registers_ = register_index + 1;
1260   }
1261   return MemOperand(frame_pointer(),
1262                     kRegisterZero - register_index * kSystemPointerSize);
1263 }
1264 
1265 void RegExpMacroAssemblerS390::CheckPosition(int cp_offset,
1266                                              Label* on_outside_input) {
1267   if (cp_offset >= 0) {
1268     __ CmpS64(current_input_offset(), Operand(-cp_offset * char_size()));
1269     BranchOrBacktrack(ge, on_outside_input);
1270   } else {
1271     __ LoadU64(r3, MemOperand(frame_pointer(), kStringStartMinusOne));
1272     __ AddS64(r2, current_input_offset(), Operand(cp_offset * char_size()));
1273     __ CmpS64(r2, r3);
1274     BranchOrBacktrack(le, on_outside_input);
1275   }
1276 }
1277 
1278 void RegExpMacroAssemblerS390::BranchOrBacktrack(Condition condition, Label* to,
1279                                                  CRegister cr) {
1280   if (condition == al) {  // Unconditional.
1281     if (to == nullptr) {
1282       Backtrack();
1283       return;
1284     }
1285     __ b(to);
1286     return;
1287   }
1288   if (to == nullptr) {
1289     __ b(condition, &backtrack_label_);
1290     return;
1291   }
1292   __ b(condition, to);
1293 }
1294 
1295 void RegExpMacroAssemblerS390::SafeCall(Label* to, Condition cond,
1296                                         CRegister cr) {
1297   Label skip;
1298   __ b(NegateCondition(cond), &skip);
1299   __ b(r14, to);
1300   __ bind(&skip);
1301 }
1302 
1303 void RegExpMacroAssemblerS390::SafeReturn() {
1304   __ pop(r14);
1305   __ mov(ip, Operand(masm_->CodeObject()));
1306   __ AddS64(r14, ip);
1307   __ Ret();
1308 }
1309 
1310 void RegExpMacroAssemblerS390::SafeCallTarget(Label* name) {
1311   __ bind(name);
1312   __ CleanseP(r14);
1313   __ mov(r0, r14);
1314   __ mov(ip, Operand(masm_->CodeObject()));
1315   __ SubS64(r0, r0, ip);
1316   __ push(r0);
1317 }
1318 
1319 void RegExpMacroAssemblerS390::Push(Register source) {
1320   DCHECK(source != backtrack_stackpointer());
1321   __ lay(backtrack_stackpointer(),
1322          MemOperand(backtrack_stackpointer(), -kSystemPointerSize));
1323   __ StoreU64(source, MemOperand(backtrack_stackpointer()));
1324 }
1325 
1326 void RegExpMacroAssemblerS390::Pop(Register target) {
1327   DCHECK(target != backtrack_stackpointer());
1328   __ LoadU64(target, MemOperand(backtrack_stackpointer()));
1329   __ la(backtrack_stackpointer(),
1330         MemOperand(backtrack_stackpointer(), kSystemPointerSize));
1331 }
1332 
1333 void RegExpMacroAssemblerS390::CheckPreemption() {
1334   // Check for preemption.
1335   ExternalReference stack_limit =
1336       ExternalReference::address_of_jslimit(isolate());
1337   __ mov(r2, Operand(stack_limit));
1338   __ CmpU64(sp, MemOperand(r2));
1339   SafeCall(&check_preempt_label_, le);
1340 }
1341 
1342 void RegExpMacroAssemblerS390::CheckStackLimit() {
1343   ExternalReference stack_limit =
1344       ExternalReference::address_of_regexp_stack_limit_address(isolate());
1345   __ mov(r2, Operand(stack_limit));
1346   __ CmpU64(backtrack_stackpointer(), MemOperand(r2));
1347   SafeCall(&stack_overflow_label_, le);
1348 }
1349 
1350 void RegExpMacroAssemblerS390::CallCFunctionUsingStub(
1351     ExternalReference function, int num_arguments) {
1352   // Must pass all arguments in registers. The stub pushes on the stack.
1353   DCHECK_GE(8, num_arguments);
1354   __ mov(code_pointer(), Operand(function));
1355   Label ret;
1356   __ larl(r14, &ret);
1357   __ StoreU64(r14, MemOperand(sp, kStackFrameRASlot * kSystemPointerSize));
1358   __ b(code_pointer());
1359   __ bind(&ret);
1360   if (base::OS::ActivationFrameAlignment() > kSystemPointerSize) {
1361     __ LoadU64(
1362         sp, MemOperand(sp, (kNumRequiredStackFrameSlots * kSystemPointerSize)));
1363   } else {
1364     __ la(sp,
1365           MemOperand(sp, (kNumRequiredStackFrameSlots * kSystemPointerSize)));
1366   }
1367   __ mov(code_pointer(), Operand(masm_->CodeObject()));
1368 }
1369 
1370 
LoadCurrentCharacterUnchecked(int cp_offset, int characters)1371 void RegExpMacroAssemblerS390::LoadCurrentCharacterUnchecked(int cp_offset,
1372                                                              int characters) {
1373   if (mode_ == LATIN1) {
1374     // using load reverse for big-endian platforms
1375     if (characters == 4) {
1376       __ LoadU32LE(current_character(),
1377                    MemOperand(current_input_offset(), end_of_input_address(),
1378                               cp_offset * char_size()));
1379     } else if (characters == 2) {
1380       __ LoadU16LE(current_character(),
1381                    MemOperand(current_input_offset(), end_of_input_address(),
1382                               cp_offset * char_size()));
1383     } else {
1384       DCHECK_EQ(1, characters);
1385       __ LoadU8(current_character(),
1386                 MemOperand(current_input_offset(), end_of_input_address(),
1387                            cp_offset * char_size()));
1388     }
1389   } else {
1390     DCHECK(mode_ == UC16);
1391     if (characters == 2) {
1392       __ LoadU32(current_character(),
1393                 MemOperand(current_input_offset(), end_of_input_address(),
1394                            cp_offset * char_size()));
1395 #if !V8_TARGET_LITTLE_ENDIAN
1396       // need to swap the order of the characters for big-endian platforms
1397       __ rll(current_character(), current_character(), Operand(16));
1398 #endif
1399     } else {
1400       DCHECK_EQ(1, characters);
1401       __ LoadU16(
1402           current_character(),
1403                 MemOperand(current_input_offset(), end_of_input_address(),
1404                            cp_offset * char_size()));
1405     }
1406   }
1407 }
1408 
1409 #undef __
1410 
1411 }  // namespace internal
1412 }  // namespace v8
1413 
1414 #endif  // V8_TARGET_ARCH_S390
1415