OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #if V8_TARGET_ARCH_ARM | 5 #if V8_TARGET_ARCH_ARM |
6 | 6 |
7 #include "src/code-stubs.h" | 7 #include "src/code-stubs.h" |
8 | 8 |
9 #include "src/api-arguments.h" | 9 #include "src/api-arguments.h" |
10 #include "src/assembler-inl.h" | 10 #include "src/assembler-inl.h" |
(...skipping 1135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1146 } | 1146 } |
1147 #endif | 1147 #endif |
1148 | 1148 |
1149 // Restore callee-saved vfp registers. | 1149 // Restore callee-saved vfp registers. |
1150 __ vldm(ia_w, sp, kFirstCalleeSavedDoubleReg, kLastCalleeSavedDoubleReg); | 1150 __ vldm(ia_w, sp, kFirstCalleeSavedDoubleReg, kLastCalleeSavedDoubleReg); |
1151 | 1151 |
1152 __ ldm(ia_w, sp, kCalleeSaved | pc.bit()); | 1152 __ ldm(ia_w, sp, kCalleeSaved | pc.bit()); |
1153 } | 1153 } |
1154 | 1154 |
1155 void RegExpExecStub::Generate(MacroAssembler* masm) { | 1155 void RegExpExecStub::Generate(MacroAssembler* masm) { |
1156 // Just jump directly to runtime if native RegExp is not selected at compile | |
1157 // time or if regexp entry in generated code is turned off runtime switch or | |
1158 // at compilation. | |
1159 #ifdef V8_INTERPRETED_REGEXP | 1156 #ifdef V8_INTERPRETED_REGEXP |
1160 __ TailCallRuntime(Runtime::kRegExpExec); | 1157 // This case is handled prior to the RegExpExecStub call. |
| 1158 __ Abort(kUnexpectedRegExpExecCall); |
1161 #else // V8_INTERPRETED_REGEXP | 1159 #else // V8_INTERPRETED_REGEXP |
1162 | |
1163 // Stack frame on entry. | |
1164 // sp[0]: last_match_info (expected JSArray) | |
1165 // sp[4]: previous index | |
1166 // sp[8]: subject string | |
1167 // sp[12]: JSRegExp object | |
1168 | |
1169 const int kLastMatchInfoOffset = 0 * kPointerSize; | |
1170 const int kPreviousIndexOffset = 1 * kPointerSize; | |
1171 const int kSubjectOffset = 2 * kPointerSize; | |
1172 const int kJSRegExpOffset = 3 * kPointerSize; | |
1173 | |
1174 Label runtime; | |
1175 // Allocation of registers for this function. These are in callee save | |
1176 // registers and will be preserved by the call to the native RegExp code, as | |
1177 // this code is called using the normal C calling convention. When calling | |
1178 // directly from generated code the native RegExp code will not do a GC and | |
1179 // therefore the content of these registers are safe to use after the call. | |
1180 Register subject = r4; | |
1181 Register regexp_data = r5; | |
1182 Register last_match_info_elements = no_reg; // will be r6; | |
1183 | |
1184 // Ensure that a RegExp stack is allocated. | |
1185 ExternalReference address_of_regexp_stack_memory_address = | |
1186 ExternalReference::address_of_regexp_stack_memory_address(isolate()); | |
1187 ExternalReference address_of_regexp_stack_memory_size = | |
1188 ExternalReference::address_of_regexp_stack_memory_size(isolate()); | |
1189 __ mov(r0, Operand(address_of_regexp_stack_memory_size)); | |
1190 __ ldr(r0, MemOperand(r0, 0)); | |
1191 __ cmp(r0, Operand::Zero()); | |
1192 __ b(eq, &runtime); | |
1193 | |
1194 // Check that the first argument is a JSRegExp object. | |
1195 __ ldr(r0, MemOperand(sp, kJSRegExpOffset)); | |
1196 __ JumpIfSmi(r0, &runtime); | |
1197 __ CompareObjectType(r0, r1, r1, JS_REGEXP_TYPE); | |
1198 __ b(ne, &runtime); | |
1199 | |
1200 // Check that the RegExp has been compiled (data contains a fixed array). | |
1201 __ ldr(regexp_data, FieldMemOperand(r0, JSRegExp::kDataOffset)); | |
1202 if (FLAG_debug_code) { | |
1203 __ SmiTst(regexp_data); | |
1204 __ Check(ne, kUnexpectedTypeForRegExpDataFixedArrayExpected); | |
1205 __ CompareObjectType(regexp_data, r0, r0, FIXED_ARRAY_TYPE); | |
1206 __ Check(eq, kUnexpectedTypeForRegExpDataFixedArrayExpected); | |
1207 } | |
1208 | |
1209 // regexp_data: RegExp data (FixedArray) | |
1210 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. | |
1211 __ ldr(r0, FieldMemOperand(regexp_data, JSRegExp::kDataTagOffset)); | |
1212 __ cmp(r0, Operand(Smi::FromInt(JSRegExp::IRREGEXP))); | |
1213 __ b(ne, &runtime); | |
1214 | |
1215 // regexp_data: RegExp data (FixedArray) | |
1216 // Check that the number of captures fit in the static offsets vector buffer. | |
1217 __ ldr(r2, | |
1218 FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset)); | |
1219 // Check (number_of_captures + 1) * 2 <= offsets vector size | |
1220 // Or number_of_captures * 2 <= offsets vector size - 2 | |
1221 // Multiplying by 2 comes for free since r2 is smi-tagged. | |
1222 STATIC_ASSERT(kSmiTag == 0); | |
1223 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); | |
1224 STATIC_ASSERT(Isolate::kJSRegexpStaticOffsetsVectorSize >= 2); | |
1225 __ cmp(r2, Operand(Isolate::kJSRegexpStaticOffsetsVectorSize - 2)); | |
1226 __ b(hi, &runtime); | |
1227 | |
1228 // Reset offset for possibly sliced string. | |
1229 __ mov(r9, Operand::Zero()); | |
1230 __ ldr(subject, MemOperand(sp, kSubjectOffset)); | |
1231 __ JumpIfSmi(subject, &runtime); | |
1232 __ mov(r3, subject); // Make a copy of the original subject string. | |
1233 // subject: subject string | |
1234 // r3: subject string | |
1235 // regexp_data: RegExp data (FixedArray) | |
1236 // Handle subject string according to its encoding and representation: | |
1237 // (1) Sequential string? If yes, go to (4). | |
1238 // (2) Sequential or cons? If not, go to (5). | |
1239 // (3) Cons string. If the string is flat, replace subject with first string | |
1240 // and go to (1). Otherwise bail out to runtime. | |
1241 // (4) Sequential string. Load regexp code according to encoding. | |
1242 // (E) Carry on. | |
1243 /// [...] | |
1244 | |
1245 // Deferred code at the end of the stub: | |
1246 // (5) Long external string? If not, go to (7). | |
1247 // (6) External string. Make it, offset-wise, look like a sequential string. | |
1248 // Go to (4). | |
1249 // (7) Short external string or not a string? If yes, bail out to runtime. | |
1250 // (8) Sliced or thin string. Replace subject with parent. Go to (1). | |
1251 | |
1252 Label seq_string /* 4 */, external_string /* 6 */, check_underlying /* 1 */, | |
1253 not_seq_nor_cons /* 5 */, not_long_external /* 7 */; | |
1254 | |
1255 __ bind(&check_underlying); | |
1256 __ ldr(r0, FieldMemOperand(subject, HeapObject::kMapOffset)); | |
1257 __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset)); | |
1258 | |
1259 // (1) Sequential string? If yes, go to (4). | |
1260 __ and_(r1, | |
1261 r0, | |
1262 Operand(kIsNotStringMask | | |
1263 kStringRepresentationMask | | |
1264 kShortExternalStringMask), | |
1265 SetCC); | |
1266 STATIC_ASSERT((kStringTag | kSeqStringTag) == 0); | |
1267 __ b(eq, &seq_string); // Go to (4). | |
1268 | |
1269 // (2) Sequential or cons? If not, go to (5). | |
1270 STATIC_ASSERT(kConsStringTag < kExternalStringTag); | |
1271 STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); | |
1272 STATIC_ASSERT(kThinStringTag > kExternalStringTag); | |
1273 STATIC_ASSERT(kIsNotStringMask > kExternalStringTag); | |
1274 STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag); | |
1275 __ cmp(r1, Operand(kExternalStringTag)); | |
1276 __ b(ge, ¬_seq_nor_cons); // Go to (5). | |
1277 | |
1278 // (3) Cons string. Check that it's flat. | |
1279 // Replace subject with first string and reload instance type. | |
1280 __ ldr(r0, FieldMemOperand(subject, ConsString::kSecondOffset)); | |
1281 __ CompareRoot(r0, Heap::kempty_stringRootIndex); | |
1282 __ b(ne, &runtime); | |
1283 __ ldr(subject, FieldMemOperand(subject, ConsString::kFirstOffset)); | |
1284 __ jmp(&check_underlying); | |
1285 | |
1286 // (4) Sequential string. Load regexp code according to encoding. | |
1287 __ bind(&seq_string); | |
1288 // subject: sequential subject string (or look-alike, external string) | |
1289 // r3: original subject string | |
1290 // Load previous index and check range before r3 is overwritten. We have to | |
1291 // use r3 instead of subject here because subject might have been only made | |
1292 // to look like a sequential string when it actually is an external string. | |
1293 __ ldr(r1, MemOperand(sp, kPreviousIndexOffset)); | |
1294 __ JumpIfNotSmi(r1, &runtime); | |
1295 __ ldr(r3, FieldMemOperand(r3, String::kLengthOffset)); | |
1296 __ cmp(r3, Operand(r1)); | |
1297 __ b(ls, &runtime); | |
1298 __ SmiUntag(r1); | |
1299 | |
1300 STATIC_ASSERT(8 == kOneByteStringTag); | |
1301 STATIC_ASSERT(kTwoByteStringTag == 0); | |
1302 __ and_(r0, r0, Operand(kStringEncodingMask)); | |
1303 __ mov(r3, Operand(r0, ASR, 3), SetCC); | |
1304 __ ldr(r6, FieldMemOperand(regexp_data, JSRegExp::kDataOneByteCodeOffset), | |
1305 ne); | |
1306 __ ldr(r6, FieldMemOperand(regexp_data, JSRegExp::kDataUC16CodeOffset), eq); | |
1307 | |
1308 // (E) Carry on. String handling is done. | |
1309 // r6: irregexp code | |
1310 // Check that the irregexp code has been generated for the actual string | |
1311 // encoding. If it has, the field contains a code object otherwise it contains | |
1312 // a smi (code flushing support). | |
1313 __ JumpIfSmi(r6, &runtime); | |
1314 | |
1315 // r1: previous index | |
1316 // r3: encoding of subject string (1 if one_byte, 0 if two_byte); | |
1317 // r6: code | |
1318 // subject: Subject string | |
1319 // regexp_data: RegExp data (FixedArray) | |
1320 // All checks done. Now push arguments for native regexp code. | |
1321 __ IncrementCounter(isolate()->counters()->regexp_entry_native(), 1, r0, r2); | |
1322 | |
1323 // Isolates: note we add an additional parameter here (isolate pointer). | 1160 // Isolates: note we add an additional parameter here (isolate pointer). |
1324 const int kRegExpExecuteArguments = 9; | 1161 const int kRegExpExecuteArguments = 9; |
1325 const int kParameterRegisters = 4; | 1162 const int kParameterRegisters = 4; |
1326 __ EnterExitFrame(false, kRegExpExecuteArguments - kParameterRegisters); | 1163 __ EnterExitFrame(false, kRegExpExecuteArguments - kParameterRegisters); |
1327 | 1164 |
1328 // Stack pointer now points to cell where return address is to be written. | 1165 // Stack pointer now points to cell where return address is to be written. |
1329 // Arguments are before that on the stack or in registers. | 1166 // Arguments are before that on the stack or in registers. |
1330 | 1167 |
1331 // Argument 9 (sp[20]): Pass current isolate address. | 1168 // Argument 9 (sp[20]): Pass current isolate address. |
1332 __ mov(r0, Operand(ExternalReference::isolate_address(isolate()))); | 1169 __ mov(r5, Operand(ExternalReference::isolate_address(isolate()))); |
1333 __ str(r0, MemOperand(sp, 5 * kPointerSize)); | 1170 __ str(r5, MemOperand(sp, 5 * kPointerSize)); |
1334 | 1171 |
1335 // Argument 8 (sp[16]): Indicate that this is a direct call from JavaScript. | 1172 // Argument 8 (sp[16]): Indicate that this is a direct call from JavaScript. |
1336 __ mov(r0, Operand(1)); | 1173 __ mov(r5, Operand(1)); |
1337 __ str(r0, MemOperand(sp, 4 * kPointerSize)); | 1174 __ str(r5, MemOperand(sp, 4 * kPointerSize)); |
1338 | 1175 |
1339 // Argument 7 (sp[12]): Start (high end) of backtracking stack memory area. | 1176 // Argument 7 (sp[12]): Start (high end) of backtracking stack memory area. |
1340 __ mov(r0, Operand(address_of_regexp_stack_memory_address)); | 1177 ExternalReference address_of_regexp_stack_memory_address = |
1341 __ ldr(r0, MemOperand(r0, 0)); | 1178 ExternalReference::address_of_regexp_stack_memory_address(isolate()); |
1342 __ mov(r2, Operand(address_of_regexp_stack_memory_size)); | 1179 ExternalReference address_of_regexp_stack_memory_size = |
1343 __ ldr(r2, MemOperand(r2, 0)); | 1180 ExternalReference::address_of_regexp_stack_memory_size(isolate()); |
1344 __ add(r0, r0, Operand(r2)); | 1181 __ mov(r5, Operand(address_of_regexp_stack_memory_address)); |
1345 __ str(r0, MemOperand(sp, 3 * kPointerSize)); | 1182 __ ldr(r5, MemOperand(r5, 0)); |
| 1183 __ mov(r6, Operand(address_of_regexp_stack_memory_size)); |
| 1184 __ ldr(r6, MemOperand(r6, 0)); |
| 1185 __ add(r5, r5, Operand(r6)); |
| 1186 __ str(r5, MemOperand(sp, 3 * kPointerSize)); |
1346 | 1187 |
1347 // Argument 6: Set the number of capture registers to zero to force global | 1188 // Argument 6: Set the number of capture registers to zero to force global |
1348 // regexps to behave as non-global. This does not affect non-global regexps. | 1189 // regexps to behave as non-global. This does not affect non-global regexps. |
1349 __ mov(r0, Operand::Zero()); | 1190 __ mov(r5, Operand::Zero()); |
1350 __ str(r0, MemOperand(sp, 2 * kPointerSize)); | 1191 __ str(r5, MemOperand(sp, 2 * kPointerSize)); |
1351 | 1192 |
1352 // Argument 5 (sp[4]): static offsets vector buffer. | 1193 // Argument 5 (sp[4]): static offsets vector buffer. |
1353 __ mov(r0, | 1194 __ mov( |
1354 Operand(ExternalReference::address_of_static_offsets_vector( | 1195 r5, |
1355 isolate()))); | 1196 Operand(ExternalReference::address_of_static_offsets_vector(isolate()))); |
1356 __ str(r0, MemOperand(sp, 1 * kPointerSize)); | 1197 __ str(r5, MemOperand(sp, 1 * kPointerSize)); |
1357 | 1198 |
1358 // For arguments 4 and 3 get string length, calculate start of string data and | 1199 // Argument 4: End of string data |
1359 // calculate the shift of the index (0 for one-byte and 1 for two-byte). | 1200 // Argument 3: Start of string data |
1360 __ add(r7, subject, Operand(SeqString::kHeaderSize - kHeapObjectTag)); | 1201 CHECK(r3.is(RegExpExecDescriptor::StringEndRegister())); |
1361 __ eor(r3, r3, Operand(1)); | 1202 CHECK(r2.is(RegExpExecDescriptor::StringStartRegister())); |
1362 // Load the length from the original subject string from the previous stack | |
1363 // frame. Therefore we have to use fp, which points exactly to two pointer | |
1364 // sizes below the previous sp. (Because creating a new stack frame pushes | |
1365 // the previous fp onto the stack and moves up sp by 2 * kPointerSize.) | |
1366 __ ldr(subject, MemOperand(fp, kSubjectOffset + 2 * kPointerSize)); | |
1367 // If slice offset is not 0, load the length from the original sliced string. | |
1368 // Argument 4, r3: End of string data | |
1369 // Argument 3, r2: Start of string data | |
1370 // Prepare start and end index of the input. | |
1371 __ add(r9, r7, Operand(r9, LSL, r3)); | |
1372 __ add(r2, r9, Operand(r1, LSL, r3)); | |
1373 | |
1374 __ ldr(r7, FieldMemOperand(subject, String::kLengthOffset)); | |
1375 __ SmiUntag(r7); | |
1376 __ add(r3, r9, Operand(r7, LSL, r3)); | |
1377 | 1203 |
1378 // Argument 2 (r1): Previous index. | 1204 // Argument 2 (r1): Previous index. |
1379 // Already there | 1205 CHECK(r1.is(RegExpExecDescriptor::LastIndexRegister())); |
1380 | 1206 |
1381 // Argument 1 (r0): Subject string. | 1207 // Argument 1 (r0): Subject string. |
1382 __ mov(r0, subject); | 1208 CHECK(r0.is(RegExpExecDescriptor::StringRegister())); |
1383 | 1209 |
1384 // Locate the code entry and call it. | 1210 // Locate the code entry and call it. |
1385 __ add(r6, r6, Operand(Code::kHeaderSize - kHeapObjectTag)); | 1211 Register code_reg = RegExpExecDescriptor::CodeRegister(); |
| 1212 __ add(code_reg, code_reg, Operand(Code::kHeaderSize - kHeapObjectTag)); |
| 1213 |
1386 DirectCEntryStub stub(isolate()); | 1214 DirectCEntryStub stub(isolate()); |
1387 stub.GenerateCall(masm, r6); | 1215 stub.GenerateCall(masm, code_reg); |
1388 | 1216 |
1389 __ LeaveExitFrame(false, no_reg, true); | 1217 __ LeaveExitFrame(false, no_reg, true); |
1390 | 1218 |
1391 last_match_info_elements = r6; | 1219 __ SmiTag(r0); |
1392 | |
1393 // r0: result | |
1394 // subject: subject string (callee saved) | |
1395 // regexp_data: RegExp data (callee saved) | |
1396 // last_match_info_elements: Last match info elements (callee saved) | |
1397 // Check the result. | |
1398 Label success; | |
1399 __ cmp(r0, Operand(1)); | |
1400 // We expect exactly one result since we force the called regexp to behave | |
1401 // as non-global. | |
1402 __ b(eq, &success); | |
1403 Label failure; | |
1404 __ cmp(r0, Operand(NativeRegExpMacroAssembler::FAILURE)); | |
1405 __ b(eq, &failure); | |
1406 __ cmp(r0, Operand(NativeRegExpMacroAssembler::EXCEPTION)); | |
1407 // If not exception it can only be retry. Handle that in the runtime system. | |
1408 __ b(ne, &runtime); | |
1409 // Result must now be exception. If there is no pending exception already a | |
1410 // stack overflow (on the backtrack stack) was detected in RegExp code but | |
1411 // haven't created the exception yet. Handle that in the runtime system. | |
1412 // TODO(592): Rerunning the RegExp to get the stack overflow exception. | |
1413 __ mov(r1, Operand(isolate()->factory()->the_hole_value())); | |
1414 __ mov(r2, Operand(ExternalReference(Isolate::kPendingExceptionAddress, | |
1415 isolate()))); | |
1416 __ ldr(r0, MemOperand(r2, 0)); | |
1417 __ cmp(r0, r1); | |
1418 __ b(eq, &runtime); | |
1419 | |
1420 // For exception, throw the exception again. | |
1421 __ TailCallRuntime(Runtime::kRegExpExecReThrow); | |
1422 | |
1423 __ bind(&failure); | |
1424 // For failure and exception return null. | |
1425 __ mov(r0, Operand(isolate()->factory()->null_value())); | |
1426 __ add(sp, sp, Operand(4 * kPointerSize)); | |
1427 __ Ret(); | 1220 __ Ret(); |
1428 | |
1429 // Process the result from the native regexp code. | |
1430 __ bind(&success); | |
1431 __ ldr(r1, | |
1432 FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset)); | |
1433 // Calculate number of capture registers (number_of_captures + 1) * 2. | |
1434 // Multiplying by 2 comes for free since r1 is smi-tagged. | |
1435 STATIC_ASSERT(kSmiTag == 0); | |
1436 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); | |
1437 __ add(r1, r1, Operand(2)); // r1 was a smi. | |
1438 | |
1439 // Check that the last match info is a FixedArray. | |
1440 __ ldr(last_match_info_elements, MemOperand(sp, kLastMatchInfoOffset)); | |
1441 __ JumpIfSmi(last_match_info_elements, &runtime); | |
1442 // Check that the object has fast elements. | |
1443 __ ldr(r0, FieldMemOperand(last_match_info_elements, HeapObject::kMapOffset)); | |
1444 __ CompareRoot(r0, Heap::kFixedArrayMapRootIndex); | |
1445 __ b(ne, &runtime); | |
1446 // Check that the last match info has space for the capture registers and the | |
1447 // additional information. | |
1448 __ ldr(r0, | |
1449 FieldMemOperand(last_match_info_elements, FixedArray::kLengthOffset)); | |
1450 __ add(r2, r1, Operand(RegExpMatchInfo::kLastMatchOverhead)); | |
1451 __ cmp(r2, Operand::SmiUntag(r0)); | |
1452 __ b(gt, &runtime); | |
1453 | |
1454 // r1: number of capture registers | |
1455 // r4: subject string | |
1456 // Store the capture count. | |
1457 __ SmiTag(r2, r1); | |
1458 __ str(r2, FieldMemOperand(last_match_info_elements, | |
1459 RegExpMatchInfo::kNumberOfCapturesOffset)); | |
1460 // Store last subject and last input. | |
1461 __ str(subject, FieldMemOperand(last_match_info_elements, | |
1462 RegExpMatchInfo::kLastSubjectOffset)); | |
1463 __ mov(r2, subject); | |
1464 __ RecordWriteField(last_match_info_elements, | |
1465 RegExpMatchInfo::kLastSubjectOffset, subject, r3, | |
1466 kLRHasNotBeenSaved, kDontSaveFPRegs); | |
1467 __ mov(subject, r2); | |
1468 __ str(subject, FieldMemOperand(last_match_info_elements, | |
1469 RegExpMatchInfo::kLastInputOffset)); | |
1470 __ RecordWriteField(last_match_info_elements, | |
1471 RegExpMatchInfo::kLastInputOffset, subject, r3, | |
1472 kLRHasNotBeenSaved, kDontSaveFPRegs); | |
1473 | |
1474 // Get the static offsets vector filled by the native regexp code. | |
1475 ExternalReference address_of_static_offsets_vector = | |
1476 ExternalReference::address_of_static_offsets_vector(isolate()); | |
1477 __ mov(r2, Operand(address_of_static_offsets_vector)); | |
1478 | |
1479 // r1: number of capture registers | |
1480 // r2: offsets vector | |
1481 Label next_capture, done; | |
1482 // Capture register counter starts from number of capture registers and | |
1483 // counts down until wrapping after zero. | |
1484 __ add(r0, last_match_info_elements, | |
1485 Operand(RegExpMatchInfo::kFirstCaptureOffset - kHeapObjectTag)); | |
1486 __ bind(&next_capture); | |
1487 __ sub(r1, r1, Operand(1), SetCC); | |
1488 __ b(mi, &done); | |
1489 // Read the value from the static offsets vector buffer. | |
1490 __ ldr(r3, MemOperand(r2, kPointerSize, PostIndex)); | |
1491 // Store the smi value in the last match info. | |
1492 __ SmiTag(r3); | |
1493 __ str(r3, MemOperand(r0, kPointerSize, PostIndex)); | |
1494 __ jmp(&next_capture); | |
1495 __ bind(&done); | |
1496 | |
1497 // Return last match info. | |
1498 __ mov(r0, last_match_info_elements); | |
1499 __ add(sp, sp, Operand(4 * kPointerSize)); | |
1500 __ Ret(); | |
1501 | |
1502 // Do the runtime call to execute the regexp. | |
1503 __ bind(&runtime); | |
1504 __ TailCallRuntime(Runtime::kRegExpExec); | |
1505 | |
1506 // Deferred code for string handling. | |
1507 // (5) Long external string? If not, go to (7). | |
1508 __ bind(¬_seq_nor_cons); | |
1509 // Compare flags are still set. | |
1510 __ b(gt, ¬_long_external); // Go to (7). | |
1511 | |
1512 // (6) External string. Make it, offset-wise, look like a sequential string. | |
1513 __ bind(&external_string); | |
1514 __ ldr(r0, FieldMemOperand(subject, HeapObject::kMapOffset)); | |
1515 __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset)); | |
1516 if (FLAG_debug_code) { | |
1517 // Assert that we do not have a cons or slice (indirect strings) here. | |
1518 // Sequential strings have already been ruled out. | |
1519 __ tst(r0, Operand(kIsIndirectStringMask)); | |
1520 __ Assert(eq, kExternalStringExpectedButNotFound); | |
1521 } | |
1522 __ ldr(subject, | |
1523 FieldMemOperand(subject, ExternalString::kResourceDataOffset)); | |
1524 // Move the pointer so that offset-wise, it looks like a sequential string. | |
1525 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); | |
1526 __ sub(subject, | |
1527 subject, | |
1528 Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | |
1529 __ jmp(&seq_string); // Go to (4). | |
1530 | |
1531 // (7) Short external string or not a string? If yes, bail out to runtime. | |
1532 __ bind(¬_long_external); | |
1533 STATIC_ASSERT(kNotStringTag != 0 && kShortExternalStringTag !=0); | |
1534 __ tst(r1, Operand(kIsNotStringMask | kShortExternalStringMask)); | |
1535 __ b(ne, &runtime); | |
1536 | |
1537 // (8) Sliced or thin string. Replace subject with parent. Go to (4). | |
1538 Label thin_string; | |
1539 __ cmp(r1, Operand(kThinStringTag)); | |
1540 __ b(eq, &thin_string); | |
1541 // Load offset into r9 and replace subject string with parent. | |
1542 __ ldr(r9, FieldMemOperand(subject, SlicedString::kOffsetOffset)); | |
1543 __ SmiUntag(r9); | |
1544 __ ldr(subject, FieldMemOperand(subject, SlicedString::kParentOffset)); | |
1545 __ jmp(&check_underlying); // Go to (4). | |
1546 | |
1547 __ bind(&thin_string); | |
1548 __ ldr(subject, FieldMemOperand(subject, ThinString::kActualOffset)); | |
1549 __ jmp(&check_underlying); // Go to (4). | |
1550 #endif // V8_INTERPRETED_REGEXP | 1221 #endif // V8_INTERPRETED_REGEXP |
1551 } | 1222 } |
1552 | 1223 |
1553 | |
1554 static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub) { | 1224 static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub) { |
1555 // r0 : number of arguments to the construct function | 1225 // r0 : number of arguments to the construct function |
1556 // r1 : the function to call | 1226 // r1 : the function to call |
1557 // r2 : feedback vector | 1227 // r2 : feedback vector |
1558 // r3 : slot in feedback vector (Smi) | 1228 // r3 : slot in feedback vector (Smi) |
1559 FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); | 1229 FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); |
1560 | 1230 |
1561 // Number-of-arguments register must be smi-tagged to call out. | 1231 // Number-of-arguments register must be smi-tagged to call out. |
1562 __ SmiTag(r0); | 1232 __ SmiTag(r0); |
1563 __ Push(r3, r2, r1, r0); | 1233 __ Push(r3, r2, r1, r0); |
(...skipping 1762 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3326 CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, | 2996 CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, |
3327 kStackUnwindSpace, NULL, return_value_operand, NULL); | 2997 kStackUnwindSpace, NULL, return_value_operand, NULL); |
3328 } | 2998 } |
3329 | 2999 |
3330 #undef __ | 3000 #undef __ |
3331 | 3001 |
3332 } // namespace internal | 3002 } // namespace internal |
3333 } // namespace v8 | 3003 } // namespace v8 |
3334 | 3004 |
3335 #endif // V8_TARGET_ARCH_ARM | 3005 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |