| 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 |