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