| OLD | NEW |
| (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 "v8.h" |
| 29 #include "regexp-macro-assembler-ia32.h" |
| 30 |
| 31 namespace v8 { namespace internal { |
| 32 |
| 33 /* |
| 34 * This assembler uses the following register assignment convention |
| 35 * - edx : current character, or kEndOfInput if current position is not |
| 36 * inside string. The kEndOfInput value is greater than 0xffff, |
| 37 * so any tests that don't check whether the current position |
| 38 * is inside the correct range should retain bits above the |
| 39 * 15th in their computations, and fail if the value is too |
| 40 * great. |
| 41 * - edi : current position in input. |
| 42 * - esi : end of input (points to byte after last character in input). |
| 43 * - ebp : points to the location above the registers on the stack, |
| 44 * as if by the "enter <register_count>" opcode. |
| 45 * - esp : points to tip of backtracking stack. |
| 46 * |
| 47 * The registers eax, ebx and eax are free to use for computations. |
| 48 * |
| 49 * Each call to a public method should retain this convention. |
| 50 * The stack is expected to have the following structure (tentative): |
| 51 * |
| 52 * - pointer to array where captures can be stored |
| 53 * - end of input |
| 54 * - start of input |
| 55 * - return address |
| 56 * ebp-> - old ebp |
| 57 * - register 0 ebp[-4] |
| 58 * - register 1 ebp[-8] |
| 59 * - ... |
| 60 * |
| 61 * The data before ebp must be placed there by the calling code. |
| 62 */ |
| 63 |
| 64 RegExpMacroAssemblerIA32::RegExpMacroAssemblerIA32() |
| 65 : masm_(new MacroAssembler(NULL, kRegExpCodeSize)), |
| 66 constants_(kRegExpConstantsSize), |
| 67 num_registers_(0), |
| 68 ignore_case(false) {} |
| 69 |
| 70 |
| 71 RegExpMacroAssemblerIA32::~RegExpMacroAssemblerIA32() { |
| 72 delete masm_; |
| 73 } |
| 74 |
| 75 |
| 76 #define __ masm_-> |
| 77 |
| 78 void RegExpMacroAssemblerIA32::AdvanceCurrentPosition(int by) { |
| 79 __ add(edi, by * sizeof(SubjectChar)); |
| 80 __ cmp(edi, esi); |
| 81 Label inside_string; |
| 82 Backtrack(); |
| 83 |
| 84 __ bind(&inside_string); |
| 85 ReadChar(edx, 0); |
| 86 } |
| 87 |
| 88 |
| 89 void RegExpMacroAssemblerIA32::AdvanceRegister(int reg, int by) { |
| 90 ASSERT(reg >= 0); |
| 91 ASSERT(reg < num_registers); |
| 92 __ add(register_location(reg), by); |
| 93 } |
| 94 |
| 95 |
| 96 void RegExpMacroAssemblerIA32::Backtrack() { |
| 97 __ ret(); |
| 98 } |
| 99 |
| 100 |
| 101 void RegExpMacroAssemblerIA32::Bind(Label* label) { |
| 102 __ bind(label); |
| 103 } |
| 104 |
| 105 |
| 106 void RegExpMacroAssemblerIA32::CheckBitmap(uc16 start, |
| 107 Label* bitmap, |
| 108 Label* on_zero) { |
| 109 ReadCurrentChar(eax); |
| 110 __ sub(eax, start); |
| 111 __ cmp(eax, 64); // FIXME: 64 = length_of_bitmap_in_bits. |
| 112 BranchOrBacktrack(greater_equal, on_zero); |
| 113 __ mov(ebx, eax); |
| 114 __ shr(ebx, 3); |
| 115 // TODO: Where is the bitmap stored? Pass the bitmap as argument instead. |
| 116 // __ mov(ecx, position_of_bitmap); |
| 117 __ movzx_b(ebx, Operand(ecx, ebx, times_1, 0)); |
| 118 __ and_(eax, (1<<3)-1); |
| 119 __ bt(ebx, eax); |
| 120 __ j(greater_equal, on_zero); // Aka. jump on carry set. |
| 121 } |
| 122 |
| 123 |
| 124 void RegExpMacroAssemblerIA32::CheckCharacterClass(RegExpCharacterClass *cclass, |
| 125 Label* on_failure) { |
| 126 UNREACHABLE(); // Not implemented. |
| 127 } |
| 128 |
| 129 |
| 130 void RegExpMacroAssemblerIA32::CheckCharacters(Vector<uc16> str, |
| 131 Label* on_failure) { |
| 132 if (sizeof(SubjectChar) == 1) { |
| 133 for (int i = 0; i < str.length(); i++) { |
| 134 if (str[i] > String::kMaxAsciiCharCode) { |
| 135 __ jmp(on_failure); |
| 136 return; |
| 137 } |
| 138 } |
| 139 } |
| 140 int byte_length = str.length() * sizeof(SubjectChar); |
| 141 __ mov(ebx, edi); |
| 142 __ add(ebx, byte_length); |
| 143 __ cmp(ebx, esi); |
| 144 BranchOrBacktrack(greater_equal, on_failure); |
| 145 |
| 146 if (str.length() <= kMaxInlineStringTests || ignore_case()) { |
| 147 // TODO: make proper loop if str.length is large but ignore_case is true; |
| 148 for(int i = 0; i < str.length(); i++) { |
| 149 ReadChar(eax, i); |
| 150 if (ignore_case()) { |
| 151 Canonicalize(eax); |
| 152 } |
| 153 __ cmp(eax, str[i]); |
| 154 BranchOrBacktrack(not_equal, on_failure); |
| 155 } |
| 156 add(edi, byte_length); |
| 157 } else { |
| 158 int offset; |
| 159 ArraySlice<SubjectChar> constant_buffer = |
| 160 constants_.GetBuffer<SubjectChar>(str.length()); |
| 161 for (int i = 0; i < str.length(); i++) { |
| 162 constant_buffer[i] = str[i]; |
| 163 } |
| 164 __ mov(ebx, esi); |
| 165 LoadConstantBufferAddress(esi, constant_buffer); |
| 166 __ mov(ecx, str.length()); |
| 167 if (sizeof(SubjectChar) == 1) { |
| 168 __ rep_cmpsb(); |
| 169 } else { |
| 170 ASSERT(sizeof(SubjectChar)==2); |
| 171 __ rep_cmpsw(); |
| 172 } |
| 173 __ mov(esi, ebx); |
| 174 BranchOrBacktrack(not_equal, on_failure); |
| 175 } |
| 176 }; |
| 177 |
| 178 |
| 179 void RegExpMacroAssemblerIA32::CheckCurrentPosition(int register_index, |
| 180 Label* on_equal) { |
| 181 __ cmp(register_location(register_index), edi); |
| 182 BranchOrBacktrack(equal, on_equal); |
| 183 } |
| 184 |
| 185 |
| 186 void RegExpMacroAssemblerIA32::DispatchHalfNibbleMap( |
| 187 uc16 start, |
| 188 Label* half_nibble_map, |
| 189 const Vector<Label*>& destinations) { |
| 190 |
| 191 if (sizeof(SubjectChar) == 1 && start > String::kMaxAsciiCharCode) { |
| 192 return; |
| 193 } |
| 194 |
| 195 Label fallthrough; |
| 196 |
| 197 ReadCurrentChar(eax); |
| 198 __ sub(eax, start); |
| 199 __ cmp(eax, 64); // FIXME: 64 = size of map in bytes. Found somehow?? |
| 200 __ j(greater_equal, &fallthrough); |
| 201 |
| 202 __ mov(ebx, eax); |
| 203 __ shr(eax, 2); |
| 204 __ movzx_b(eax, Operand(ecx, eax)); // FIXME: ecx holds address of map |
| 205 Label got_nybble; |
| 206 Label high_bits; |
| 207 __ and_(ebx, 0x03); |
| 208 __ shr(eax, ebx); |
| 209 |
| 210 Label second_bit_set, case_3, case_1; |
| 211 __ test(eax, 2); |
| 212 __ j(not_equal, &second_bit_set); |
| 213 __ test(eax, 1); |
| 214 __ j(not_equal, &case_1); |
| 215 // Case 0: |
| 216 __ jmp(&destinations[0]); |
| 217 __ bind(&case_1); |
| 218 // Case 1: |
| 219 __ jmp(&destinations[1]); |
| 220 __ bind(&second_bit_set); |
| 221 __ test(eax, 1); |
| 222 __ j(not_equal, &case_3); |
| 223 // Case 2 |
| 224 __ jmp(&destinations[2]); |
| 225 __ bind(&case_3); |
| 226 // Case 3: |
| 227 __ jmp(&destinations[3]); |
| 228 |
| 229 __ bind(&fallthrough); |
| 230 } |
| 231 |
| 232 |
| 233 void RegExpMacroAssemblerIA32::DispatchByteMap( |
| 234 uc16 start, |
| 235 Label* byte_map, |
| 236 const Vector<Label*>& destinations) { |
| 237 |
| 238 if (sizeof(SubjectChar) == 1 && start > String::kMaxAsciiCharCode) { |
| 239 return; |
| 240 } |
| 241 |
| 242 Label fallthrough; |
| 243 |
| 244 ReadCurrentChar(eax); |
| 245 __ sub(eax, start); |
| 246 __ cmp(eax, 64); // FIXME: 64 = size of map. Found somehow?? |
| 247 __ j(greater_equal, &fallthrough); |
| 248 |
| 249 __ movzx_b(eax, Operand(ecx, eax)); // FIXME: ecx must hold address of map |
| 250 // jump table: jump to destinations[eax]; |
| 251 |
| 252 __ bind(&fallthrough); |
| 253 } |
| 254 |
| 255 void RegExpMacroAssemblerIA32::DispatchHighByteMap( |
| 256 byte start, |
| 257 Label* byte_map, |
| 258 const Vector<Label*>& destinations) { |
| 259 Label fallthrough; |
| 260 ReadCurrentChar(eax); |
| 261 __ shr(eax, 8); |
| 262 __ sub(eax, start); |
| 263 __ cmp(eax, destinations.length() - start); |
| 264 __ j(greater_equal, &fallthrough); |
| 265 |
| 266 // TODO jumptable: jump to destinations[eax] |
| 267 __ bind(&fallthrough); |
| 268 } |
| 269 |
| 270 |
| 271 void RegExpMacroAssemblerIA32::EmitOrLink(Label* label) { |
| 272 UNREACHABLE(); // Has no use. |
| 273 } |
| 274 |
| 275 |
| 276 void RegExpMacroAssemblerIA32::Fail() { |
| 277 Exit(false); |
| 278 } |
| 279 |
| 280 Handle<Object> RegExpMacroAssemblerIA32::GetCode() { |
| 281 // something |
| 282 return Handle(); |
| 283 } |
| 284 |
| 285 |
| 286 void RegExpMacroAssemblerIA32::GoTo(Label &to) { |
| 287 __ jmp(to); |
| 288 } |
| 289 |
| 290 |
| 291 void RegExpMacroAssemblerIA32::IfRegisterGE(int reg, |
| 292 int comparand, |
| 293 Label* if_ge) { |
| 294 __ cmp(register_location(reg), comparand); |
| 295 BranchOrBacktrack(greater_equal, if_ge); |
| 296 } |
| 297 |
| 298 |
| 299 void RegExpMacroAssemblerIA32::IfRegisterLT(int reg, |
| 300 int comparand, |
| 301 Label* if_lt) { |
| 302 __ cmp(register_location(reg), comparand); |
| 303 BranchOrBacktrack(less, if_lt); |
| 304 } |
| 305 |
| 306 |
| 307 Re2kImplementation RegExpMacroAssemblerIA32::Implementation() { |
| 308 return kIA32Implementation; |
| 309 } |
| 310 |
| 311 |
| 312 void RegExpMacroAssemblerIA32::PopCurrentPosition() { |
| 313 __ pop(edi); |
| 314 ReadChar(edx, 0); |
| 315 } |
| 316 |
| 317 |
| 318 void RegExpMacroAssemblerIA32::PopRegister(int register_index) { |
| 319 __ pop(register_location(register_index)); |
| 320 } |
| 321 |
| 322 |
| 323 void RegExpMacroAssemblerIA32::PushBacktrack(Label* label) { |
| 324 Label cont; |
| 325 __ call(&cont); |
| 326 __ jmp(label); |
| 327 __ bind(&cont); |
| 328 } |
| 329 |
| 330 |
| 331 void RegExpMacroAssemblerIA32::PushCurrentPosition() { |
| 332 __ push(edi); |
| 333 } |
| 334 |
| 335 |
| 336 void RegExpMacroAssemblerIA32::PushRegister(int register_index) { |
| 337 __ push(register_location(register_index)); |
| 338 } |
| 339 |
| 340 |
| 341 void RegExpMacroAssemblerIA32::SetRegister(int register_index, int to) { |
| 342 __ mov(register_location(register_index), to); |
| 343 } |
| 344 |
| 345 |
| 346 void RegExpMacroAssemblerIA32::Succeed() { |
| 347 Exit(true); |
| 348 } |
| 349 |
| 350 void RegExpMacroAssemblerIA32::WriteCurrentPositionToRegister() { |
| 351 __ mov(register_location(register_index), edi); |
| 352 } |
| 353 |
| 354 // Custom : |
| 355 |
| 356 void RegExpMacroAssemblerIA32::Initialize(int num_registers, bool ignore_case) { |
| 357 num_registers_ = num_registers; |
| 358 ignore_case_ = ignore_case; |
| 359 __ enter(num_registers * sizeof(uint32_t)); |
| 360 } |
| 361 |
| 362 |
| 363 Operand RegExpMacroAssemblerIA32::register_location(int register_index) { |
| 364 ASSERT(register_index < (1<<30)); |
| 365 return Operand(ebp, -((register_index + 1) * sizeof(uint32_t))); |
| 366 } |
| 367 |
| 368 |
| 369 void RegExpMacroAssemblerIA32::BranchOrBacktrack(Condition condition, |
| 370 Label* to) { |
| 371 if (condition < 0) { // No condition |
| 372 if (to == NULL) { |
| 373 Backtrack(); |
| 374 return; |
| 375 } |
| 376 __ jmp(to); |
| 377 return; |
| 378 } else if (to == NULL) { |
| 379 Label skip; |
| 380 __ j(NegateCondition(condition), &skip); |
| 381 Backtrack(); |
| 382 __ bind(&skip); |
| 383 return; |
| 384 } |
| 385 __ j(condition, to); |
| 386 } |
| 387 |
| 388 |
| 389 void RegExpMacroAssemblerIA32::Canonicalize(Register reg) { |
| 390 if (sizeof(SubjectChar) == 1) { |
| 391 Label end; |
| 392 __ cmp(reg, 'a'); |
| 393 __ j(below, &end); |
| 394 __ cmp(reg, 'z'); |
| 395 __ j(above, &end); |
| 396 __ sub(reg, 'a' - 'A'); |
| 397 __ bind(&end); |
| 398 return; |
| 399 } |
| 400 ASSERT(sizeof(SubjectChar) == 2); |
| 401 // TODO: Use some tables. |
| 402 } |
| 403 |
| 404 |
| 405 void RegExpMacroAssemblerIA32::Exit(bool success) { |
| 406 if (success) { |
| 407 // Copy captures to output capture array. |
| 408 } |
| 409 __ leave(); |
| 410 __ mov(eax, success ? 1 : 0); |
| 411 __ ret(); |
| 412 } |
| 413 |
| 414 |
| 415 void RegExpMacroAssemblerIA32::ReadChar(Register destination, int offset) { |
| 416 if (sizeof(SubjectChar) == 1) { |
| 417 __ movzx_b(destination, Operand(edi, offset)); |
| 418 return; |
| 419 } |
| 420 ASSERT(sizeof(SubjectChar) == 2); |
| 421 __ movzx_w(destination, Operand(edi, offset * 2)); |
| 422 } |
| 423 |
| 424 |
| 425 void RegExpMacroAssemblerIA32::ReadCurrentChar(Register destination) { |
| 426 mov(destination, edx); |
| 427 } |
| 428 |
| 429 |
| 430 template <typename T> |
| 431 void LoadConstantBufferAddress(Register reg, ArraySlice<T>& buffer) { |
| 432 __ mov(reg, buffer.array()); |
| 433 __ add(reg, buffer.base_offset()); |
| 434 } |
| 435 |
| 436 #undef __ |
| 437 }} |
| OLD | NEW |