regexp-macro-assembler-s390.cc 50.5 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

#if V8_TARGET_ARCH_S390

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

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.
25
 * - r7: Pointer to current Code object including heap object tag.
jyan's avatar
jyan committed
26 27 28 29 30 31 32 33 34 35 36 37 38 39
 * - 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.
 *
40 41 42 43
 * 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)
44
 *  - fp[108] Isolate* isolate   (address of the current isolate)
jyan's avatar
jyan committed
45 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
 *  - 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:
82
 * int (*match)(String input_string,
jyan's avatar
jyan committed
83 84 85 86
 *              int start_index,
 *              Address start,
 *              Address end,
 *              int* capture_output_array,
87
 *              int num_capture_registers,
jyan's avatar
jyan committed
88
 *              byte* stack_area_base,
89
 *              bool direct_call = false,
90 91
 *              Isolate* isolate,
 *              Address regexp);
jyan's avatar
jyan committed
92
 * The call is performed by NativeRegExpMacroAssembler::Execute()
93
 * (in regexp-macro-assembler.cc) via the GeneratedCode wrapper.
jyan's avatar
jyan committed
94 95 96 97
 */

#define __ ACCESS_MASM(masm_)

98 99
const int RegExpMacroAssemblerS390::kRegExpCodeSize;

jyan's avatar
jyan committed
100 101 102 103
RegExpMacroAssemblerS390::RegExpMacroAssemblerS390(Isolate* isolate, Zone* zone,
                                                   Mode mode,
                                                   int registers_to_save)
    : NativeRegExpMacroAssembler(isolate, zone),
104 105 106 107
      masm_(std::make_unique<MacroAssembler>(
          isolate, CodeObjectRequired::kYes,
          NewAssemblerBuffer(kRegExpCodeSize))),
      no_root_array_scope_(masm_.get()),
jyan's avatar
jyan committed
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
      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_() {
  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_);
123
  __ mov(r2, Operand(FAILURE));
jyan's avatar
jyan committed
124 125 126 127 128 129 130 131 132 133 134 135 136 137
  __ Ret();
  __ bind(&start_label_);  // And then continue from here.
}

RegExpMacroAssemblerS390::~RegExpMacroAssemblerS390() {
  // 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();
138
  fallback_label_.Unuse();
jyan's avatar
jyan committed
139 140 141 142 143 144 145 146
}

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

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

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

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

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

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

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

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

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

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

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

222 223
void RegExpMacroAssemblerS390::CheckCharacterLT(base::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
      AllowExternalCallThatCantCauseGC scope(masm_.get());
jyan's avatar
jyan committed
355
      ExternalReference function =
356 357 358
          unicode
              ? ExternalReference::re_case_insensitive_compare_unicode()
              : ExternalReference::re_case_insensitive_compare_non_unicode();
jyan's avatar
jyan committed
359 360 361 362
      __ CallCFunction(function, argument_count);
    }

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

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

  __ bind(&fallthrough);
}

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

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

  // 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) {
394
    __ LoadU64(r5, MemOperand(frame_pointer(), kStringStartMinusOne));
395
    __ AddS64(r5, r5, r3);
396
    __ CmpS64(current_input_offset(), r5);
397
    BranchOrBacktrack(le, on_no_match);
jyan's avatar
jyan committed
398
  } else {
399
    __ AddS64(r0, r3, current_input_offset());
jyan's avatar
jyan committed
400 401 402 403 404 405 406 407
    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) {
408
    __ SubS64(r4, r4, r3);  // Offset by length when matching backwards.
jyan's avatar
jyan committed
409 410 411 412 413 414
  }
  __ mov(r1, Operand::Zero());

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

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

  __ bind(&fallthrough);
}

void RegExpMacroAssemblerS390::CheckNotCharacter(unsigned c,
                                                 Label* on_not_equal) {
444
  __ CmpU64(current_character(), Operand(c));
jyan's avatar
jyan committed
445 446 447 448 449 450 451
  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) {
452
    __ CmpU64(r2, Operand(c));
jyan's avatar
jyan committed
453 454 455 456 457 458 459 460 461
  }
  BranchOrBacktrack(eq, on_equal);
}

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

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

478 479
void RegExpMacroAssemblerS390::CheckCharacterInRange(base::uc16 from,
                                                     base::uc16 to,
jyan's avatar
jyan committed
480 481
                                                     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
  BranchOrBacktrack(le, on_in_range);  // Unsigned lower-or-same condition.
}

void RegExpMacroAssemblerS390::CheckCharacterNotInRange(
487
    base::uc16 from, base::uc16 to, Label* on_not_in_range) {
jyan's avatar
jyan committed
488
  __ lay(r2, MemOperand(current_character(), -from));
489
  __ CmpU64(r2, Operand(to - from));
jyan's avatar
jyan committed
490 491 492
  BranchOrBacktrack(gt, on_not_in_range);  // Unsigned higher condition.
}

493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527
void RegExpMacroAssemblerS390::CallIsCharacterInRangeArray(
    const ZoneList<CharacterRange>* ranges) {
  static const int kNumArguments = 3;
  __ PrepareCallCFunction(kNumArguments, r0);

  __ mov(r2, current_character());
  __ mov(r3, Operand(GetOrAddRangeArray(ranges)));
  __ mov(r4, Operand(ExternalReference::isolate_address(isolate())));

  {
    // We have a frame (set up in GetCode), but the assembler doesn't know.
    FrameScope scope(masm_.get(), StackFrame::MANUAL);
    __ CallCFunction(ExternalReference::re_is_character_in_range_array(),
                     kNumArguments);
  }

  __ mov(code_pointer(), Operand(masm_->CodeObject()));
}

bool RegExpMacroAssemblerS390::CheckCharacterInRangeArray(
    const ZoneList<CharacterRange>* ranges, Label* on_in_range) {
  CallIsCharacterInRangeArray(ranges);
  __ CmpS64(r2, Operand::Zero());
  BranchOrBacktrack(ne, on_in_range);
  return true;
}

bool RegExpMacroAssemblerS390::CheckCharacterNotInRangeArray(
    const ZoneList<CharacterRange>* ranges, Label* on_not_in_range) {
  CallIsCharacterInRangeArray(ranges);
  __ CmpS64(r2, Operand::Zero());
  BranchOrBacktrack(eq, on_not_in_range);
  return true;
}

jyan's avatar
jyan committed
528 529 530 531 532 533 534 535
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;
  }
536
  __ LoadU8(r2,
jyan's avatar
jyan committed
537
            MemOperand(r2, index, (ByteArray::kHeaderSize - kHeapObjectTag)));
538
  __ CmpS64(r2, Operand::Zero());
jyan's avatar
jyan committed
539 540 541
  BranchOrBacktrack(ne, on_bit_set);
}

542 543
bool RegExpMacroAssemblerS390::CheckSpecialCharacterClass(
    StandardCharacterSet type, Label* on_no_match) {
jyan's avatar
jyan committed
544 545
  // Range checks (c in min..max) are generally implemented by an unsigned
  // (c - min) <= (max - min) check
546
  // TODO(jgruber): No custom implementation (yet): s(UC16), S(UC16).
jyan's avatar
jyan committed
547
  switch (type) {
548 549
    case StandardCharacterSet::kWhitespace:
      // Match space-characters.
jyan's avatar
jyan committed
550 551 552
      if (mode_ == LATIN1) {
        // One byte space characters are '\t'..'\r', ' ' and \u00a0.
        Label success;
553
        __ CmpS64(current_character(), Operand(' '));
jyan's avatar
jyan committed
554
        __ beq(&success);
555
        // Check range 0x09..0x0D.
556
        __ SubS64(r2, current_character(), Operand('\t'));
557
        __ CmpU64(r2, Operand('\r' - '\t'));
jyan's avatar
jyan committed
558 559
        __ ble(&success);
        // \u00a0 (NBSP).
560
        __ CmpU64(r2, Operand(0x00A0 - '\t'));
jyan's avatar
jyan committed
561 562 563 564 565
        BranchOrBacktrack(ne, on_no_match);
        __ bind(&success);
        return true;
      }
      return false;
566
    case StandardCharacterSet::kNotWhitespace:
jyan's avatar
jyan committed
567 568
      // The emitted code for generic character classes is good enough.
      return false;
569
    case StandardCharacterSet::kDigit:
jyan's avatar
jyan committed
570
      // Match ASCII digits ('0'..'9')
571
      __ SubS64(r2, current_character(), Operand('0'));
572
      __ CmpU64(r2, Operand('9' - '0'));
jyan's avatar
jyan committed
573 574
      BranchOrBacktrack(gt, on_no_match);
      return true;
575
    case StandardCharacterSet::kNotDigit:
jyan's avatar
jyan committed
576
      // Match non ASCII-digits
577
      __ SubS64(r2, current_character(), Operand('0'));
578
      __ CmpU64(r2, Operand('9' - '0'));
jyan's avatar
jyan committed
579 580
      BranchOrBacktrack(le, on_no_match);
      return true;
581
    case StandardCharacterSet::kNotLineTerminator: {
582
      // Match non-newlines (not 0x0A('\n'), 0x0D('\r'), 0x2028 and 0x2029)
jyan's avatar
jyan committed
583
      __ XorP(r2, current_character(), Operand(0x01));
584
      // See if current character is '\n'^1 or '\r'^1, i.e., 0x0B or 0x0C
585
      __ SubS64(r2, Operand(0x0B));
586
      __ CmpU64(r2, Operand(0x0C - 0x0B));
jyan's avatar
jyan committed
587 588 589
      BranchOrBacktrack(le, on_no_match);
      if (mode_ == UC16) {
        // Compare original value to 0x2028 and 0x2029, using the already
590 591
        // computed (current_char ^ 0x01 - 0x0B). I.e., check for
        // 0x201D (0x2028 - 0x0B) or 0x201E.
592
        __ SubS64(r2, Operand(0x2028 - 0x0B));
593
        __ CmpU64(r2, Operand(1));
jyan's avatar
jyan committed
594 595 596 597
        BranchOrBacktrack(le, on_no_match);
      }
      return true;
    }
598
    case StandardCharacterSet::kLineTerminator: {
599
      // Match newlines (0x0A('\n'), 0x0D('\r'), 0x2028 and 0x2029)
jyan's avatar
jyan committed
600
      __ XorP(r2, current_character(), Operand(0x01));
601
      // See if current character is '\n'^1 or '\r'^1, i.e., 0x0B or 0x0C
602
      __ SubS64(r2, Operand(0x0B));
603
      __ CmpU64(r2, Operand(0x0C - 0x0B));
jyan's avatar
jyan committed
604 605 606 607 608 609
      if (mode_ == LATIN1) {
        BranchOrBacktrack(gt, on_no_match);
      } else {
        Label done;
        __ ble(&done);
        // Compare original value to 0x2028 and 0x2029, using the already
610 611
        // computed (current_char ^ 0x01 - 0x0B). I.e., check for
        // 0x201D (0x2028 - 0x0B) or 0x201E.
612
        __ SubS64(r2, Operand(0x2028 - 0x0B));
613
        __ CmpU64(r2, Operand(1));
jyan's avatar
jyan committed
614 615 616 617 618
        BranchOrBacktrack(gt, on_no_match);
        __ bind(&done);
      }
      return true;
    }
619
    case StandardCharacterSet::kWord: {
jyan's avatar
jyan committed
620 621
      if (mode_ != LATIN1) {
        // Table is 1256 entries, so all LATIN1 characters can be tested.
622
        __ CmpS64(current_character(), Operand('z'));
jyan's avatar
jyan committed
623 624
        BranchOrBacktrack(gt, on_no_match);
      }
625
      ExternalReference map = ExternalReference::re_word_character_map();
jyan's avatar
jyan committed
626
      __ mov(r2, Operand(map));
627
      __ LoadU8(r2, MemOperand(r2, current_character()));
628
      __ CmpU64(r2, Operand::Zero());
jyan's avatar
jyan committed
629 630 631
      BranchOrBacktrack(eq, on_no_match);
      return true;
    }
632
    case StandardCharacterSet::kNotWord: {
jyan's avatar
jyan committed
633 634 635
      Label done;
      if (mode_ != LATIN1) {
        // Table is 256 entries, so all LATIN characters can be tested.
636
        __ CmpU64(current_character(), Operand('z'));
jyan's avatar
jyan committed
637 638
        __ bgt(&done);
      }
639
      ExternalReference map = ExternalReference::re_word_character_map();
jyan's avatar
jyan committed
640
      __ mov(r2, Operand(map));
641
      __ LoadU8(r2, MemOperand(r2, current_character()));
642
      __ CmpU64(r2, Operand::Zero());
jyan's avatar
jyan committed
643 644 645 646 647 648
      BranchOrBacktrack(ne, on_no_match);
      if (mode_ != LATIN1) {
        __ bind(&done);
      }
      return true;
    }
649
    case StandardCharacterSet::kEverything:
jyan's avatar
jyan committed
650 651 652 653 654 655
      // Match any character.
      return true;
  }
}

void RegExpMacroAssemblerS390::Fail() {
656
  __ mov(r2, Operand(FAILURE));
jyan's avatar
jyan committed
657 658 659
  __ b(&exit_label_);
}

660 661 662 663 664 665 666 667 668 669 670 671 672 673 674
void RegExpMacroAssemblerS390::LoadRegExpStackPointerFromMemory(Register dst) {
  ExternalReference ref =
      ExternalReference::address_of_regexp_stack_stack_pointer(isolate());
  __ mov(dst, Operand(ref));
  __ LoadU64(dst, MemOperand(dst));
}

void RegExpMacroAssemblerS390::StoreRegExpStackPointerToMemory(
    Register src, Register scratch) {
  ExternalReference ref =
      ExternalReference::address_of_regexp_stack_stack_pointer(isolate());
  __ mov(scratch, Operand(ref));
  __ StoreU64(src, MemOperand(scratch));
}

675 676
void RegExpMacroAssemblerS390::PushRegExpBasePointer(Register stack_pointer,
                                                     Register scratch) {
677 678
  ExternalReference ref =
      ExternalReference::address_of_regexp_stack_memory_top_address(isolate());
679 680 681 682
  __ mov(scratch, Operand(ref));
  __ LoadU64(scratch, MemOperand(scratch));
  __ SubS64(scratch, stack_pointer, scratch);
  __ StoreU64(scratch, MemOperand(frame_pointer(), kRegExpStackBasePointer));
683 684
}

685 686
void RegExpMacroAssemblerS390::PopRegExpBasePointer(Register stack_pointer_out,
                                                    Register scratch) {
687 688
  ExternalReference ref =
      ExternalReference::address_of_regexp_stack_memory_top_address(isolate());
689 690 691 692 693 694
  __ LoadU64(stack_pointer_out,
             MemOperand(frame_pointer(), kRegExpStackBasePointer));
  __ mov(scratch, Operand(ref));
  __ LoadU64(scratch, MemOperand(scratch));
  __ AddS64(stack_pointer_out, stack_pointer_out, scratch);
  StoreRegExpStackPointerToMemory(stack_pointer_out, scratch);
695 696
}

jyan's avatar
jyan committed
697 698 699 700 701 702 703 704 705 706 707
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.
708
  FrameScope scope(masm_.get(), StackFrame::MANUAL);
jyan's avatar
jyan committed
709 710

  // Ensure register assigments are consistent with callee save mask
711 712 713 714 715 716 717
  DCHECK(kRegExpCalleeSaved.has(r6));
  DCHECK(kRegExpCalleeSaved.has(code_pointer()));
  DCHECK(kRegExpCalleeSaved.has(current_input_offset()));
  DCHECK(kRegExpCalleeSaved.has(current_character()));
  DCHECK(kRegExpCalleeSaved.has(backtrack_stackpointer()));
  DCHECK(kRegExpCalleeSaved.has(end_of_input_address()));
  DCHECK(kRegExpCalleeSaved.has(frame_pointer()));
jyan's avatar
jyan committed
718 719 720 721 722 723 724 725 726 727 728

  // 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
729
  __ StoreMultipleP(r6, sp, MemOperand(sp, 6 * kSystemPointerSize));
jyan's avatar
jyan committed
730 731

  // Load stack parameters from caller stack frame
732 733
  __ LoadMultipleP(
      r7, r9, MemOperand(sp, kStackFrameExtraParamSlot * kSystemPointerSize));
jyan's avatar
jyan committed
734 735 736 737 738 739 740 741 742 743 744 745 746
  // 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.
747
  __ mov(frame_pointer(), sp);
748
  __ lay(sp, MemOperand(sp, -10 * kSystemPointerSize));
749
  STATIC_ASSERT(kSuccessfulCaptures == kInputString - kSystemPointerSize);
jyan's avatar
jyan committed
750
  __ mov(r1, Operand::Zero());  // success counter
751 752
  STATIC_ASSERT(kStringStartMinusOne ==
                kSuccessfulCaptures - kSystemPointerSize);
753
  __ mov(r0, r1);  // offset of location
jyan's avatar
jyan committed
754
  __ StoreMultipleP(r0, r9, MemOperand(sp, 0));
755 756
  STATIC_ASSERT(kBacktrackCount == kStringStartMinusOne - kSystemPointerSize);
  __ Push(r1);  // The backtrack counter.
757 758 759 760
  STATIC_ASSERT(kRegExpStackBasePointer ==
                kBacktrackCount - kSystemPointerSize);
  __ push(r1);  // The regexp stack base ptr.

761 762 763 764 765
  // Initialize backtrack stack pointer. It must not be clobbered from here on.
  // Note the backtrack_stackpointer is callee-saved.
  STATIC_ASSERT(backtrack_stackpointer() == r13);
  LoadRegExpStackPointerFromMemory(backtrack_stackpointer());

766 767
  // Store the regexp base pointer - we'll later restore it / write it to
  // memory when returning from this irregexp code object.
768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794
  PushRegExpBasePointer(backtrack_stackpointer(), r3);

  {
    // Check if we have space on the stack for registers.
    Label stack_limit_hit, stack_ok;

    ExternalReference stack_limit =
        ExternalReference::address_of_jslimit(isolate());
    __ mov(r2, Operand(stack_limit));
    __ LoadU64(r2, MemOperand(r2));
    __ SubS64(r2, sp, r2);
    // 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.
    __ CmpU64(r2, Operand(num_registers_ * kSystemPointerSize));
    __ 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);
    __ CmpS64(r2, Operand::Zero());
    // If returned value is non-zero, we exit with the returned value as result.
    __ bne(&return_r2);
jyan's avatar
jyan committed
795

796 797
    __ bind(&stack_ok);
  }
jyan's avatar
jyan committed
798 799

  // Allocate space on stack for registers.
800
  __ lay(sp, MemOperand(sp, (-num_registers_ * kSystemPointerSize)));
jyan's avatar
jyan committed
801
  // Load string end.
802
  __ LoadU64(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
jyan's avatar
jyan committed
803
  // Load input start.
804
  __ LoadU64(r4, MemOperand(frame_pointer(), kInputStart));
jyan's avatar
jyan committed
805
  // Find negative length (offset of start relative to end).
806
  __ SubS64(current_input_offset(), r4, end_of_input_address());
807
  __ LoadU64(r3, MemOperand(frame_pointer(), kStartIndex));
jyan's avatar
jyan committed
808 809
  // Set r1 to address of char before start of the input string
  // (effectively string position -1).
810
  __ mov(r1, r4);
811
  __ SubS64(r1, current_input_offset(), Operand(char_size()));
jyan's avatar
jyan committed
812
  if (mode_ == UC16) {
813
    __ ShiftLeftU64(r0, r3, Operand(1));
814
    __ SubS64(r1, r1, r0);
jyan's avatar
jyan committed
815
  } else {
816
    __ SubS64(r1, r1, r3);
jyan's avatar
jyan committed
817 818 819
  }
  // Store this value in a local variable, for use when clearing
  // position registers.
820
  __ StoreU64(r1, MemOperand(frame_pointer(), kStringStartMinusOne));
jyan's avatar
jyan committed
821 822 823 824

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

825 826 827 828 829 830 831 832 833 834 835 836 837 838 839
  Label load_char_start_regexp;
  {
    Label start_regexp;
    // Load newline if index is at start, previous character otherwise.
    __ CmpS64(r3, Operand::Zero());
    __ 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);
  }
jyan's avatar
jyan committed
840 841 842 843 844 845

  // 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.
846 847
      __ lay(r3,
             MemOperand(frame_pointer(), kRegisterZero + kSystemPointerSize));
848
      __ mov(r4, Operand(num_saved_registers_));
jyan's avatar
jyan committed
849 850
      Label init_loop;
      __ bind(&init_loop);
851
      __ StoreU64(r1, MemOperand(r3, -kSystemPointerSize));
852
      __ lay(r3, MemOperand(r3, -kSystemPointerSize));
jyan's avatar
jyan committed
853 854 855
      __ BranchOnCount(r4, &init_loop);
    } else {
      for (int i = 0; i < num_saved_registers_; i++) {
856
        __ StoreU64(r1, register_location(i));
jyan's avatar
jyan committed
857 858 859 860 861 862 863 864 865 866 867 868
      }
    }
  }

  __ 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
869 870 871
      __ LoadU64(r0, MemOperand(frame_pointer(), kInputStart));
      __ LoadU64(r2, MemOperand(frame_pointer(), kRegisterOutput));
      __ LoadU64(r4, MemOperand(frame_pointer(), kStartIndex));
872
      __ SubS64(r0, end_of_input_address(), r0);
jyan's avatar
jyan committed
873 874
      // r0 is length of input in bytes.
      if (mode_ == UC16) {
875
        __ ShiftRightU64(r0, r0, Operand(1));
jyan's avatar
jyan committed
876 877
      }
      // r0 is length of input in characters.
878
      __ AddS64(r0, r4);
jyan's avatar
jyan committed
879 880 881 882 883 884 885 886
      // 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_;) {
887
        if ((false) && i < num_saved_registers_ - 4) {
jyan's avatar
jyan committed
888 889 890
          // TODO(john.yan): Can be optimized by SIMD instructions
          __ LoadMultipleP(r3, r6, register_location(i + 3));
          if (mode_ == UC16) {
891 892 893 894
            __ 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
895
          }
896 897 898 899
          __ AddS64(r3, r0);
          __ AddS64(r4, r0);
          __ AddS64(r5, r0);
          __ AddS64(r6, r0);
900 901 902 903 904 905 906 907
          __ 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
908 909 910 911
          i += 4;
        } else {
          __ LoadMultipleP(r3, r4, register_location(i + 1));
          if (mode_ == UC16) {
912 913
            __ ShiftRightS64(r3, r3, Operand(1));
            __ ShiftRightS64(r4, r4, Operand(1));
jyan's avatar
jyan committed
914
          }
915 916
          __ AddS64(r3, r0);
          __ AddS64(r4, r0);
917 918 919 920
          __ StoreU32(
              r3, MemOperand(r2, -(num_saved_registers_ - i - 1) * kIntSize));
          __ StoreU32(r4,
                      MemOperand(r2, -(num_saved_registers_ - i) * kIntSize));
jyan's avatar
jyan committed
921 922 923 924 925
          i += 2;
        }
      }
      if (global_with_zero_length_check()) {
        // Keep capture start in r6 for the zero-length check later.
926
        __ LoadU64(r6, register_location(0));
jyan's avatar
jyan committed
927 928 929 930 931
      }
    }

    if (global()) {
      // Restart matching if the regular expression is flagged as global.
932 933 934
      __ LoadU64(r2, MemOperand(frame_pointer(), kSuccessfulCaptures));
      __ LoadU64(r3, MemOperand(frame_pointer(), kNumOutputRegisters));
      __ LoadU64(r4, MemOperand(frame_pointer(), kRegisterOutput));
jyan's avatar
jyan committed
935
      // Increment success counter.
936
      __ AddS64(r2, Operand(1));
937
      __ StoreU64(r2, MemOperand(frame_pointer(), kSuccessfulCaptures));
jyan's avatar
jyan committed
938 939
      // Capture results have been stored, so the number of remaining global
      // output registers is reduced by the number of stored captures.
940
      __ SubS64(r3, Operand(num_saved_registers_));
jyan's avatar
jyan committed
941
      // Check whether we have enough room for another set of capture results.
942
      __ CmpS64(r3, Operand(num_saved_registers_));
jyan's avatar
jyan committed
943 944
      __ blt(&return_r2);

945
      __ StoreU64(r3, MemOperand(frame_pointer(), kNumOutputRegisters));
jyan's avatar
jyan committed
946
      // Advance the location for output.
947
      __ AddS64(r4, Operand(num_saved_registers_ * kIntSize));
948
      __ StoreU64(r4, MemOperand(frame_pointer(), kRegisterOutput));
jyan's avatar
jyan committed
949 950

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

953 954 955 956
      // Restore the original regexp stack pointer value (effectively, pop the
      // stored base pointer).
      PopRegExpBasePointer(backtrack_stackpointer(), r4);

jyan's avatar
jyan committed
957 958 959
      if (global_with_zero_length_check()) {
        // Special case for zero-length matches.
        // r6: capture start index
960
        __ CmpS64(current_input_offset(), r6);
jyan's avatar
jyan committed
961 962 963
        // Not a zero-length match, restart.
        __ bne(&load_char_start_regexp);
        // Offset from the end is zero if we already reached the end.
964
        __ CmpS64(current_input_offset(), Operand::Zero());
jyan's avatar
jyan committed
965 966 967 968
        __ beq(&exit_label_);
        // Advance current position after a zero-length match.
        Label advance;
        __ bind(&advance);
969
        __ AddS64(current_input_offset(), Operand((mode_ == UC16) ? 2 : 1));
jyan's avatar
jyan committed
970 971 972 973 974
        if (global_unicode()) CheckNotInSurrogatePair(0, &advance);
      }

      __ b(&load_char_start_regexp);
    } else {
975
      __ mov(r2, Operand(SUCCESS));
jyan's avatar
jyan committed
976 977 978 979 980 981
    }
  }

  // Exit and return r2
  __ bind(&exit_label_);
  if (global()) {
982
    __ LoadU64(r2, MemOperand(frame_pointer(), kSuccessfulCaptures));
jyan's avatar
jyan committed
983 984 985
  }

  __ bind(&return_r2);
986 987
  // Restore the original regexp stack pointer value (effectively, pop the
  // stored base pointer).
988
  PopRegExpBasePointer(backtrack_stackpointer(), r4);
989

jyan's avatar
jyan committed
990
  // Skip sp past regexp registers and local variables..
991
  __ mov(sp, frame_pointer());
jyan's avatar
jyan committed
992
  // Restore registers r6..r15.
993
  __ LoadMultipleP(r6, sp, MemOperand(sp, 6 * kSystemPointerSize));
jyan's avatar
jyan committed
994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008

  __ 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_);

1009 1010
    StoreRegExpStackPointerToMemory(backtrack_stackpointer(), r3);

jyan's avatar
jyan committed
1011
    CallCheckStackGuardState(r2);
1012
    __ CmpS64(r2, Operand::Zero());
jyan's avatar
jyan committed
1013 1014 1015 1016
    // If returning non-zero, we should end execution with the given
    // result as return value.
    __ bne(&return_r2);

1017 1018
    LoadRegExpStackPointerFromMemory(backtrack_stackpointer());

jyan's avatar
jyan committed
1019
    // String might have moved: Reload end of string from frame.
1020
    __ LoadU64(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
jyan's avatar
jyan committed
1021 1022 1023 1024 1025 1026 1027 1028
    SafeReturn();
  }

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

1029 1030 1031 1032 1033 1034 1035
    // Call GrowStack(isolate).

    StoreRegExpStackPointerToMemory(backtrack_stackpointer(), r3);

    static constexpr int kNumArguments = 1;
    __ PrepareCallCFunction(kNumArguments, r2);
    __ mov(r2, Operand(ExternalReference::isolate_address(isolate())));
1036
    ExternalReference grow_stack = ExternalReference::re_grow_stack();
1037 1038 1039
    __ CallCFunction(grow_stack, kNumArguments);
    // If nullptr is returned, we have failed to grow the stack, and must exit
    // with a stack-overflow exception.
1040
    __ CmpS64(r2, Operand::Zero());
jyan's avatar
jyan committed
1041 1042
    __ beq(&exit_with_exception);
    // Otherwise use return value as new stack pointer.
1043
    __ mov(backtrack_stackpointer(), r2);
jyan's avatar
jyan committed
1044 1045 1046 1047 1048 1049 1050 1051
    // 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.
1052
    __ mov(r2, Operand(EXCEPTION));
jyan's avatar
jyan committed
1053 1054 1055
    __ b(&return_r2);
  }

1056 1057
  if (fallback_label_.is_linked()) {
    __ bind(&fallback_label_);
1058
    __ mov(r2, Operand(FALLBACK_TO_EXPERIMENTAL));
1059 1060 1061
    __ b(&return_r2);
  }

jyan's avatar
jyan committed
1062
  CodeDesc code_desc;
1063
  masm_->GetCode(isolate(), &code_desc);
1064 1065 1066 1067
  Handle<Code> code =
      Factory::CodeBuilder(isolate(), code_desc, CodeKind::REGEXP)
          .set_self_reference(masm_->CodeObject())
          .Build();
jyan's avatar
jyan committed
1068
  PROFILE(masm_->isolate(),
1069
          RegExpCodeCreateEvent(Handle<AbstractCode>::cast(code), source));
jyan's avatar
jyan committed
1070 1071 1072 1073 1074 1075 1076
  return Handle<HeapObject>::cast(code);
}

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

void RegExpMacroAssemblerS390::IfRegisterGE(int reg, int comparand,
                                            Label* if_ge) {
1077
  __ LoadU64(r2, register_location(reg), r0);
1078
  __ CmpS64(r2, Operand(comparand));
jyan's avatar
jyan committed
1079 1080 1081 1082 1083
  BranchOrBacktrack(ge, if_ge);
}

void RegExpMacroAssemblerS390::IfRegisterLT(int reg, int comparand,
                                            Label* if_lt) {
1084
  __ LoadU64(r2, register_location(reg), r0);
1085
  __ CmpS64(r2, Operand(comparand));
jyan's avatar
jyan committed
1086 1087 1088 1089
  BranchOrBacktrack(lt, if_lt);
}

void RegExpMacroAssemblerS390::IfRegisterEqPos(int reg, Label* if_eq) {
1090
  __ LoadU64(r2, register_location(reg), r0);
1091
  __ CmpS64(r2, current_input_offset());
jyan's avatar
jyan committed
1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105
  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);
1106
  __ StoreU64(r2, register_location(register_index));
jyan's avatar
jyan committed
1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125
}

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) {
1126
  __ LoadU64(r2, register_location(register_index), r0);
jyan's avatar
jyan committed
1127 1128 1129 1130 1131
  Push(r2);
  if (check_stack_limit) CheckStackLimit();
}

void RegExpMacroAssemblerS390::ReadCurrentPositionFromRegister(int reg) {
1132
  __ LoadU64(current_input_offset(), register_location(reg), r0);
jyan's avatar
jyan committed
1133 1134
}

1135 1136 1137 1138 1139 1140 1141 1142 1143
void RegExpMacroAssemblerS390::WriteStackPointerToRegister(int reg) {
  ExternalReference ref =
      ExternalReference::address_of_regexp_stack_memory_top_address(isolate());
  __ mov(r3, Operand(ref));
  __ LoadU64(r3, MemOperand(r3));
  __ SubS64(r2, backtrack_stackpointer(), r3);
  __ StoreU64(r2, register_location(reg));
}

jyan's avatar
jyan committed
1144
void RegExpMacroAssemblerS390::ReadStackPointerFromRegister(int reg) {
1145 1146 1147 1148 1149 1150
  ExternalReference ref =
      ExternalReference::address_of_regexp_stack_memory_top_address(isolate());
  __ mov(r2, Operand(ref));
  __ LoadU64(r2, MemOperand(r2));
  __ LoadU64(backtrack_stackpointer(), register_location(reg));
  __ AddS64(backtrack_stackpointer(), backtrack_stackpointer(), r2);
jyan's avatar
jyan committed
1151 1152 1153 1154
}

void RegExpMacroAssemblerS390::SetCurrentPositionFromEnd(int by) {
  Label after_position;
1155
  __ CmpS64(current_input_offset(), Operand(-by * char_size()));
jyan's avatar
jyan committed
1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167
  __ 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));
1168
  __ StoreU64(r2, register_location(register_index));
jyan's avatar
jyan committed
1169 1170 1171 1172 1173 1174 1175 1176 1177 1178
}

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

void RegExpMacroAssemblerS390::WriteCurrentPositionToRegister(int reg,
                                                              int cp_offset) {
  if (cp_offset == 0) {
1179
    __ StoreU64(current_input_offset(), register_location(reg));
jyan's avatar
jyan committed
1180
  } else {
1181
    __ AddS64(r2, current_input_offset(), Operand(cp_offset * char_size()));
1182
    __ StoreU64(r2, register_location(reg));
jyan's avatar
jyan committed
1183 1184 1185 1186 1187
  }
}

void RegExpMacroAssemblerS390::ClearRegisters(int reg_from, int reg_to) {
  DCHECK(reg_from <= reg_to);
1188
  __ LoadU64(r2, MemOperand(frame_pointer(), kStringStartMinusOne));
jyan's avatar
jyan committed
1189
  for (int reg = reg_from; reg <= reg_to; reg++) {
1190
    __ StoreU64(r2, register_location(reg));
jyan's avatar
jyan committed
1191 1192 1193 1194 1195 1196
  }
}

// Private methods:

void RegExpMacroAssemblerS390::CallCheckStackGuardState(Register scratch) {
1197
  DCHECK(!isolate()->IsGeneratingEmbeddedBuiltins());
1198 1199 1200
  DCHECK(!masm_->options().isolate_independent_code);

  static constexpr int num_arguments = 3;
jyan's avatar
jyan committed
1201 1202
  __ PrepareCallCFunction(num_arguments, scratch);
  // RegExp code frame pointer.
1203
  __ mov(r4, frame_pointer());
1204
  // Code of self.
jyan's avatar
jyan committed
1205 1206
  __ mov(r3, Operand(masm_->CodeObject()));
  // r2 becomes return address pointer.
1207
  __ lay(r2, MemOperand(sp, kStackFrameRASlot * kSystemPointerSize));
jyan's avatar
jyan committed
1208
  ExternalReference stack_guard_check =
1209
      ExternalReference::re_check_stack_guard_state();
1210 1211 1212 1213

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

1214
  if (base::OS::ActivationFrameAlignment() > kSystemPointerSize) {
1215
    __ LoadU64(
1216
        sp, MemOperand(sp, (kNumRequiredStackFrameSlots * kSystemPointerSize)));
1217
  } else {
1218 1219
    __ la(sp,
          MemOperand(sp, (kNumRequiredStackFrameSlots * kSystemPointerSize)));
1220 1221 1222
  }

  __ mov(code_pointer(), Operand(masm_->CodeObject()));
jyan's avatar
jyan committed
1223 1224 1225 1226 1227
}

// Helper function for reading a value out of a stack frame.
template <typename T>
static T& frame_entry(Address re_frame, int frame_offset) {
1228
  DCHECK_EQ(kSystemPointerSize, sizeof(T));
jyan's avatar
jyan committed
1229
#ifdef V8_TARGET_ARCH_S390X
1230
  return reinterpret_cast<T&>(Memory<uint64_t>(re_frame + frame_offset));
jyan's avatar
jyan committed
1231
#else
1232
  return reinterpret_cast<T&>(Memory<uint32_t>(re_frame + frame_offset));
jyan's avatar
jyan committed
1233 1234 1235 1236 1237 1238 1239 1240 1241
#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,
1242
                                                   Address raw_code,
jyan's avatar
jyan committed
1243
                                                   Address re_frame) {
1244
  Code re_code = Code::cast(Object(raw_code));
jyan's avatar
jyan committed
1245 1246 1247
  return NativeRegExpMacroAssembler::CheckStackGuardState(
      frame_entry<Isolate*>(re_frame, kIsolate),
      frame_entry<intptr_t>(re_frame, kStartIndex),
1248 1249 1250 1251
      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
1252 1253 1254 1255 1256 1257 1258 1259 1260 1261
      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(),
1262
                    kRegisterZero - register_index * kSystemPointerSize);
jyan's avatar
jyan committed
1263 1264 1265 1266 1267
}

void RegExpMacroAssemblerS390::CheckPosition(int cp_offset,
                                             Label* on_outside_input) {
  if (cp_offset >= 0) {
1268
    __ CmpS64(current_input_offset(), Operand(-cp_offset * char_size()));
jyan's avatar
jyan committed
1269 1270
    BranchOrBacktrack(ge, on_outside_input);
  } else {
1271
    __ LoadU64(r3, MemOperand(frame_pointer(), kStringStartMinusOne));
1272
    __ AddS64(r2, current_input_offset(), Operand(cp_offset * char_size()));
1273
    __ CmpS64(r2, r3);
jyan's avatar
jyan committed
1274 1275 1276 1277 1278 1279 1280
    BranchOrBacktrack(le, on_outside_input);
  }
}

void RegExpMacroAssemblerS390::BranchOrBacktrack(Condition condition, Label* to,
                                                 CRegister cr) {
  if (condition == al) {  // Unconditional.
1281
    if (to == nullptr) {
jyan's avatar
jyan committed
1282 1283 1284 1285 1286 1287
      Backtrack();
      return;
    }
    __ b(to);
    return;
  }
1288
  if (to == nullptr) {
jyan's avatar
jyan committed
1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305
    __ 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()));
1306
  __ AddS64(r14, ip);
jyan's avatar
jyan committed
1307 1308 1309 1310 1311 1312
  __ Ret();
}

void RegExpMacroAssemblerS390::SafeCallTarget(Label* name) {
  __ bind(name);
  __ CleanseP(r14);
1313
  __ mov(r0, r14);
jyan's avatar
jyan committed
1314
  __ mov(ip, Operand(masm_->CodeObject()));
1315
  __ SubS64(r0, r0, ip);
jyan's avatar
jyan committed
1316 1317 1318 1319
  __ push(r0);
}

void RegExpMacroAssemblerS390::Push(Register source) {
1320
  DCHECK(source != backtrack_stackpointer());
jyan's avatar
jyan committed
1321
  __ lay(backtrack_stackpointer(),
1322
         MemOperand(backtrack_stackpointer(), -kSystemPointerSize));
1323
  __ StoreU64(source, MemOperand(backtrack_stackpointer()));
jyan's avatar
jyan committed
1324 1325 1326
}

void RegExpMacroAssemblerS390::Pop(Register target) {
1327
  DCHECK(target != backtrack_stackpointer());
1328
  __ LoadU64(target, MemOperand(backtrack_stackpointer()));
jyan's avatar
jyan committed
1329
  __ la(backtrack_stackpointer(),
1330
        MemOperand(backtrack_stackpointer(), kSystemPointerSize));
jyan's avatar
jyan committed
1331 1332 1333 1334 1335
}

void RegExpMacroAssemblerS390::CheckPreemption() {
  // Check for preemption.
  ExternalReference stack_limit =
1336
      ExternalReference::address_of_jslimit(isolate());
jyan's avatar
jyan committed
1337
  __ mov(r2, Operand(stack_limit));
1338
  __ CmpU64(sp, MemOperand(r2));
jyan's avatar
jyan committed
1339 1340 1341 1342 1343
  SafeCall(&check_preempt_label_, le);
}

void RegExpMacroAssemblerS390::CheckStackLimit() {
  ExternalReference stack_limit =
1344
      ExternalReference::address_of_regexp_stack_limit_address(isolate());
jyan's avatar
jyan committed
1345
  __ mov(r2, Operand(stack_limit));
1346
  __ CmpU64(backtrack_stackpointer(), MemOperand(r2));
jyan's avatar
jyan committed
1347 1348 1349 1350 1351 1352
  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.
1353
  DCHECK_GE(8, num_arguments);
jyan's avatar
jyan committed
1354 1355 1356
  __ mov(code_pointer(), Operand(function));
  Label ret;
  __ larl(r14, &ret);
1357
  __ StoreU64(r14, MemOperand(sp, kStackFrameRASlot * kSystemPointerSize));
jyan's avatar
jyan committed
1358 1359
  __ b(code_pointer());
  __ bind(&ret);
1360
  if (base::OS::ActivationFrameAlignment() > kSystemPointerSize) {
1361
    __ LoadU64(
1362
        sp, MemOperand(sp, (kNumRequiredStackFrameSlots * kSystemPointerSize)));
jyan's avatar
jyan committed
1363
  } else {
1364 1365
    __ la(sp,
          MemOperand(sp, (kNumRequiredStackFrameSlots * kSystemPointerSize)));
jyan's avatar
jyan committed
1366 1367 1368 1369 1370 1371 1372 1373
  }
  __ mov(code_pointer(), Operand(masm_->CodeObject()));
}


void RegExpMacroAssemblerS390::LoadCurrentCharacterUnchecked(int cp_offset,
                                                             int characters) {
  if (mode_ == LATIN1) {
1374 1375
    // using load reverse for big-endian platforms
    if (characters == 4) {
1376 1377 1378
      __ LoadU32LE(current_character(),
                   MemOperand(current_input_offset(), end_of_input_address(),
                              cp_offset * char_size()));
1379
    } else if (characters == 2) {
1380 1381 1382
      __ LoadU16LE(current_character(),
                   MemOperand(current_input_offset(), end_of_input_address(),
                              cp_offset * char_size()));
1383
    } else {
1384
      DCHECK_EQ(1, characters);
1385
      __ LoadU8(current_character(),
1386 1387 1388
                MemOperand(current_input_offset(), end_of_input_address(),
                           cp_offset * char_size()));
    }
jyan's avatar
jyan committed
1389 1390
  } else {
    DCHECK(mode_ == UC16);
1391
    if (characters == 2) {
1392
      __ LoadU32(current_character(),
1393 1394 1395 1396 1397 1398 1399
                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 {
1400
      DCHECK_EQ(1, characters);
1401
      __ LoadU16(
1402 1403 1404 1405
          current_character(),
                MemOperand(current_input_offset(), end_of_input_address(),
                           cp_offset * char_size()));
    }
jyan's avatar
jyan committed
1406 1407 1408 1409 1410 1411 1412 1413 1414
  }
}

#undef __

}  // namespace internal
}  // namespace v8

#endif  // V8_TARGET_ARCH_S390