Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(382)

Side by Side Diff: src/regexp-macro-assembler-ia32.cc

Issue 12427: Merge regexp2000 back into bleeding_edge (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: Created 12 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2008 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #include <string.h>
29 #include "v8.h"
30 #include "log.h"
31 #include "ast.h"
32 #include "macro-assembler.h"
33 #include "regexp-macro-assembler-ia32.h"
34
35 namespace v8 { namespace internal {
36 /*
37 * This assembler uses the following register assignment convention
38 * - edx : current character, or kEndOfInput if current position is not
39 * inside string. The kEndOfInput value is greater than 0xffff,
40 * so any tests that don't check whether the current position
41 * is inside the correct range should retain bits above the
42 * 15th in their computations, and fail if the value is too
43 * great.
44 * - edi : current position in input, as negative offset from end of string.
45 * - esi : end of input (points to byte after last character in input).
46 * - ebp : points to the location above the registers on the stack,
47 * as if by the "enter <register_count>" opcode.
48 * - esp : points to tip of backtracking stack.
49 *
50 * The registers eax, ebx and ecx are free to use for computations.
51 *
52 * Each call to a public method should retain this convention.
53 * The stack will have the following structure:
54 * - int* capture_array (int[num_saved_registers_], for output).
55 * - end of input (index of end of string, relative to *string_base)
56 * - start of input (index of first character in string, relative
57 * to *string_base)
58 * - void** string_base (location of a handle containing the string)
59 * - return address
60 * - backup of esi
61 * - backup of edi
62 * ebp-> - old ebp
63 * - register 0 ebp[-4]
64 * - register 1 ebp[-8]
65 * - ...
66 *
67 * The data before ebp must be placed there by the calling code, e.g.,
68 * by calling the code as cast to:
69 * bool (*match)(String** string_base,
70 * int start_offset,
71 * int end_offset,
72 * int* capture_output_array)
73 */
74
75 #define __ masm_->
76
77 RegExpMacroAssemblerIA32::RegExpMacroAssemblerIA32(
78 Mode mode,
79 int registers_to_save,
80 bool ignore_case)
81 : masm_(new MacroAssembler(NULL, kRegExpCodeSize)),
Mads Ager (chromium) 2008/11/25 21:09:41 Guess what? :-)
82 constants_(kRegExpConstantsSize),
83 mode_(mode),
84 num_registers_(registers_to_save),
85 num_saved_registers_(registers_to_save),
86 ignore_case_(ignore_case),
87 entry_label_(),
88 start_label_(),
89 success_label_(),
90 exit_label_(),
91 self_(Heap::undefined_value()) {
92 __ jmp(&entry_label_); // We'll write the entry code later.
93 __ bind(&start_label_); // And then continue from here.
94 }
95
96
97 RegExpMacroAssemblerIA32::~RegExpMacroAssemblerIA32() {
98 delete masm_;
99 // Unuse labels in case we throw away the assembler without calling GetCode.
100 entry_label_.Unuse();
101 start_label_.Unuse();
102 success_label_.Unuse();
103 exit_label_.Unuse();
104 }
105
106
107 void RegExpMacroAssemblerIA32::AdvanceCurrentPosition(int by) {
108 ASSERT(by > 0);
109 Label inside_string;
110 __ add(Operand(edi), Immediate(by * char_size()));
111 __ j(below, &inside_string);
112 Backtrack();
113
114 __ bind(&inside_string);
115 }
116
117
118 void RegExpMacroAssemblerIA32::AdvanceRegister(int reg, int by) {
119 ASSERT(reg >= 0);
120 ASSERT(reg < num_registers_);
121 __ add(register_location(reg), Immediate(by));
122 }
123
124
125 void RegExpMacroAssemblerIA32::Backtrack() {
126 __ pop(ecx);
127 __ add(Operand(ecx), Immediate(self_));
128 __ jmp(Operand(ecx));
129 }
130
131
132 void RegExpMacroAssemblerIA32::Bind(Label* label) {
133 __ bind(label);
134 }
135
136 void RegExpMacroAssemblerIA32::CheckBitmap(uc16 start,
137 Label* bitmap,
138 Label* on_zero) {
139 ReadCurrentChar(eax);
140 __ sub(Operand(eax), Immediate(start));
141 __ cmp(eax, 64); // FIXME: 64 = length_of_bitmap_in_bits.
142 BranchOrBacktrack(greater_equal, on_zero);
143 __ mov(ebx, eax);
144 __ shr(ebx, 3);
145 // TODO(lrn): Where is the bitmap stored? Pass the bitmap as argument instead.
146 // __ mov(ecx, position_of_bitmap);
147 __ movzx_b(ebx, Operand(ecx, ebx, times_1, 0));
148 __ and_(eax, (1<<3)-1);
149 __ bt(Operand(ebx), eax);
150 __ j(carry, on_zero);
151 }
152
153
154 void RegExpMacroAssemblerIA32::CheckCharacter(uc16 c, Label* on_equal) {
155 __ cmp(edx, c);
156 BranchOrBacktrack(equal, on_equal);
157 }
158
159
160 void RegExpMacroAssemblerIA32::CheckCharacterGT(uc16 limit, Label* on_greater) {
161 __ cmp(edx, limit);
162 BranchOrBacktrack(greater, on_greater);
163 }
164
165
166 void RegExpMacroAssemblerIA32::CheckCharacterLT(uc16 limit, Label* on_less) {
167 __ cmp(edx, limit);
168 BranchOrBacktrack(less, on_less);
169 }
170
171
172 void RegExpMacroAssemblerIA32::CheckCharacters(Vector<const uc16> str,
173 int cp_offset,
174 Label* on_failure) {
175 int byte_length = str.length() * char_size();
176 int start_offset = cp_offset * char_size();
177 __ mov(ebx, edi);
178 __ add(Operand(ebx), Immediate(start_offset + byte_length));
179 BranchOrBacktrack(greater_equal, on_failure);
180
181 ArraySlice constant_buffer = constants_.GetBuffer(str.length(), char_size());
182 for (int i = 0; i < str.length(); i++) {
183 if (mode_ == ASCII) {
184 constant_buffer.at<char>(i) = static_cast<char>(str[i]);
185 } else {
186 memcpy(constant_buffer.location<void>(),
187 str.start(),
188 str.length() * sizeof(uc16));
189 }
190 }
191
192 __ mov(eax, edi);
193 __ mov(ebx, esi);
194 __ lea(edi, Operand(esi, edi, times_1, start_offset));
195 LoadConstantBufferAddress(esi, &constant_buffer);
196 __ mov(ecx, str.length());
197 if (mode_ == ASCII) {
198 __ rep_cmpsb();
199 } else {
200 ASSERT(mode_ == UC16);
201 __ rep_cmpsw();
202 }
203 __ mov(esi, ebx);
204 __ mov(edi, eax);
205 BranchOrBacktrack(not_equal, on_failure);
206 }
207
208
209 void RegExpMacroAssemblerIA32::CheckCurrentPosition(int register_index,
210 Label* on_equal) {
211 __ cmp(edi, register_location(register_index));
212 BranchOrBacktrack(equal, on_equal);
213 }
214
215
216 void RegExpMacroAssemblerIA32::CheckNotBackReference(
217 int start_reg, Label* on_no_match) {
218 if (ignore_case_) {
219 UNIMPLEMENTED();
220 }
221 Label fallthrough;
222 __ mov(eax, register_location(start_reg));
223 __ mov(ecx, register_location(start_reg + 1));
224 __ sub(ecx, Operand(eax)); // Length to check.
225 __ j(equal, &fallthrough); // Covers the case where it's not bound (-1,-1).
226 __ mov(ebx, Operand(edi));
227 __ push(esi);
228 __ add(edi, Operand(esi));
229 __ add(esi, Operand(eax));
230 if (mode_ == ASCII) {
231 __ rep_cmpsb();
232 } else {
233 __ rep_cmpsw();
234 }
235 __ pop(esi);
236 __ mov(edi, Operand(ebx));
237 BranchOrBacktrack(not_equal, on_no_match);
238 __ bind(&fallthrough);
239 }
240
241
242 void RegExpMacroAssemblerIA32::CheckNotCharacter(uc16 c, Label* on_not_equal) {
243 __ cmp(edx, c);
244 BranchOrBacktrack(not_equal, on_not_equal);
245 }
246
247
248 void RegExpMacroAssemblerIA32::CheckNotCharacterAfterOr(uc16 c,
249 uc16 mask,
250 Label* on_not_equal) {
251 __ mov(eax, Operand(edx));
252 __ or_(eax, mask);
253 __ cmp(eax, c);
254 BranchOrBacktrack(not_equal, on_not_equal);
255 }
256
257
258 void RegExpMacroAssemblerIA32::CheckNotCharacterAfterMinusOr(
259 uc16 c,
260 uc16 mask,
261 Label* on_not_equal) {
262 __ lea(eax, Operand(edx, -mask));
263 __ or_(eax, mask);
264 __ cmp(eax, c);
265 BranchOrBacktrack(not_equal, on_not_equal);
266 }
267
268
269 void RegExpMacroAssemblerIA32::DispatchHalfNibbleMap(
270 uc16 start,
271 Label* half_nibble_map,
272 const Vector<Label*>& destinations) {
273 ReadCurrentChar(eax);
274 __ sub(Operand(eax), Immediate(start));
275
276 __ mov(ecx, eax);
277 __ shr(eax, 2);
278 // FIXME: ecx must hold address of map
279 __ movzx_b(eax, Operand(ecx, eax, times_1, 0));
280 __ and_(ecx, 0x03);
281 __ add(ecx, Operand(ecx));
282 __ shr(eax); // Shift right cl times
283
284 Label second_bit_set, case_3, case_1;
285 __ test(eax, Immediate(0x02));
286 __ j(not_zero, &second_bit_set);
287 __ test(eax, Immediate(0x01));
288 __ j(not_zero, &case_1);
289 // Case 0:
290 __ jmp(destinations[0]);
291 __ bind(&case_1);
292 // Case 1:
293 __ jmp(destinations[1]);
294 __ bind(&second_bit_set);
295 __ test(eax, Immediate(0x01));
296 __ j(not_zero, &case_3);
297 // Case 2
298 __ jmp(destinations[2]);
299 __ bind(&case_3);
300 // Case 3:
301 __ jmp(destinations[3]);
302 }
303
304
305 void RegExpMacroAssemblerIA32::DispatchByteMap(
306 uc16 start,
307 Label* byte_map,
308 const Vector<Label*>& destinations) {
309 Label fallthrough;
310 ReadCurrentChar(eax);
311 __ sub(Operand(eax), Immediate(start));
312 __ cmp(eax, 64); // FIXME: 64 = size of map. Found somehow??
313 __ j(greater_equal, &fallthrough);
314 // FIXME: ecx must hold address of map
315 __ movzx_b(eax, Operand(ecx, eax, times_1, 0));
316 // jump table: jump to destinations[eax];
317
318 __ bind(&fallthrough);
319 }
320
321
322
323 void RegExpMacroAssemblerIA32::DispatchHighByteMap(
324 byte start,
325 Label* byte_map,
326 const Vector<Label*>& destinations) {
327 Label fallthrough;
328 ReadCurrentChar(eax);
329 __ shr(eax, 8);
330 __ sub(Operand(eax), Immediate(start));
331 __ cmp(eax, destinations.length() - start);
332 __ j(greater_equal, &fallthrough);
333
334 // TODO(lrn) jumptable: jump to destinations[eax]
335 __ bind(&fallthrough);
336 }
337
338
339 void RegExpMacroAssemblerIA32::EmitOrLink(Label* label) {
340 UNREACHABLE(); // Has no use.
341 }
342
343
344 void RegExpMacroAssemblerIA32::Fail() {
345 __ mov(eax, 0);
346 __ jmp(&exit_label_);
347 }
348
349
350 Handle<Object> RegExpMacroAssemblerIA32::GetCode() {
351 // Finalize code - write the entry point code now we know how many
352 // registers we need.
353
354 // Entry code:
355 __ bind(&entry_label_);
356 __ push(esi);
357 __ push(edi);
358 __ enter(Immediate(num_registers_ * sizeof(uint32_t)));
359 __ mov(esi, Operand(ebp, kInputEndOffset));
360 __ mov(edi, Operand(ebp, kInputStartOffset));
361 __ sub(edi, Operand(esi));
362 __ mov(edx, Operand(ebp, kInputBuffer));
363 __ mov(edx, Operand(edx, 0));
364 __ add(esi, Operand(edx));
365 __ jmp(&start_label_);
366
367 // Exit code:
368 __ bind(&success_label_);
369 __ mov(ebx, Operand(ebp, kRegisterOutput));
370 __ mov(ecx, Operand(ebp, kInputEndOffset));
371 __ sub(ecx, Operand(ebp, kInputStartOffset));
372 for (int i = 0; i < num_saved_registers_; i++) {
373 __ mov(eax, register_location(i));
374 __ sub(eax, Operand(ecx)); // Convert to index from start, not end.
375 __ mov(Operand(ebx, i * sizeof(int32_t)), eax);
376 }
377 // copy captures to output
378 __ mov(eax, Immediate(1));
379
380 __ bind(&exit_label_);
381 __ leave();
382 __ pop(edi);
383 __ pop(esi);
384 __ ret(0);
385
386 CodeDesc code_desc;
387 masm_->GetCode(&code_desc);
388 Handle<Code> code = Factory::NewCode(code_desc,
389 NULL,
390 Code::ComputeFlags(Code::REGEXP),
391 self_);
392 LOG(CodeCreateEvent("RegExp", *code, "(Compiled RegExp)"));
393 return Handle<Object>::cast(code);
394 }
395
396
397 void RegExpMacroAssemblerIA32::GoTo(Label* to) {
398 __ jmp(to);
399 }
400
401
402
403 void RegExpMacroAssemblerIA32::IfRegisterGE(int reg,
404 int comparand,
405 Label* if_ge) {
406 __ cmp(register_location(reg), Immediate(comparand));
407 BranchOrBacktrack(greater_equal, if_ge);
408 }
409
410
411
412 void RegExpMacroAssemblerIA32::IfRegisterLT(int reg,
413 int comparand,
414 Label* if_lt) {
415 __ cmp(register_location(reg), Immediate(comparand));
416 BranchOrBacktrack(less, if_lt);
417 }
418
419
420
421 RegExpMacroAssembler::IrregexpImplementation
422 RegExpMacroAssemblerIA32::Implementation() {
423 return kIA32Implementation;
424 }
425
426
427
428 void RegExpMacroAssemblerIA32::LoadCurrentCharacter(int cp_offset,
429 Label* on_end_of_input) {
430 ASSERT(cp_offset >= 0);
431 ASSERT(cp_offset < (1<<30)); // Be sane! (And ensure negation works)
432 __ cmp(edi, -cp_offset);
433 BranchOrBacktrack(less_equal, on_end_of_input);
434 ReadChar(edx, cp_offset);
435 }
436
437
438 void RegExpMacroAssemblerIA32::PopCurrentPosition() {
439 __ pop(edi);
440 }
441
442
443 void RegExpMacroAssemblerIA32::PopRegister(int register_index) {
444 RecordRegister(register_index);
445 __ pop(register_location(register_index));
446 }
447
448
449 void RegExpMacroAssemblerIA32::PushBacktrack(Label* label) {
450 // Check for preemption first.
451 Label no_preempt;
452 Label retry_preempt;
453 // Check for preemption.
454 ExternalReference stack_limit =
455 ExternalReference::address_of_stack_guard_limit();
456 __ cmp(esp, Operand::StaticVariable(stack_limit));
457 __ j(above, &no_preempt);
458
459 __ push(edi); // Current position.
460 __ push(edx); // Current character.
461 // Restore original edi, esi.
462 __ mov(edi, Operand(ebp, kBackup_edi));
463 __ mov(esi, Operand(ebp, kBackup_esi));
464
465 __ bind(&retry_preempt);
466 // simulate stack for Runtime call.
467 __ push(Immediate(0)); // Dummy receiver
468 __ CallRuntime(Runtime::kStackGuard, 0);
469 __ cmp(esp, Operand::StaticVariable(stack_limit));
470 __ j(below_equal, &retry_preempt);
471
472 __ pop(edx);
473 __ pop(edi);
474 __ mov(esi, Operand(ebp, kInputBuffer));
475 __ mov(esi, Operand(esi, 0));
476 __ add(esi, Operand(ebp, kInputEndOffset));
477
478 __ bind(&no_preempt);
479
480 Label cont;
481 __ push(label, RelocInfo::NONE);
482 }
483
484
485 void RegExpMacroAssemblerIA32::PushCurrentPosition() {
486 __ push(edi);
487 }
488
489
490 void RegExpMacroAssemblerIA32::PushRegister(int register_index) {
491 __ push(register_location(register_index));
492 }
493
494
495 void RegExpMacroAssemblerIA32::ReadCurrentPositionFromRegister(int reg) {
496 __ mov(edi, register_location(reg));
497 }
498
499
500 void RegExpMacroAssemblerIA32::ReadStackPointerFromRegister(int reg) {
501 __ mov(esp, register_location(reg));
502 }
503
504
505 void RegExpMacroAssemblerIA32::SetRegister(int register_index, int to) {
506 RecordRegister(register_index);
507 __ mov(register_location(register_index), Immediate(to));
508 }
509
510
511 void RegExpMacroAssemblerIA32::Succeed() {
512 __ jmp(&success_label_);
513 }
514
515
516 void RegExpMacroAssemblerIA32::WriteCurrentPositionToRegister(
517 int register_index) {
518 __ mov(register_location(register_index), edi);
519 }
520
521 void RegExpMacroAssemblerIA32::WriteStackPointerToRegister(int reg) {
522 __ mov(register_location(reg), esp);
523 }
524
525
526 // Private methods:
527
528 Operand RegExpMacroAssemblerIA32::register_location(
529 int register_index) {
530 ASSERT(register_index < (1<<30));
531 return Operand(ebp, -((register_index + 1) * sizeof(uint32_t)));
532 }
533
534
535 size_t RegExpMacroAssemblerIA32::char_size() {
536 return static_cast<size_t>(mode_);
537 }
538
539
540 void RegExpMacroAssemblerIA32::BranchOrBacktrack(Condition condition,
541 Label* to) {
542 if (condition < 0) { // No condition
543 if (to == NULL) {
544 Backtrack();
545 return;
546 }
547 __ jmp(to);
548 return;
549 } else if (to == NULL) {
550 Label skip;
551 __ j(NegateCondition(condition), &skip);
552 Backtrack();
553 __ bind(&skip);
554 return;
555 }
556 __ j(condition, to);
557 }
558
559
560 void RegExpMacroAssemblerIA32::Canonicalize(Register reg) {
561 if (mode_ == ASCII) {
562 Label end;
563 __ cmp(Operand(reg), Immediate('a'));
564 __ j(below, &end);
565 __ cmp(Operand(reg), Immediate('z'));
566 __ j(above, &end);
567 __ sub(Operand(reg), Immediate('a' - 'A'));
568 __ bind(&end);
569 return;
570 }
571 ASSERT(mode_ == UC16);
572 // TODO(lrn): Use some tables.
573 }
574
575
576 void RegExpMacroAssemblerIA32::RecordRegister(int register_index) {
577 if (register_index >= num_registers_) {
578 num_registers_ = register_index + 1;
579 }
580 }
581
582
583 void RegExpMacroAssemblerIA32::ReadChar(Register destination, int offset) {
584 if (mode_ == ASCII) {
585 __ movzx_b(destination, Operand(esi, edi, times_1, offset));
586 return;
587 }
588 ASSERT(mode_ == UC16);
589 __ movzx_w(destination, Operand(esi, edi, times_1, offset * 2));
590 }
591
592
593 void RegExpMacroAssemblerIA32::ReadCurrentChar(Register destination) {
594 __ mov(destination, edx);
595 }
596
597
598 void RegExpMacroAssemblerIA32::LoadConstantBufferAddress(Register reg,
599 ArraySlice* buffer) {
600 __ mov(reg, buffer->array());
601 __ add(Operand(reg), Immediate(buffer->base_offset()));
602 }
603
604 #undef __
605 }}
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698