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