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