regexp-macro-assembler-s390.cc 46.4 KB
Newer Older
jyan's avatar
jyan committed
1 2 3 4
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
#include "src/init/v8.h"
jyan's avatar
jyan committed
6 7 8 9

#if V8_TARGET_ARCH_S390

#include "src/base/bits.h"
10 11
#include "src/codegen/assembler-inl.h"
#include "src/codegen/macro-assembler.h"
12
#include "src/logging/log.h"
jyan's avatar
jyan committed
13 14
#include "src/regexp/regexp-macro-assembler.h"
#include "src/regexp/regexp-stack.h"
15
#include "src/regexp/s390/regexp-macro-assembler-s390.h"
16
#include "src/snapshot/embedded/embedded-data.h"
17
#include "src/strings/unicode.h"
jyan's avatar
jyan committed
18 19 20 21 22 23 24 25

namespace v8 {
namespace internal {

/*
 * This assembler uses the following register assignment convention
 * - r6: Temporarily stores the index of capture start after a matching pass
 *        for a global regexp.
26
 * - r7: Pointer to current Code object including heap object tag.
jyan's avatar
jyan committed
27 28 29 30 31 32 33 34 35 36 37 38 39 40
 * - r8: Current position in input, as negative offset from end of string.
 *        Please notice that this is the byte offset, not the character offset!
 * - r9: Currently loaded character. Must be loaded using
 *        LoadCurrentCharacter before using any of the dispatch methods.
 * - r13: Points to tip of backtrack stack
 * - r10: End of input (points to byte after last character in input).
 * - r11: Frame pointer. Used to access arguments, local variables and
 *         RegExp registers.
 * - r12: IP register, used by assembler. Very volatile.
 * - r15/sp : Points to tip of C stack.
 *
 * The remaining registers are free for computations.
 * Each call to a public method should retain this convention.
 *
41 42 43 44
 * The stack will have the following structure
 *  - fp[112]  Address regexp     (address of the JSRegExp object; unused in
 *                                native code, passed to match signature of
 *                                the interpreter)
45
 *  - fp[108] Isolate* isolate   (address of the current isolate)
jyan's avatar
jyan committed
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
 *  - fp[104] direct_call        (if 1, direct call from JavaScript code,
 *                                if 0, call through the runtime system).
 *  - fp[100] stack_area_base    (high end of the memory area to use as
 *                                backtracking stack).
 *  - fp[96]  capture array size (may fit multiple sets of matches)
 *  - fp[0..96] zLinux ABI register saving area
 *  --- sp when called ---
 *  --- frame pointer ----
 *  - fp[-4]  direct_call        (if 1, direct call from JavaScript code,
 *                                if 0, call through the runtime system).
 *  - fp[-8]  stack_area_base    (high end of the memory area to use as
 *                                backtracking stack).
 *  - fp[-12] capture array size (may fit multiple sets of matches)
 *  - fp[-16] int* capture_array (int[num_saved_registers_], for output).
 *  - fp[-20] end of input       (address of end of string).
 *  - fp[-24] start of input     (address of first character in string).
 *  - fp[-28] start index        (character index of start).
 *  - fp[-32] void* input_string (location of a handle containing the string).
 *  - fp[-36] success counter    (only for global regexps to count matches).
 *  - fp[-40] Offset of location before start of input (effectively character
 *            string start - 1). Used to initialize capture registers to a
 *            non-position.
 *  - fp[-44] At start (if 1, we are starting at the start of the
 *    string, otherwise 0)
 *  - fp[-48] register 0         (Only positions must be stored in the first
 *  -         register 1          num_saved_registers_ registers)
 *  -         ...
 *  -         register num_registers-1
 *  --- sp ---
 *
 * The first num_saved_registers_ registers are initialized to point to
 * "character -1" in the string (i.e., char_size() bytes before the first
 * character of the string). The remaining registers start out as garbage.
 *
 * The data up to the return address must be placed there by the calling
 * code and the remaining arguments are passed in registers, e.g. by calling the
 * code entry as cast to a function with the signature:
83
 * int (*match)(String input_string,
jyan's avatar
jyan committed
84 85 86 87
 *              int start_index,
 *              Address start,
 *              Address end,
 *              int* capture_output_array,
88
 *              int num_capture_registers,
jyan's avatar
jyan committed
89
 *              byte* stack_area_base,
90
 *              bool direct_call = false,
91 92
 *              Isolate* isolate,
 *              Address regexp);
jyan's avatar
jyan committed
93
 * The call is performed by NativeRegExpMacroAssembler::Execute()
94
 * (in regexp-macro-assembler.cc) via the GeneratedCode wrapper.
jyan's avatar
jyan committed
95 96 97 98
 */

#define __ ACCESS_MASM(masm_)

99 100
const int RegExpMacroAssemblerS390::kRegExpCodeSize;

jyan's avatar
jyan committed
101 102 103 104
RegExpMacroAssemblerS390::RegExpMacroAssemblerS390(Isolate* isolate, Zone* zone,
                                                   Mode mode,
                                                   int registers_to_save)
    : NativeRegExpMacroAssembler(isolate, zone),
105 106
      masm_(new MacroAssembler(isolate, CodeObjectRequired::kYes,
                               NewAssemblerBuffer(kRegExpCodeSize))),
jyan's avatar
jyan committed
107 108 109 110 111 112 113 114 115
      mode_(mode),
      num_registers_(registers_to_save),
      num_saved_registers_(registers_to_save),
      entry_label_(),
      start_label_(),
      success_label_(),
      backtrack_label_(),
      exit_label_(),
      internal_failure_label_() {
116 117
  masm_->set_root_array_available(false);

jyan's avatar
jyan committed
118 119 120 121 122 123
  DCHECK_EQ(0, registers_to_save % 2);

  __ b(&entry_label_);  // We'll write the entry code later.
  // If the code gets too big or corrupted, an internal exception will be
  // raised, and we will exit right away.
  __ bind(&internal_failure_label_);
124
  __ mov(r2, Operand(FAILURE));
jyan's avatar
jyan committed
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
  __ Ret();
  __ bind(&start_label_);  // And then continue from here.
}

RegExpMacroAssemblerS390::~RegExpMacroAssemblerS390() {
  delete masm_;
  // Unuse labels in case we throw away the assembler without calling GetCode.
  entry_label_.Unuse();
  start_label_.Unuse();
  success_label_.Unuse();
  backtrack_label_.Unuse();
  exit_label_.Unuse();
  check_preempt_label_.Unuse();
  stack_overflow_label_.Unuse();
  internal_failure_label_.Unuse();
140
  fallback_label_.Unuse();
jyan's avatar
jyan committed
141 142 143 144 145 146 147 148
}

int RegExpMacroAssemblerS390::stack_limit_slack() {
  return RegExpStack::kStackLimitSlack;
}

void RegExpMacroAssemblerS390::AdvanceCurrentPosition(int by) {
  if (by != 0) {
149
    __ AddS64(current_input_offset(), Operand(by * char_size()));
jyan's avatar
jyan committed
150 151 152 153
  }
}

void RegExpMacroAssemblerS390::AdvanceRegister(int reg, int by) {
154 155
  DCHECK_LE(0, reg);
  DCHECK_GT(num_registers_, reg);
jyan's avatar
jyan committed
156 157
  if (by != 0) {
    if (CpuFeatures::IsSupported(GENERAL_INSTR_EXT) && is_int8(by)) {
158
      __ agsi(register_location(reg), Operand(by));
jyan's avatar
jyan committed
159
    } else {
160
      __ LoadU64(r2, register_location(reg), r0);
jyan's avatar
jyan committed
161
      __ mov(r0, Operand(by));
162
      __ agr(r2, r0);
163
      __ StoreU64(r2, register_location(reg));
jyan's avatar
jyan committed
164 165 166 167 168 169
    }
  }
}

void RegExpMacroAssemblerS390::Backtrack() {
  CheckPreemption();
170 171
  if (has_backtrack_limit()) {
    Label next;
172
    __ LoadU64(r2, MemOperand(frame_pointer(), kBacktrackCount), r0);
173
    __ AddS64(r2, r2, Operand(1));
174
    __ StoreU64(r2, MemOperand(frame_pointer(), kBacktrackCount), r0);
175
    __ CmpU64(r2, Operand(backtrack_limit()));
176 177
    __ bne(&next);

178 179 180 181 182 183 184
    // Backtrack limit exceeded.
    if (can_fallback()) {
      __ jmp(&fallback_label_);
    } else {
      // Can't fallback, so we treat it as a failed match.
      Fail();
    }
185 186 187

    __ bind(&next);
  }
188
  // Pop Code offset from backtrack stack, add Code and jump to location.
jyan's avatar
jyan committed
189
  Pop(r2);
190
  __ AddS64(r2, code_pointer());
jyan's avatar
jyan committed
191 192 193 194 195 196
  __ b(r2);
}

void RegExpMacroAssemblerS390::Bind(Label* label) { __ bind(label); }

void RegExpMacroAssemblerS390::CheckCharacter(uint32_t c, Label* on_equal) {
197
  __ CmpU64(current_character(), Operand(c));
jyan's avatar
jyan committed
198 199 200 201
  BranchOrBacktrack(eq, on_equal);
}

void RegExpMacroAssemblerS390::CheckCharacterGT(uc16 limit, Label* on_greater) {
202
  __ CmpU64(current_character(), Operand(limit));
jyan's avatar
jyan committed
203 204 205
  BranchOrBacktrack(gt, on_greater);
}

206
void RegExpMacroAssemblerS390::CheckAtStart(int cp_offset, Label* on_at_start) {
207
  __ LoadU64(r3, MemOperand(frame_pointer(), kStringStartMinusOne));
208 209
  __ AddS64(r2, current_input_offset(),
            Operand(-char_size() + cp_offset * char_size()));
210
  __ CmpS64(r2, r3);
jyan's avatar
jyan committed
211 212 213 214 215
  BranchOrBacktrack(eq, on_at_start);
}

void RegExpMacroAssemblerS390::CheckNotAtStart(int cp_offset,
                                               Label* on_not_at_start) {
216
  __ LoadU64(r3, MemOperand(frame_pointer(), kStringStartMinusOne));
217 218
  __ AddS64(r2, current_input_offset(),
            Operand(-char_size() + cp_offset * char_size()));
219
  __ CmpS64(r2, r3);
jyan's avatar
jyan committed
220 221 222 223
  BranchOrBacktrack(ne, on_not_at_start);
}

void RegExpMacroAssemblerS390::CheckCharacterLT(uc16 limit, Label* on_less) {
224
  __ CmpU64(current_character(), Operand(limit));
jyan's avatar
jyan committed
225 226 227 228 229
  BranchOrBacktrack(lt, on_less);
}

void RegExpMacroAssemblerS390::CheckGreedyLoop(Label* on_equal) {
  Label backtrack_non_equal;
230
  __ CmpS64(current_input_offset(), MemOperand(backtrack_stackpointer(), 0));
jyan's avatar
jyan committed
231
  __ bne(&backtrack_non_equal);
232
  __ AddS64(backtrack_stackpointer(), Operand(kSystemPointerSize));
jyan's avatar
jyan committed
233 234 235 236 237 238

  BranchOrBacktrack(al, on_equal);
  __ bind(&backtrack_non_equal);
}

void RegExpMacroAssemblerS390::CheckNotBackReferenceIgnoreCase(
239
    int start_reg, bool read_backward, bool unicode, Label* on_no_match) {
jyan's avatar
jyan committed
240
  Label fallthrough;
241 242 243
  __ LoadU64(r2, register_location(start_reg));      // Index of start of
                                                     // capture
  __ LoadU64(r3, register_location(start_reg + 1));  // Index of end
244
  __ SubS64(r3, r3, r2);
jyan's avatar
jyan committed
245 246 247 248 249 250 251 252

  // At this point, the capture registers are either both set or both cleared.
  // If the capture length is zero, then the capture is either empty or cleared.
  // Fall through in both cases.
  __ beq(&fallthrough);

  // Check that there are enough characters left in the input.
  if (read_backward) {
253
    __ LoadU64(r5, MemOperand(frame_pointer(), kStringStartMinusOne));
254
    __ AddS64(r5, r5, r3);
255
    __ CmpS64(current_input_offset(), r5);
jyan's avatar
jyan committed
256 257
    BranchOrBacktrack(le, on_no_match);
  } else {
258
    __ AddS64(r0, r3, current_input_offset());
jyan's avatar
jyan committed
259 260 261 262 263 264 265 266 267 268
    BranchOrBacktrack(gt, on_no_match);
  }

  if (mode_ == LATIN1) {
    Label success;
    Label fail;
    Label loop_check;

    // r2 - offset of start of capture
    // r3 - length of capture
269 270
    __ AddS64(r2, end_of_input_address());
    __ AddS64(r4, current_input_offset(), end_of_input_address());
jyan's avatar
jyan committed
271
    if (read_backward) {
272
      __ SubS64(r4, r4, r3);  // Offset by length when matching backwards.
jyan's avatar
jyan committed
273 274 275 276 277 278 279 280 281
    }
    __ mov(r1, Operand::Zero());

    // r1 - Loop index
    // r2 - Address of start of capture.
    // r4 - Address of current input position.

    Label loop;
    __ bind(&loop);
282 283
    __ LoadU8(r5, MemOperand(r2, r1));
    __ LoadU8(r6, MemOperand(r4, r1));
jyan's avatar
jyan committed
284

285
    __ CmpS64(r6, r5);
jyan's avatar
jyan committed
286 287 288 289 290
    __ beq(&loop_check);

    // Mismatch, try case-insensitive match (converting letters to lower-case).
    __ Or(r5, Operand(0x20));  // Convert capture character to lower-case.
    __ Or(r6, Operand(0x20));  // Also convert input character.
291
    __ CmpS64(r6, r5);
jyan's avatar
jyan committed
292
    __ bne(&fail);
293
    __ SubS64(r5, Operand('a'));
294
    __ CmpU64(r5, Operand('z' - 'a'));       // Is r5 a lowercase letter?
jyan's avatar
jyan committed
295 296
    __ ble(&loop_check);                     // In range 'a'-'z'.
    // Latin-1: Check for values in range [224,254] but not 247.
297
    __ SubS64(r5, Operand(224 - 'a'));
298
    __ CmpU64(r5, Operand(254 - 224));
jyan's avatar
jyan committed
299
    __ bgt(&fail);                           // Weren't Latin-1 letters.
300
    __ CmpU64(r5, Operand(247 - 224));       // Check for 247.
jyan's avatar
jyan committed
301 302 303 304
    __ beq(&fail);

    __ bind(&loop_check);
    __ la(r1, MemOperand(r1, char_size()));
305
    __ CmpS64(r1, r3);
jyan's avatar
jyan committed
306 307 308 309 310 311 312 313
    __ blt(&loop);
    __ b(&success);

    __ bind(&fail);
    BranchOrBacktrack(al, on_no_match);

    __ bind(&success);
    // Compute new value of character position after the matched part.
314
    __ SubS64(current_input_offset(), r4, end_of_input_address());
jyan's avatar
jyan committed
315
    if (read_backward) {
316 317 318 319
      __ LoadU64(r2,
                 register_location(start_reg));  // Index of start of capture
      __ LoadU64(r3,
                 register_location(start_reg + 1));  // Index of end of capture
320 321
      __ AddS64(current_input_offset(), current_input_offset(), r2);
      __ SubS64(current_input_offset(), current_input_offset(), r3);
jyan's avatar
jyan committed
322
    }
323
    __ AddS64(current_input_offset(), r1);
jyan's avatar
jyan committed
324 325 326 327 328 329 330 331 332 333 334 335 336
  } else {
    DCHECK(mode_ == UC16);
    int argument_count = 4;
    __ PrepareCallCFunction(argument_count, r4);

    // r2 - offset of start of capture
    // r3 - length of capture

    // Put arguments into arguments registers.
    // Parameters are
    //   r2: Address byte_offset1 - Address captured substring's start.
    //   r3: Address byte_offset2 - Address of current character position.
    //   r4: size_t byte_length - length of capture in bytes(!)
337
    //   r5: Isolate* isolate.
jyan's avatar
jyan committed
338 339

    // Address of start of capture.
340
    __ AddS64(r2, end_of_input_address());
jyan's avatar
jyan committed
341
    // Length of capture.
342
    __ mov(r4, r3);
jyan's avatar
jyan committed
343
    // Save length in callee-save register for use on return.
344
    __ mov(r6, r3);
jyan's avatar
jyan committed
345
    // Address of current input position.
346
    __ AddS64(r3, current_input_offset(), end_of_input_address());
jyan's avatar
jyan committed
347
    if (read_backward) {
348
      __ SubS64(r3, r3, r6);
jyan's avatar
jyan committed
349 350
    }
// Isolate.
351
    __ mov(r5, Operand(ExternalReference::isolate_address(isolate())));
jyan's avatar
jyan committed
352 353 354 355

    {
      AllowExternalCallThatCantCauseGC scope(masm_);
      ExternalReference function =
356 357 358 359
          unicode ? ExternalReference::re_case_insensitive_compare_unicode(
                        isolate())
                  : ExternalReference::re_case_insensitive_compare_non_unicode(
                        isolate());
jyan's avatar
jyan committed
360 361 362 363
      __ CallCFunction(function, argument_count);
    }

    // Check if function returned non-zero for success or zero for failure.
364
    __ CmpS64(r2, Operand::Zero());
jyan's avatar
jyan committed
365 366 367 368
    BranchOrBacktrack(eq, on_no_match);

    // On success, advance position by length of capture.
    if (read_backward) {
369
      __ SubS64(current_input_offset(), current_input_offset(), r6);
jyan's avatar
jyan committed
370
    } else {
371
      __ AddS64(current_input_offset(), current_input_offset(), r6);
jyan's avatar
jyan committed
372 373 374 375 376 377 378 379 380 381 382 383
    }
  }

  __ bind(&fallthrough);
}

void RegExpMacroAssemblerS390::CheckNotBackReference(int start_reg,
                                                     bool read_backward,
                                                     Label* on_no_match) {
  Label fallthrough;

  // Find length of back-referenced capture.
384 385
  __ LoadU64(r2, register_location(start_reg));
  __ LoadU64(r3, register_location(start_reg + 1));
386
  __ SubS64(r3, r3, r2);  // Length to check.
jyan's avatar
jyan committed
387 388 389 390 391 392 393 394

  // At this point, the capture registers are either both set or both cleared.
  // If the capture length is zero, then the capture is either empty or cleared.
  // Fall through in both cases.
  __ beq(&fallthrough);

  // Check that there are enough characters left in the input.
  if (read_backward) {
395
    __ LoadU64(r5, MemOperand(frame_pointer(), kStringStartMinusOne));
396
    __ AddS64(r5, r5, r3);
397
    __ CmpS64(current_input_offset(), r5);
398
    BranchOrBacktrack(le, on_no_match);
jyan's avatar
jyan committed
399
  } else {
400
    __ AddS64(r0, r3, current_input_offset());
jyan's avatar
jyan committed
401 402 403 404 405 406 407 408
    BranchOrBacktrack(gt, on_no_match, cr0);
  }

  // r2 - offset of start of capture
  // r3 - length of capture
  __ la(r2, MemOperand(r2, end_of_input_address()));
  __ la(r4, MemOperand(current_input_offset(), end_of_input_address()));
  if (read_backward) {
409
    __ SubS64(r4, r4, r3);  // Offset by length when matching backwards.
jyan's avatar
jyan committed
410 411 412 413 414 415
  }
  __ mov(r1, Operand::Zero());

  Label loop;
  __ bind(&loop);
  if (mode_ == LATIN1) {
416 417
    __ LoadU8(r5, MemOperand(r2, r1));
    __ LoadU8(r6, MemOperand(r4, r1));
jyan's avatar
jyan committed
418 419
  } else {
    DCHECK(mode_ == UC16);
420 421
    __ LoadU16(r5, MemOperand(r2, r1));
    __ LoadU16(r6, MemOperand(r4, r1));
jyan's avatar
jyan committed
422 423
  }
  __ la(r1, MemOperand(r1, char_size()));
424
  __ CmpS64(r5, r6);
jyan's avatar
jyan committed
425
  BranchOrBacktrack(ne, on_no_match);
426
  __ CmpS64(r1, r3);
jyan's avatar
jyan committed
427 428 429
  __ blt(&loop);

  // Move current character position to position after match.
430
  __ SubS64(current_input_offset(), r4, end_of_input_address());
jyan's avatar
jyan committed
431
  if (read_backward) {
432 433 434
    __ LoadU64(r2, register_location(start_reg));  // Index of start of capture
    __ LoadU64(r3,
               register_location(start_reg + 1));  // Index of end of capture
435 436
    __ AddS64(current_input_offset(), current_input_offset(), r2);
    __ SubS64(current_input_offset(), current_input_offset(), r3);
jyan's avatar
jyan committed
437
  }
438
  __ AddS64(current_input_offset(), r1);
jyan's avatar
jyan committed
439 440 441 442 443 444

  __ bind(&fallthrough);
}

void RegExpMacroAssemblerS390::CheckNotCharacter(unsigned c,
                                                 Label* on_not_equal) {
445
  __ CmpU64(current_character(), Operand(c));
jyan's avatar
jyan committed
446 447 448 449 450 451 452
  BranchOrBacktrack(ne, on_not_equal);
}

void RegExpMacroAssemblerS390::CheckCharacterAfterAnd(uint32_t c, uint32_t mask,
                                                      Label* on_equal) {
  __ AndP(r2, current_character(), Operand(mask));
  if (c != 0) {
453
    __ CmpU64(r2, Operand(c));
jyan's avatar
jyan committed
454 455 456 457 458 459 460 461 462
  }
  BranchOrBacktrack(eq, on_equal);
}

void RegExpMacroAssemblerS390::CheckNotCharacterAfterAnd(unsigned c,
                                                         unsigned mask,
                                                         Label* on_not_equal) {
  __ AndP(r2, current_character(), Operand(mask));
  if (c != 0) {
463
    __ CmpU64(r2, Operand(c));
jyan's avatar
jyan committed
464 465 466 467 468 469
  }
  BranchOrBacktrack(ne, on_not_equal);
}

void RegExpMacroAssemblerS390::CheckNotCharacterAfterMinusAnd(
    uc16 c, uc16 minus, uc16 mask, Label* on_not_equal) {
470
  DCHECK_GT(String::kMaxUtf16CodeUnit, minus);
jyan's avatar
jyan committed
471 472 473
  __ lay(r2, MemOperand(current_character(), -minus));
  __ And(r2, Operand(mask));
  if (c != 0) {
474
    __ CmpU64(r2, Operand(c));
jyan's avatar
jyan committed
475 476 477 478 479 480 481
  }
  BranchOrBacktrack(ne, on_not_equal);
}

void RegExpMacroAssemblerS390::CheckCharacterInRange(uc16 from, uc16 to,
                                                     Label* on_in_range) {
  __ lay(r2, MemOperand(current_character(), -from));
482
  __ CmpU64(r2, Operand(to - from));
jyan's avatar
jyan committed
483 484 485 486 487 488
  BranchOrBacktrack(le, on_in_range);  // Unsigned lower-or-same condition.
}

void RegExpMacroAssemblerS390::CheckCharacterNotInRange(
    uc16 from, uc16 to, Label* on_not_in_range) {
  __ lay(r2, MemOperand(current_character(), -from));
489
  __ CmpU64(r2, Operand(to - from));
jyan's avatar
jyan committed
490 491 492 493 494 495 496 497 498 499 500
  BranchOrBacktrack(gt, on_not_in_range);  // Unsigned higher condition.
}

void RegExpMacroAssemblerS390::CheckBitInTable(Handle<ByteArray> table,
                                               Label* on_bit_set) {
  __ mov(r2, Operand(table));
  Register index = current_character();
  if (mode_ != LATIN1 || kTableMask != String::kMaxOneByteCharCode) {
    __ AndP(r3, current_character(), Operand(kTableSize - 1));
    index = r3;
  }
501
  __ LoadU8(r2,
jyan's avatar
jyan committed
502
            MemOperand(r2, index, (ByteArray::kHeaderSize - kHeapObjectTag)));
503
  __ CmpS64(r2, Operand::Zero());
jyan's avatar
jyan committed
504 505 506 507 508 509 510 511 512 513 514 515 516
  BranchOrBacktrack(ne, on_bit_set);
}

bool RegExpMacroAssemblerS390::CheckSpecialCharacterClass(uc16 type,
                                                          Label* on_no_match) {
  // Range checks (c in min..max) are generally implemented by an unsigned
  // (c - min) <= (max - min) check
  switch (type) {
    case 's':
      // Match space-characters
      if (mode_ == LATIN1) {
        // One byte space characters are '\t'..'\r', ' ' and \u00a0.
        Label success;
517
        __ CmpS64(current_character(), Operand(' '));
jyan's avatar
jyan committed
518
        __ beq(&success);
519
        // Check range 0x09..0x0D
520
        __ SubS64(r2, current_character(), Operand('\t'));
521
        __ CmpU64(r2, Operand('\r' - '\t'));
jyan's avatar
jyan committed
522 523
        __ ble(&success);
        // \u00a0 (NBSP).
524
        __ CmpU64(r2, Operand(0x00A0 - '\t'));
jyan's avatar
jyan committed
525 526 527 528 529 530 531 532 533 534
        BranchOrBacktrack(ne, on_no_match);
        __ bind(&success);
        return true;
      }
      return false;
    case 'S':
      // The emitted code for generic character classes is good enough.
      return false;
    case 'd':
      // Match ASCII digits ('0'..'9')
535
      __ SubS64(r2, current_character(), Operand('0'));
536
      __ CmpU64(r2, Operand('9' - '0'));
jyan's avatar
jyan committed
537 538 539 540
      BranchOrBacktrack(gt, on_no_match);
      return true;
    case 'D':
      // Match non ASCII-digits
541
      __ SubS64(r2, current_character(), Operand('0'));
542
      __ CmpU64(r2, Operand('9' - '0'));
jyan's avatar
jyan committed
543 544 545
      BranchOrBacktrack(le, on_no_match);
      return true;
    case '.': {
546
      // Match non-newlines (not 0x0A('\n'), 0x0D('\r'), 0x2028 and 0x2029)
jyan's avatar
jyan committed
547
      __ XorP(r2, current_character(), Operand(0x01));
548
      // See if current character is '\n'^1 or '\r'^1, i.e., 0x0B or 0x0C
549
      __ SubS64(r2, Operand(0x0B));
550
      __ CmpU64(r2, Operand(0x0C - 0x0B));
jyan's avatar
jyan committed
551 552 553
      BranchOrBacktrack(le, on_no_match);
      if (mode_ == UC16) {
        // Compare original value to 0x2028 and 0x2029, using the already
554 555
        // computed (current_char ^ 0x01 - 0x0B). I.e., check for
        // 0x201D (0x2028 - 0x0B) or 0x201E.
556
        __ SubS64(r2, Operand(0x2028 - 0x0B));
557
        __ CmpU64(r2, Operand(1));
jyan's avatar
jyan committed
558 559 560 561 562
        BranchOrBacktrack(le, on_no_match);
      }
      return true;
    }
    case 'n': {
563
      // Match newlines (0x0A('\n'), 0x0D('\r'), 0x2028 and 0x2029)
jyan's avatar
jyan committed
564
      __ XorP(r2, current_character(), Operand(0x01));
565
      // See if current character is '\n'^1 or '\r'^1, i.e., 0x0B or 0x0C
566
      __ SubS64(r2, Operand(0x0B));
567
      __ CmpU64(r2, Operand(0x0C - 0x0B));
jyan's avatar
jyan committed
568 569 570 571 572 573
      if (mode_ == LATIN1) {
        BranchOrBacktrack(gt, on_no_match);
      } else {
        Label done;
        __ ble(&done);
        // Compare original value to 0x2028 and 0x2029, using the already
574 575
        // computed (current_char ^ 0x01 - 0x0B). I.e., check for
        // 0x201D (0x2028 - 0x0B) or 0x201E.
576
        __ SubS64(r2, Operand(0x2028 - 0x0B));
577
        __ CmpU64(r2, Operand(1));
jyan's avatar
jyan committed
578 579 580 581 582 583 584 585
        BranchOrBacktrack(gt, on_no_match);
        __ bind(&done);
      }
      return true;
    }
    case 'w': {
      if (mode_ != LATIN1) {
        // Table is 1256 entries, so all LATIN1 characters can be tested.
586
        __ CmpS64(current_character(), Operand('z'));
jyan's avatar
jyan committed
587 588
        BranchOrBacktrack(gt, on_no_match);
      }
589 590
      ExternalReference map =
          ExternalReference::re_word_character_map(isolate());
jyan's avatar
jyan committed
591
      __ mov(r2, Operand(map));
592
      __ LoadU8(r2, MemOperand(r2, current_character()));
593
      __ CmpU64(r2, Operand::Zero());
jyan's avatar
jyan committed
594 595 596 597 598 599 600
      BranchOrBacktrack(eq, on_no_match);
      return true;
    }
    case 'W': {
      Label done;
      if (mode_ != LATIN1) {
        // Table is 256 entries, so all LATIN characters can be tested.
601
        __ CmpU64(current_character(), Operand('z'));
jyan's avatar
jyan committed
602 603
        __ bgt(&done);
      }
604 605
      ExternalReference map =
          ExternalReference::re_word_character_map(isolate());
jyan's avatar
jyan committed
606
      __ mov(r2, Operand(map));
607
      __ LoadU8(r2, MemOperand(r2, current_character()));
608
      __ CmpU64(r2, Operand::Zero());
jyan's avatar
jyan committed
609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624
      BranchOrBacktrack(ne, on_no_match);
      if (mode_ != LATIN1) {
        __ bind(&done);
      }
      return true;
    }
    case '*':
      // Match any character.
      return true;
    // No custom implementation (yet): s(UC16), S(UC16).
    default:
      return false;
  }
}

void RegExpMacroAssemblerS390::Fail() {
625
  __ mov(r2, Operand(FAILURE));
jyan's avatar
jyan committed
626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660
  __ b(&exit_label_);
}

Handle<HeapObject> RegExpMacroAssemblerS390::GetCode(Handle<String> source) {
  Label return_r2;

  // Finalize code - write the entry point code now we know how many
  // registers we need.

  // Entry code:
  __ bind(&entry_label_);

  // Tell the system that we have a stack frame.  Because the type
  // is MANUAL, no is generated.
  FrameScope scope(masm_, StackFrame::MANUAL);

  // Ensure register assigments are consistent with callee save mask
  DCHECK(r6.bit() & kRegExpCalleeSaved);
  DCHECK(code_pointer().bit() & kRegExpCalleeSaved);
  DCHECK(current_input_offset().bit() & kRegExpCalleeSaved);
  DCHECK(current_character().bit() & kRegExpCalleeSaved);
  DCHECK(backtrack_stackpointer().bit() & kRegExpCalleeSaved);
  DCHECK(end_of_input_address().bit() & kRegExpCalleeSaved);
  DCHECK(frame_pointer().bit() & kRegExpCalleeSaved);

  // zLinux ABI
  //    Incoming parameters:
  //          r2: input_string
  //          r3: start_index
  //          r4: start addr
  //          r5: end addr
  //          r6: capture output arrray
  //    Requires us to save the callee-preserved registers r6-r13
  //    General convention is to also save r14 (return addr) and
  //    sp/r15 as well in a single STM/STMG
661
  __ StoreMultipleP(r6, sp, MemOperand(sp, 6 * kSystemPointerSize));
jyan's avatar
jyan committed
662 663

  // Load stack parameters from caller stack frame
664 665
  __ LoadMultipleP(
      r7, r9, MemOperand(sp, kStackFrameExtraParamSlot * kSystemPointerSize));
jyan's avatar
jyan committed
666 667 668 669 670 671 672 673 674 675 676 677 678
  // r7 = capture array size
  // r8 = stack area base
  // r9 = direct call

  // Actually emit code to start a new stack frame.
  // Push arguments
  // Save callee-save registers.
  // Start new stack frame.
  // Store link register in existing stack-cell.
  // Order here should correspond to order of offset constants in header file.
  //
  // Set frame pointer in space for it if this is not a direct call
  // from generated code.
679
  __ mov(frame_pointer(), sp);
680
  __ lay(sp, MemOperand(sp, -10 * kSystemPointerSize));
681
  STATIC_ASSERT(kSuccessfulCaptures == kInputString - kSystemPointerSize);
jyan's avatar
jyan committed
682
  __ mov(r1, Operand::Zero());  // success counter
683 684
  STATIC_ASSERT(kStringStartMinusOne ==
                kSuccessfulCaptures - kSystemPointerSize);
685
  __ mov(r0, r1);  // offset of location
jyan's avatar
jyan committed
686
  __ StoreMultipleP(r0, r9, MemOperand(sp, 0));
687 688
  STATIC_ASSERT(kBacktrackCount == kStringStartMinusOne - kSystemPointerSize);
  __ Push(r1);  // The backtrack counter.
jyan's avatar
jyan committed
689 690 691 692 693
  // Check if we have space on the stack for registers.
  Label stack_limit_hit;
  Label stack_ok;

  ExternalReference stack_limit =
694
      ExternalReference::address_of_jslimit(isolate());
jyan's avatar
jyan committed
695
  __ mov(r2, Operand(stack_limit));
696
  __ LoadU64(r2, MemOperand(r2));
697
  __ SubS64(r2, sp, r2);
jyan's avatar
jyan committed
698 699 700 701
  // Handle it if the stack pointer is already below the stack limit.
  __ ble(&stack_limit_hit);
  // Check if there is room for the variable number of registers above
  // the stack limit.
702
  __ CmpU64(r2, Operand(num_registers_ * kSystemPointerSize));
jyan's avatar
jyan committed
703 704 705 706 707 708 709 710
  __ bge(&stack_ok);
  // Exit with OutOfMemory exception. There is not enough space on the stack
  // for our working registers.
  __ mov(r2, Operand(EXCEPTION));
  __ b(&return_r2);

  __ bind(&stack_limit_hit);
  CallCheckStackGuardState(r2);
711
  __ CmpS64(r2, Operand::Zero());
jyan's avatar
jyan committed
712 713 714 715 716 717
  // If returned value is non-zero, we exit with the returned value as result.
  __ bne(&return_r2);

  __ bind(&stack_ok);

  // Allocate space on stack for registers.
718
  __ lay(sp, MemOperand(sp, (-num_registers_ * kSystemPointerSize)));
jyan's avatar
jyan committed
719
  // Load string end.
720
  __ LoadU64(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
jyan's avatar
jyan committed
721
  // Load input start.
722
  __ LoadU64(r4, MemOperand(frame_pointer(), kInputStart));
jyan's avatar
jyan committed
723
  // Find negative length (offset of start relative to end).
724
  __ SubS64(current_input_offset(), r4, end_of_input_address());
725
  __ LoadU64(r3, MemOperand(frame_pointer(), kStartIndex));
jyan's avatar
jyan committed
726 727
  // Set r1 to address of char before start of the input string
  // (effectively string position -1).
728
  __ mov(r1, r4);
729
  __ SubS64(r1, current_input_offset(), Operand(char_size()));
jyan's avatar
jyan committed
730
  if (mode_ == UC16) {
731
    __ ShiftLeftU64(r0, r3, Operand(1));
732
    __ SubS64(r1, r1, r0);
jyan's avatar
jyan committed
733
  } else {
734
    __ SubS64(r1, r1, r3);
jyan's avatar
jyan committed
735 736 737
  }
  // Store this value in a local variable, for use when clearing
  // position registers.
738
  __ StoreU64(r1, MemOperand(frame_pointer(), kStringStartMinusOne));
jyan's avatar
jyan committed
739 740 741 742 743 744

  // Initialize code pointer register
  __ mov(code_pointer(), Operand(masm_->CodeObject()));

  Label load_char_start_regexp, start_regexp;
  // Load newline if index is at start, previous character otherwise.
745
  __ CmpS64(r3, Operand::Zero());
jyan's avatar
jyan committed
746 747 748 749 750 751 752 753 754 755 756 757 758 759 760
  __ bne(&load_char_start_regexp);
  __ mov(current_character(), Operand('\n'));
  __ b(&start_regexp);

  // Global regexp restarts matching here.
  __ bind(&load_char_start_regexp);
  // Load previous char as initial value of current character register.
  LoadCurrentCharacterUnchecked(-1, 1);
  __ bind(&start_regexp);

  // Initialize on-stack registers.
  if (num_saved_registers_ > 0) {  // Always is, if generated from a regexp.
    // Fill saved registers with initial value = start offset - 1
    if (num_saved_registers_ > 8) {
      // One slot beyond address of register 0.
761 762
      __ lay(r3,
             MemOperand(frame_pointer(), kRegisterZero + kSystemPointerSize));
763
      __ mov(r4, Operand(num_saved_registers_));
jyan's avatar
jyan committed
764 765
      Label init_loop;
      __ bind(&init_loop);
766
      __ StoreU64(r1, MemOperand(r3, -kSystemPointerSize));
767
      __ lay(r3, MemOperand(r3, -kSystemPointerSize));
jyan's avatar
jyan committed
768 769 770
      __ BranchOnCount(r4, &init_loop);
    } else {
      for (int i = 0; i < num_saved_registers_; i++) {
771
        __ StoreU64(r1, register_location(i));
jyan's avatar
jyan committed
772 773 774 775 776
      }
    }
  }

  // Initialize backtrack stack pointer.
777 778
  __ LoadU64(backtrack_stackpointer(),
             MemOperand(frame_pointer(), kStackHighEnd));
jyan's avatar
jyan committed
779 780 781 782 783 784 785 786 787

  __ b(&start_label_);

  // Exit code:
  if (success_label_.is_linked()) {
    // Save captures when successful.
    __ bind(&success_label_);
    if (num_saved_registers_ > 0) {
      // copy captures to output
788 789 790
      __ LoadU64(r0, MemOperand(frame_pointer(), kInputStart));
      __ LoadU64(r2, MemOperand(frame_pointer(), kRegisterOutput));
      __ LoadU64(r4, MemOperand(frame_pointer(), kStartIndex));
791
      __ SubS64(r0, end_of_input_address(), r0);
jyan's avatar
jyan committed
792 793
      // r0 is length of input in bytes.
      if (mode_ == UC16) {
794
        __ ShiftRightU64(r0, r0, Operand(1));
jyan's avatar
jyan committed
795 796
      }
      // r0 is length of input in characters.
797
      __ AddS64(r0, r4);
jyan's avatar
jyan committed
798 799 800 801 802 803 804 805
      // r0 is length of string in characters.

      DCHECK_EQ(0, num_saved_registers_ % 2);
      // Always an even number of capture registers. This allows us to
      // unroll the loop once to add an operation between a load of a register
      // and the following use of that register.
      __ lay(r2, MemOperand(r2, num_saved_registers_ * kIntSize));
      for (int i = 0; i < num_saved_registers_;) {
806
        if ((false) && i < num_saved_registers_ - 4) {
jyan's avatar
jyan committed
807 808 809
          // TODO(john.yan): Can be optimized by SIMD instructions
          __ LoadMultipleP(r3, r6, register_location(i + 3));
          if (mode_ == UC16) {
810 811 812 813
            __ ShiftRightS64(r3, r3, Operand(1));
            __ ShiftRightS64(r4, r4, Operand(1));
            __ ShiftRightS64(r5, r5, Operand(1));
            __ ShiftRightS64(r6, r6, Operand(1));
jyan's avatar
jyan committed
814
          }
815 816 817 818
          __ AddS64(r3, r0);
          __ AddS64(r4, r0);
          __ AddS64(r5, r0);
          __ AddS64(r6, r0);
819 820 821 822 823 824 825 826
          __ StoreU32(
              r3, MemOperand(r2, -(num_saved_registers_ - i - 3) * kIntSize));
          __ StoreU32(
              r4, MemOperand(r2, -(num_saved_registers_ - i - 2) * kIntSize));
          __ StoreU32(
              r5, MemOperand(r2, -(num_saved_registers_ - i - 1) * kIntSize));
          __ StoreU32(r6,
                      MemOperand(r2, -(num_saved_registers_ - i) * kIntSize));
jyan's avatar
jyan committed
827 828 829 830
          i += 4;
        } else {
          __ LoadMultipleP(r3, r4, register_location(i + 1));
          if (mode_ == UC16) {
831 832
            __ ShiftRightS64(r3, r3, Operand(1));
            __ ShiftRightS64(r4, r4, Operand(1));
jyan's avatar
jyan committed
833
          }
834 835
          __ AddS64(r3, r0);
          __ AddS64(r4, r0);
836 837 838 839
          __ StoreU32(
              r3, MemOperand(r2, -(num_saved_registers_ - i - 1) * kIntSize));
          __ StoreU32(r4,
                      MemOperand(r2, -(num_saved_registers_ - i) * kIntSize));
jyan's avatar
jyan committed
840 841 842 843 844
          i += 2;
        }
      }
      if (global_with_zero_length_check()) {
        // Keep capture start in r6 for the zero-length check later.
845
        __ LoadU64(r6, register_location(0));
jyan's avatar
jyan committed
846 847 848 849 850
      }
    }

    if (global()) {
      // Restart matching if the regular expression is flagged as global.
851 852 853
      __ LoadU64(r2, MemOperand(frame_pointer(), kSuccessfulCaptures));
      __ LoadU64(r3, MemOperand(frame_pointer(), kNumOutputRegisters));
      __ LoadU64(r4, MemOperand(frame_pointer(), kRegisterOutput));
jyan's avatar
jyan committed
854
      // Increment success counter.
855
      __ AddS64(r2, Operand(1));
856
      __ StoreU64(r2, MemOperand(frame_pointer(), kSuccessfulCaptures));
jyan's avatar
jyan committed
857 858
      // Capture results have been stored, so the number of remaining global
      // output registers is reduced by the number of stored captures.
859
      __ SubS64(r3, Operand(num_saved_registers_));
jyan's avatar
jyan committed
860
      // Check whether we have enough room for another set of capture results.
861
      __ CmpS64(r3, Operand(num_saved_registers_));
jyan's avatar
jyan committed
862 863
      __ blt(&return_r2);

864
      __ StoreU64(r3, MemOperand(frame_pointer(), kNumOutputRegisters));
jyan's avatar
jyan committed
865
      // Advance the location for output.
866
      __ AddS64(r4, Operand(num_saved_registers_ * kIntSize));
867
      __ StoreU64(r4, MemOperand(frame_pointer(), kRegisterOutput));
jyan's avatar
jyan committed
868 869

      // Prepare r2 to initialize registers with its value in the next run.
870
      __ LoadU64(r2, MemOperand(frame_pointer(), kStringStartMinusOne));
jyan's avatar
jyan committed
871 872 873 874

      if (global_with_zero_length_check()) {
        // Special case for zero-length matches.
        // r6: capture start index
875
        __ CmpS64(current_input_offset(), r6);
jyan's avatar
jyan committed
876 877 878
        // Not a zero-length match, restart.
        __ bne(&load_char_start_regexp);
        // Offset from the end is zero if we already reached the end.
879
        __ CmpS64(current_input_offset(), Operand::Zero());
jyan's avatar
jyan committed
880 881 882 883
        __ beq(&exit_label_);
        // Advance current position after a zero-length match.
        Label advance;
        __ bind(&advance);
884
        __ AddS64(current_input_offset(), Operand((mode_ == UC16) ? 2 : 1));
jyan's avatar
jyan committed
885 886 887 888 889
        if (global_unicode()) CheckNotInSurrogatePair(0, &advance);
      }

      __ b(&load_char_start_regexp);
    } else {
890
      __ mov(r2, Operand(SUCCESS));
jyan's avatar
jyan committed
891 892 893 894 895 896
    }
  }

  // Exit and return r2
  __ bind(&exit_label_);
  if (global()) {
897
    __ LoadU64(r2, MemOperand(frame_pointer(), kSuccessfulCaptures));
jyan's avatar
jyan committed
898 899 900 901
  }

  __ bind(&return_r2);
  // Skip sp past regexp registers and local variables..
902
  __ mov(sp, frame_pointer());
jyan's avatar
jyan committed
903
  // Restore registers r6..r15.
904
  __ LoadMultipleP(r6, sp, MemOperand(sp, 6 * kSystemPointerSize));
jyan's avatar
jyan committed
905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920

  __ b(r14);

  // Backtrack code (branch target for conditional backtracks).
  if (backtrack_label_.is_linked()) {
    __ bind(&backtrack_label_);
    Backtrack();
  }

  Label exit_with_exception;

  // Preempt-code
  if (check_preempt_label_.is_linked()) {
    SafeCallTarget(&check_preempt_label_);

    CallCheckStackGuardState(r2);
921
    __ CmpS64(r2, Operand::Zero());
jyan's avatar
jyan committed
922 923 924 925 926
    // If returning non-zero, we should end execution with the given
    // result as return value.
    __ bne(&return_r2);

    // String might have moved: Reload end of string from frame.
927
    __ LoadU64(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
jyan's avatar
jyan committed
928 929 930 931 932 933 934 935 936 937 938
    SafeReturn();
  }

  // Backtrack stack overflow code.
  if (stack_overflow_label_.is_linked()) {
    SafeCallTarget(&stack_overflow_label_);
    // Reached if the backtrack-stack limit has been hit.

    // Call GrowStack(backtrack_stackpointer(), &stack_base)
    static const int num_arguments = 3;
    __ PrepareCallCFunction(num_arguments, r2);
939
    __ mov(r2, backtrack_stackpointer());
940
    __ AddS64(r3, frame_pointer(), Operand(kStackHighEnd));
jyan's avatar
jyan committed
941 942 943
    __ mov(r4, Operand(ExternalReference::isolate_address(isolate())));
    ExternalReference grow_stack = ExternalReference::re_grow_stack(isolate());
    __ CallCFunction(grow_stack, num_arguments);
944
    // If return nullptr, we have failed to grow the stack, and
jyan's avatar
jyan committed
945
    // must exit with a stack-overflow exception.
946
    __ CmpS64(r2, Operand::Zero());
jyan's avatar
jyan committed
947 948
    __ beq(&exit_with_exception);
    // Otherwise use return value as new stack pointer.
949
    __ mov(backtrack_stackpointer(), r2);
jyan's avatar
jyan committed
950 951 952 953 954 955 956 957
    // Restore saved registers and continue.
    SafeReturn();
  }

  if (exit_with_exception.is_linked()) {
    // If any of the code above needed to exit with an exception.
    __ bind(&exit_with_exception);
    // Exit with Result EXCEPTION(-1) to signal thrown exception.
958
    __ mov(r2, Operand(EXCEPTION));
jyan's avatar
jyan committed
959 960 961
    __ b(&return_r2);
  }

962 963
  if (fallback_label_.is_linked()) {
    __ bind(&fallback_label_);
964
    __ mov(r2, Operand(FALLBACK_TO_EXPERIMENTAL));
965 966 967
    __ b(&return_r2);
  }

jyan's avatar
jyan committed
968
  CodeDesc code_desc;
969
  masm_->GetCode(isolate(), &code_desc);
970 971 972 973
  Handle<Code> code =
      Factory::CodeBuilder(isolate(), code_desc, CodeKind::REGEXP)
          .set_self_reference(masm_->CodeObject())
          .Build();
jyan's avatar
jyan committed
974
  PROFILE(masm_->isolate(),
975
          RegExpCodeCreateEvent(Handle<AbstractCode>::cast(code), source));
jyan's avatar
jyan committed
976 977 978 979 980 981 982
  return Handle<HeapObject>::cast(code);
}

void RegExpMacroAssemblerS390::GoTo(Label* to) { BranchOrBacktrack(al, to); }

void RegExpMacroAssemblerS390::IfRegisterGE(int reg, int comparand,
                                            Label* if_ge) {
983
  __ LoadU64(r2, register_location(reg), r0);
984
  __ CmpS64(r2, Operand(comparand));
jyan's avatar
jyan committed
985 986 987 988 989
  BranchOrBacktrack(ge, if_ge);
}

void RegExpMacroAssemblerS390::IfRegisterLT(int reg, int comparand,
                                            Label* if_lt) {
990
  __ LoadU64(r2, register_location(reg), r0);
991
  __ CmpS64(r2, Operand(comparand));
jyan's avatar
jyan committed
992 993 994 995
  BranchOrBacktrack(lt, if_lt);
}

void RegExpMacroAssemblerS390::IfRegisterEqPos(int reg, Label* if_eq) {
996
  __ LoadU64(r2, register_location(reg), r0);
997
  __ CmpS64(r2, current_input_offset());
jyan's avatar
jyan committed
998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011
  BranchOrBacktrack(eq, if_eq);
}

RegExpMacroAssembler::IrregexpImplementation
RegExpMacroAssemblerS390::Implementation() {
  return kS390Implementation;
}

void RegExpMacroAssemblerS390::PopCurrentPosition() {
  Pop(current_input_offset());
}

void RegExpMacroAssemblerS390::PopRegister(int register_index) {
  Pop(r2);
1012
  __ StoreU64(r2, register_location(register_index));
jyan's avatar
jyan committed
1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031
}

void RegExpMacroAssemblerS390::PushBacktrack(Label* label) {
  if (label->is_bound()) {
    int target = label->pos();
    __ mov(r2, Operand(target + Code::kHeaderSize - kHeapObjectTag));
  } else {
    masm_->load_label_offset(r2, label);
  }
  Push(r2);
  CheckStackLimit();
}

void RegExpMacroAssemblerS390::PushCurrentPosition() {
  Push(current_input_offset());
}

void RegExpMacroAssemblerS390::PushRegister(int register_index,
                                            StackCheckFlag check_stack_limit) {
1032
  __ LoadU64(r2, register_location(register_index), r0);
jyan's avatar
jyan committed
1033 1034 1035 1036 1037
  Push(r2);
  if (check_stack_limit) CheckStackLimit();
}

void RegExpMacroAssemblerS390::ReadCurrentPositionFromRegister(int reg) {
1038
  __ LoadU64(current_input_offset(), register_location(reg), r0);
jyan's avatar
jyan committed
1039 1040 1041
}

void RegExpMacroAssemblerS390::ReadStackPointerFromRegister(int reg) {
1042 1043
  __ LoadU64(backtrack_stackpointer(), register_location(reg), r0);
  __ LoadU64(r2, MemOperand(frame_pointer(), kStackHighEnd));
1044
  __ AddS64(backtrack_stackpointer(), r2);
jyan's avatar
jyan committed
1045 1046 1047 1048
}

void RegExpMacroAssemblerS390::SetCurrentPositionFromEnd(int by) {
  Label after_position;
1049
  __ CmpS64(current_input_offset(), Operand(-by * char_size()));
jyan's avatar
jyan committed
1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061
  __ bge(&after_position);
  __ mov(current_input_offset(), Operand(-by * char_size()));
  // On RegExp code entry (where this operation is used), the character before
  // the current position is expected to be already loaded.
  // We have advanced the position, so it's safe to read backwards.
  LoadCurrentCharacterUnchecked(-1, 1);
  __ bind(&after_position);
}

void RegExpMacroAssemblerS390::SetRegister(int register_index, int to) {
  DCHECK(register_index >= num_saved_registers_);  // Reserved for positions!
  __ mov(r2, Operand(to));
1062
  __ StoreU64(r2, register_location(register_index));
jyan's avatar
jyan committed
1063 1064 1065 1066 1067 1068 1069 1070 1071 1072
}

bool RegExpMacroAssemblerS390::Succeed() {
  __ b(&success_label_);
  return global();
}

void RegExpMacroAssemblerS390::WriteCurrentPositionToRegister(int reg,
                                                              int cp_offset) {
  if (cp_offset == 0) {
1073
    __ StoreU64(current_input_offset(), register_location(reg));
jyan's avatar
jyan committed
1074
  } else {
1075
    __ AddS64(r2, current_input_offset(), Operand(cp_offset * char_size()));
1076
    __ StoreU64(r2, register_location(reg));
jyan's avatar
jyan committed
1077 1078 1079 1080 1081
  }
}

void RegExpMacroAssemblerS390::ClearRegisters(int reg_from, int reg_to) {
  DCHECK(reg_from <= reg_to);
1082
  __ LoadU64(r2, MemOperand(frame_pointer(), kStringStartMinusOne));
jyan's avatar
jyan committed
1083
  for (int reg = reg_from; reg <= reg_to; reg++) {
1084
    __ StoreU64(r2, register_location(reg));
jyan's avatar
jyan committed
1085 1086 1087 1088
  }
}

void RegExpMacroAssemblerS390::WriteStackPointerToRegister(int reg) {
1089
  __ LoadU64(r3, MemOperand(frame_pointer(), kStackHighEnd));
1090
  __ SubS64(r2, backtrack_stackpointer(), r3);
1091
  __ StoreU64(r2, register_location(reg));
jyan's avatar
jyan committed
1092 1093 1094 1095 1096
}

// Private methods:

void RegExpMacroAssemblerS390::CallCheckStackGuardState(Register scratch) {
1097
  DCHECK(!isolate()->IsGeneratingEmbeddedBuiltins());
1098 1099 1100
  DCHECK(!masm_->options().isolate_independent_code);

  static constexpr int num_arguments = 3;
jyan's avatar
jyan committed
1101 1102
  __ PrepareCallCFunction(num_arguments, scratch);
  // RegExp code frame pointer.
1103
  __ mov(r4, frame_pointer());
1104
  // Code of self.
jyan's avatar
jyan committed
1105 1106
  __ mov(r3, Operand(masm_->CodeObject()));
  // r2 becomes return address pointer.
1107
  __ lay(r2, MemOperand(sp, kStackFrameRASlot * kSystemPointerSize));
jyan's avatar
jyan committed
1108 1109
  ExternalReference stack_guard_check =
      ExternalReference::re_check_stack_guard_state(isolate());
1110 1111 1112 1113

  __ mov(ip, Operand(stack_guard_check));
  __ StoreReturnAddressAndCall(ip);

1114
  if (base::OS::ActivationFrameAlignment() > kSystemPointerSize) {
1115
    __ LoadU64(
1116
        sp, MemOperand(sp, (kNumRequiredStackFrameSlots * kSystemPointerSize)));
1117
  } else {
1118 1119
    __ la(sp,
          MemOperand(sp, (kNumRequiredStackFrameSlots * kSystemPointerSize)));
1120 1121 1122
  }

  __ mov(code_pointer(), Operand(masm_->CodeObject()));
jyan's avatar
jyan committed
1123 1124 1125 1126 1127
}

// Helper function for reading a value out of a stack frame.
template <typename T>
static T& frame_entry(Address re_frame, int frame_offset) {
1128
  DCHECK_EQ(kSystemPointerSize, sizeof(T));
jyan's avatar
jyan committed
1129
#ifdef V8_TARGET_ARCH_S390X
1130
  return reinterpret_cast<T&>(Memory<uint64_t>(re_frame + frame_offset));
jyan's avatar
jyan committed
1131
#else
1132
  return reinterpret_cast<T&>(Memory<uint32_t>(re_frame + frame_offset));
jyan's avatar
jyan committed
1133 1134 1135 1136 1137 1138 1139 1140 1141
#endif
}

template <typename T>
static T* frame_entry_address(Address re_frame, int frame_offset) {
  return reinterpret_cast<T*>(re_frame + frame_offset);
}

int RegExpMacroAssemblerS390::CheckStackGuardState(Address* return_address,
1142
                                                   Address raw_code,
jyan's avatar
jyan committed
1143
                                                   Address re_frame) {
1144
  Code re_code = Code::cast(Object(raw_code));
jyan's avatar
jyan committed
1145 1146 1147
  return NativeRegExpMacroAssembler::CheckStackGuardState(
      frame_entry<Isolate*>(re_frame, kIsolate),
      frame_entry<intptr_t>(re_frame, kStartIndex),
1148 1149 1150 1151
      static_cast<RegExp::CallOrigin>(
          frame_entry<intptr_t>(re_frame, kDirectCall)),
      return_address, re_code,
      frame_entry_address<Address>(re_frame, kInputString),
jyan's avatar
jyan committed
1152 1153 1154 1155 1156 1157 1158 1159 1160 1161
      frame_entry_address<const byte*>(re_frame, kInputStart),
      frame_entry_address<const byte*>(re_frame, kInputEnd));
}

MemOperand RegExpMacroAssemblerS390::register_location(int register_index) {
  DCHECK(register_index < (1 << 30));
  if (num_registers_ <= register_index) {
    num_registers_ = register_index + 1;
  }
  return MemOperand(frame_pointer(),
1162
                    kRegisterZero - register_index * kSystemPointerSize);
jyan's avatar
jyan committed
1163 1164 1165 1166 1167
}

void RegExpMacroAssemblerS390::CheckPosition(int cp_offset,
                                             Label* on_outside_input) {
  if (cp_offset >= 0) {
1168
    __ CmpS64(current_input_offset(), Operand(-cp_offset * char_size()));
jyan's avatar
jyan committed
1169 1170
    BranchOrBacktrack(ge, on_outside_input);
  } else {
1171
    __ LoadU64(r3, MemOperand(frame_pointer(), kStringStartMinusOne));
1172
    __ AddS64(r2, current_input_offset(), Operand(cp_offset * char_size()));
1173
    __ CmpS64(r2, r3);
jyan's avatar
jyan committed
1174 1175 1176 1177 1178 1179 1180
    BranchOrBacktrack(le, on_outside_input);
  }
}

void RegExpMacroAssemblerS390::BranchOrBacktrack(Condition condition, Label* to,
                                                 CRegister cr) {
  if (condition == al) {  // Unconditional.
1181
    if (to == nullptr) {
jyan's avatar
jyan committed
1182 1183 1184 1185 1186 1187
      Backtrack();
      return;
    }
    __ b(to);
    return;
  }
1188
  if (to == nullptr) {
jyan's avatar
jyan committed
1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205
    __ b(condition, &backtrack_label_);
    return;
  }
  __ b(condition, to);
}

void RegExpMacroAssemblerS390::SafeCall(Label* to, Condition cond,
                                        CRegister cr) {
  Label skip;
  __ b(NegateCondition(cond), &skip);
  __ b(r14, to);
  __ bind(&skip);
}

void RegExpMacroAssemblerS390::SafeReturn() {
  __ pop(r14);
  __ mov(ip, Operand(masm_->CodeObject()));
1206
  __ AddS64(r14, ip);
jyan's avatar
jyan committed
1207 1208 1209 1210 1211 1212
  __ Ret();
}

void RegExpMacroAssemblerS390::SafeCallTarget(Label* name) {
  __ bind(name);
  __ CleanseP(r14);
1213
  __ mov(r0, r14);
jyan's avatar
jyan committed
1214
  __ mov(ip, Operand(masm_->CodeObject()));
1215
  __ SubS64(r0, r0, ip);
jyan's avatar
jyan committed
1216 1217 1218 1219
  __ push(r0);
}

void RegExpMacroAssemblerS390::Push(Register source) {
1220
  DCHECK(source != backtrack_stackpointer());
jyan's avatar
jyan committed
1221
  __ lay(backtrack_stackpointer(),
1222
         MemOperand(backtrack_stackpointer(), -kSystemPointerSize));
1223
  __ StoreU64(source, MemOperand(backtrack_stackpointer()));
jyan's avatar
jyan committed
1224 1225 1226
}

void RegExpMacroAssemblerS390::Pop(Register target) {
1227
  DCHECK(target != backtrack_stackpointer());
1228
  __ LoadU64(target, MemOperand(backtrack_stackpointer()));
jyan's avatar
jyan committed
1229
  __ la(backtrack_stackpointer(),
1230
        MemOperand(backtrack_stackpointer(), kSystemPointerSize));
jyan's avatar
jyan committed
1231 1232 1233 1234 1235
}

void RegExpMacroAssemblerS390::CheckPreemption() {
  // Check for preemption.
  ExternalReference stack_limit =
1236
      ExternalReference::address_of_jslimit(isolate());
jyan's avatar
jyan committed
1237
  __ mov(r2, Operand(stack_limit));
1238
  __ CmpU64(sp, MemOperand(r2));
jyan's avatar
jyan committed
1239 1240 1241 1242 1243
  SafeCall(&check_preempt_label_, le);
}

void RegExpMacroAssemblerS390::CheckStackLimit() {
  ExternalReference stack_limit =
1244
      ExternalReference::address_of_regexp_stack_limit_address(isolate());
jyan's avatar
jyan committed
1245
  __ mov(r2, Operand(stack_limit));
1246
  __ CmpU64(backtrack_stackpointer(), MemOperand(r2));
jyan's avatar
jyan committed
1247 1248 1249 1250 1251 1252
  SafeCall(&stack_overflow_label_, le);
}

void RegExpMacroAssemblerS390::CallCFunctionUsingStub(
    ExternalReference function, int num_arguments) {
  // Must pass all arguments in registers. The stub pushes on the stack.
1253
  DCHECK_GE(8, num_arguments);
jyan's avatar
jyan committed
1254 1255 1256
  __ mov(code_pointer(), Operand(function));
  Label ret;
  __ larl(r14, &ret);
1257
  __ StoreU64(r14, MemOperand(sp, kStackFrameRASlot * kSystemPointerSize));
jyan's avatar
jyan committed
1258 1259
  __ b(code_pointer());
  __ bind(&ret);
1260
  if (base::OS::ActivationFrameAlignment() > kSystemPointerSize) {
1261
    __ LoadU64(
1262
        sp, MemOperand(sp, (kNumRequiredStackFrameSlots * kSystemPointerSize)));
jyan's avatar
jyan committed
1263
  } else {
1264 1265
    __ la(sp,
          MemOperand(sp, (kNumRequiredStackFrameSlots * kSystemPointerSize)));
jyan's avatar
jyan committed
1266 1267 1268 1269 1270 1271 1272 1273
  }
  __ mov(code_pointer(), Operand(masm_->CodeObject()));
}


void RegExpMacroAssemblerS390::LoadCurrentCharacterUnchecked(int cp_offset,
                                                             int characters) {
  if (mode_ == LATIN1) {
1274 1275
    // using load reverse for big-endian platforms
    if (characters == 4) {
1276 1277 1278
      __ LoadU32LE(current_character(),
                   MemOperand(current_input_offset(), end_of_input_address(),
                              cp_offset * char_size()));
1279
    } else if (characters == 2) {
1280 1281 1282
      __ LoadU16LE(current_character(),
                   MemOperand(current_input_offset(), end_of_input_address(),
                              cp_offset * char_size()));
1283
    } else {
1284
      DCHECK_EQ(1, characters);
1285
      __ LoadU8(current_character(),
1286 1287 1288
                MemOperand(current_input_offset(), end_of_input_address(),
                           cp_offset * char_size()));
    }
jyan's avatar
jyan committed
1289 1290
  } else {
    DCHECK(mode_ == UC16);
1291
    if (characters == 2) {
1292
      __ LoadU32(current_character(),
1293 1294 1295 1296 1297 1298 1299
                MemOperand(current_input_offset(), end_of_input_address(),
                           cp_offset * char_size()));
#if !V8_TARGET_LITTLE_ENDIAN
      // need to swap the order of the characters for big-endian platforms
      __ rll(current_character(), current_character(), Operand(16));
#endif
    } else {
1300
      DCHECK_EQ(1, characters);
1301
      __ LoadU16(
1302 1303 1304 1305
          current_character(),
                MemOperand(current_input_offset(), end_of_input_address(),
                           cp_offset * char_size()));
    }
jyan's avatar
jyan committed
1306 1307 1308 1309 1310 1311 1312 1313 1314
  }
}

#undef __

}  // namespace internal
}  // namespace v8

#endif  // V8_TARGET_ARCH_S390