OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 22 matching lines...) Expand all Loading... |
33 #include "code-stubs.h" | 33 #include "code-stubs.h" |
34 #include "regexp-macro-assembler.h" | 34 #include "regexp-macro-assembler.h" |
35 | 35 |
36 namespace v8 { | 36 namespace v8 { |
37 namespace internal { | 37 namespace internal { |
38 | 38 |
39 #define __ ACCESS_MASM(masm) | 39 #define __ ACCESS_MASM(masm) |
40 | 40 |
41 void ToNumberStub::Generate(MacroAssembler* masm) { | 41 void ToNumberStub::Generate(MacroAssembler* masm) { |
42 // The ToNumber stub takes one argument in eax. | 42 // The ToNumber stub takes one argument in eax. |
43 NearLabel check_heap_number, call_builtin; | 43 Label check_heap_number, call_builtin; |
44 __ SmiTest(rax); | 44 __ SmiTest(rax); |
45 __ j(not_zero, &check_heap_number); | 45 __ j(not_zero, &check_heap_number, Label::kNear); |
46 __ Ret(); | 46 __ Ret(); |
47 | 47 |
48 __ bind(&check_heap_number); | 48 __ bind(&check_heap_number); |
49 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset), | 49 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset), |
50 Heap::kHeapNumberMapRootIndex); | 50 Heap::kHeapNumberMapRootIndex); |
51 __ j(not_equal, &call_builtin); | 51 __ j(not_equal, &call_builtin, Label::kNear); |
52 __ Ret(); | 52 __ Ret(); |
53 | 53 |
54 __ bind(&call_builtin); | 54 __ bind(&call_builtin); |
55 __ pop(rcx); // Pop return address. | 55 __ pop(rcx); // Pop return address. |
56 __ push(rax); | 56 __ push(rax); |
57 __ push(rcx); // Push return address. | 57 __ push(rcx); // Push return address. |
58 __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION); | 58 __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION); |
59 } | 59 } |
60 | 60 |
61 | 61 |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
225 | 225 |
226 // Return and remove the on-stack parameters. | 226 // Return and remove the on-stack parameters. |
227 __ ret(3 * kPointerSize); | 227 __ ret(3 * kPointerSize); |
228 | 228 |
229 __ bind(&slow_case); | 229 __ bind(&slow_case); |
230 __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1); | 230 __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1); |
231 } | 231 } |
232 | 232 |
233 | 233 |
234 void ToBooleanStub::Generate(MacroAssembler* masm) { | 234 void ToBooleanStub::Generate(MacroAssembler* masm) { |
235 NearLabel false_result, true_result, not_string; | 235 Label false_result, true_result, not_string; |
236 __ movq(rax, Operand(rsp, 1 * kPointerSize)); | 236 __ movq(rax, Operand(rsp, 1 * kPointerSize)); |
237 | 237 |
238 // 'null' => false. | 238 // 'null' => false. |
239 __ CompareRoot(rax, Heap::kNullValueRootIndex); | 239 __ CompareRoot(rax, Heap::kNullValueRootIndex); |
240 __ j(equal, &false_result); | 240 __ j(equal, &false_result, Label::kNear); |
241 | 241 |
242 // Get the map and type of the heap object. | 242 // Get the map and type of the heap object. |
243 // We don't use CmpObjectType because we manipulate the type field. | 243 // We don't use CmpObjectType because we manipulate the type field. |
244 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); | 244 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); |
245 __ movzxbq(rcx, FieldOperand(rdx, Map::kInstanceTypeOffset)); | 245 __ movzxbq(rcx, FieldOperand(rdx, Map::kInstanceTypeOffset)); |
246 | 246 |
247 // Undetectable => false. | 247 // Undetectable => false. |
248 __ movzxbq(rbx, FieldOperand(rdx, Map::kBitFieldOffset)); | 248 __ movzxbq(rbx, FieldOperand(rdx, Map::kBitFieldOffset)); |
249 __ and_(rbx, Immediate(1 << Map::kIsUndetectable)); | 249 __ and_(rbx, Immediate(1 << Map::kIsUndetectable)); |
250 __ j(not_zero, &false_result); | 250 __ j(not_zero, &false_result, Label::kNear); |
251 | 251 |
252 // JavaScript object => true. | 252 // JavaScript object => true. |
253 __ cmpq(rcx, Immediate(FIRST_JS_OBJECT_TYPE)); | 253 __ cmpq(rcx, Immediate(FIRST_JS_OBJECT_TYPE)); |
254 __ j(above_equal, &true_result); | 254 __ j(above_equal, &true_result, Label::kNear); |
255 | 255 |
256 // String value => false iff empty. | 256 // String value => false iff empty. |
257 __ cmpq(rcx, Immediate(FIRST_NONSTRING_TYPE)); | 257 __ cmpq(rcx, Immediate(FIRST_NONSTRING_TYPE)); |
258 __ j(above_equal, ¬_string); | 258 __ j(above_equal, ¬_string, Label::kNear); |
259 __ movq(rdx, FieldOperand(rax, String::kLengthOffset)); | 259 __ movq(rdx, FieldOperand(rax, String::kLengthOffset)); |
260 __ SmiTest(rdx); | 260 __ SmiTest(rdx); |
261 __ j(zero, &false_result); | 261 __ j(zero, &false_result, Label::kNear); |
262 __ jmp(&true_result); | 262 __ jmp(&true_result, Label::kNear); |
263 | 263 |
264 __ bind(¬_string); | 264 __ bind(¬_string); |
265 __ CompareRoot(rdx, Heap::kHeapNumberMapRootIndex); | 265 __ CompareRoot(rdx, Heap::kHeapNumberMapRootIndex); |
266 __ j(not_equal, &true_result); | 266 __ j(not_equal, &true_result, Label::kNear); |
267 // HeapNumber => false iff +0, -0, or NaN. | 267 // HeapNumber => false iff +0, -0, or NaN. |
268 // These three cases set the zero flag when compared to zero using ucomisd. | 268 // These three cases set the zero flag when compared to zero using ucomisd. |
269 __ xorps(xmm0, xmm0); | 269 __ xorps(xmm0, xmm0); |
270 __ ucomisd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset)); | 270 __ ucomisd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset)); |
271 __ j(zero, &false_result); | 271 __ j(zero, &false_result, Label::kNear); |
272 // Fall through to |true_result|. | 272 // Fall through to |true_result|. |
273 | 273 |
274 // Return 1/0 for true/false in rax. | 274 // Return 1/0 for true/false in rax. |
275 __ bind(&true_result); | 275 __ bind(&true_result); |
276 __ Set(rax, 1); | 276 __ Set(rax, 1); |
277 __ ret(1 * kPointerSize); | 277 __ ret(1 * kPointerSize); |
278 __ bind(&false_result); | 278 __ bind(&false_result); |
279 __ Set(rax, 0); | 279 __ Set(rax, 0); |
280 __ ret(1 * kPointerSize); | 280 __ ret(1 * kPointerSize); |
281 } | 281 } |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
327 void IntegerConvert(MacroAssembler* masm, | 327 void IntegerConvert(MacroAssembler* masm, |
328 Register result, | 328 Register result, |
329 Register source) { | 329 Register source) { |
330 // Result may be rcx. If result and source are the same register, source will | 330 // Result may be rcx. If result and source are the same register, source will |
331 // be overwritten. | 331 // be overwritten. |
332 ASSERT(!result.is(rdi) && !result.is(rbx)); | 332 ASSERT(!result.is(rdi) && !result.is(rbx)); |
333 // TODO(lrn): When type info reaches here, if value is a 32-bit integer, use | 333 // TODO(lrn): When type info reaches here, if value is a 32-bit integer, use |
334 // cvttsd2si (32-bit version) directly. | 334 // cvttsd2si (32-bit version) directly. |
335 Register double_exponent = rbx; | 335 Register double_exponent = rbx; |
336 Register double_value = rdi; | 336 Register double_value = rdi; |
337 NearLabel done, exponent_63_plus; | 337 Label done, exponent_63_plus; |
338 // Get double and extract exponent. | 338 // Get double and extract exponent. |
339 __ movq(double_value, FieldOperand(source, HeapNumber::kValueOffset)); | 339 __ movq(double_value, FieldOperand(source, HeapNumber::kValueOffset)); |
340 // Clear result preemptively, in case we need to return zero. | 340 // Clear result preemptively, in case we need to return zero. |
341 __ xorl(result, result); | 341 __ xorl(result, result); |
342 __ movq(xmm0, double_value); // Save copy in xmm0 in case we need it there. | 342 __ movq(xmm0, double_value); // Save copy in xmm0 in case we need it there. |
343 // Double to remove sign bit, shift exponent down to least significant bits. | 343 // Double to remove sign bit, shift exponent down to least significant bits. |
344 // and subtract bias to get the unshifted, unbiased exponent. | 344 // and subtract bias to get the unshifted, unbiased exponent. |
345 __ lea(double_exponent, Operand(double_value, double_value, times_1, 0)); | 345 __ lea(double_exponent, Operand(double_value, double_value, times_1, 0)); |
346 __ shr(double_exponent, Immediate(64 - HeapNumber::kExponentBits)); | 346 __ shr(double_exponent, Immediate(64 - HeapNumber::kExponentBits)); |
347 __ subl(double_exponent, Immediate(HeapNumber::kExponentBias)); | 347 __ subl(double_exponent, Immediate(HeapNumber::kExponentBias)); |
348 // Check whether the exponent is too big for a 63 bit unsigned integer. | 348 // Check whether the exponent is too big for a 63 bit unsigned integer. |
349 __ cmpl(double_exponent, Immediate(63)); | 349 __ cmpl(double_exponent, Immediate(63)); |
350 __ j(above_equal, &exponent_63_plus); | 350 __ j(above_equal, &exponent_63_plus, Label::kNear); |
351 // Handle exponent range 0..62. | 351 // Handle exponent range 0..62. |
352 __ cvttsd2siq(result, xmm0); | 352 __ cvttsd2siq(result, xmm0); |
353 __ jmp(&done); | 353 __ jmp(&done, Label::kNear); |
354 | 354 |
355 __ bind(&exponent_63_plus); | 355 __ bind(&exponent_63_plus); |
356 // Exponent negative or 63+. | 356 // Exponent negative or 63+. |
357 __ cmpl(double_exponent, Immediate(83)); | 357 __ cmpl(double_exponent, Immediate(83)); |
358 // If exponent negative or above 83, number contains no significant bits in | 358 // If exponent negative or above 83, number contains no significant bits in |
359 // the range 0..2^31, so result is zero, and rcx already holds zero. | 359 // the range 0..2^31, so result is zero, and rcx already holds zero. |
360 __ j(above, &done); | 360 __ j(above, &done, Label::kNear); |
361 | 361 |
362 // Exponent in rage 63..83. | 362 // Exponent in rage 63..83. |
363 // Mantissa * 2^exponent contains bits in the range 2^0..2^31, namely | 363 // Mantissa * 2^exponent contains bits in the range 2^0..2^31, namely |
364 // the least significant exponent-52 bits. | 364 // the least significant exponent-52 bits. |
365 | 365 |
366 // Negate low bits of mantissa if value is negative. | 366 // Negate low bits of mantissa if value is negative. |
367 __ addq(double_value, double_value); // Move sign bit to carry. | 367 __ addq(double_value, double_value); // Move sign bit to carry. |
368 __ sbbl(result, result); // And convert carry to -1 in result register. | 368 __ sbbl(result, result); // And convert carry to -1 in result register. |
369 // if scratch2 is negative, do (scratch2-1)^-1, otherwise (scratch2-0)^0. | 369 // if scratch2 is negative, do (scratch2-1)^-1, otherwise (scratch2-0)^0. |
370 __ addl(double_value, result); | 370 __ addl(double_value, result); |
(...skipping 779 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1150 void TypeRecordingBinaryOpStub::GenerateOddballStub(MacroAssembler* masm) { | 1150 void TypeRecordingBinaryOpStub::GenerateOddballStub(MacroAssembler* masm) { |
1151 Label call_runtime; | 1151 Label call_runtime; |
1152 | 1152 |
1153 if (op_ == Token::ADD) { | 1153 if (op_ == Token::ADD) { |
1154 // Handle string addition here, because it is the only operation | 1154 // Handle string addition here, because it is the only operation |
1155 // that does not do a ToNumber conversion on the operands. | 1155 // that does not do a ToNumber conversion on the operands. |
1156 GenerateStringAddCode(masm); | 1156 GenerateStringAddCode(masm); |
1157 } | 1157 } |
1158 | 1158 |
1159 // Convert oddball arguments to numbers. | 1159 // Convert oddball arguments to numbers. |
1160 NearLabel check, done; | 1160 Label check, done; |
1161 __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex); | 1161 __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex); |
1162 __ j(not_equal, &check); | 1162 __ j(not_equal, &check, Label::kNear); |
1163 if (Token::IsBitOp(op_)) { | 1163 if (Token::IsBitOp(op_)) { |
1164 __ xor_(rdx, rdx); | 1164 __ xor_(rdx, rdx); |
1165 } else { | 1165 } else { |
1166 __ LoadRoot(rdx, Heap::kNanValueRootIndex); | 1166 __ LoadRoot(rdx, Heap::kNanValueRootIndex); |
1167 } | 1167 } |
1168 __ jmp(&done); | 1168 __ jmp(&done, Label::kNear); |
1169 __ bind(&check); | 1169 __ bind(&check); |
1170 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | 1170 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
1171 __ j(not_equal, &done); | 1171 __ j(not_equal, &done, Label::kNear); |
1172 if (Token::IsBitOp(op_)) { | 1172 if (Token::IsBitOp(op_)) { |
1173 __ xor_(rax, rax); | 1173 __ xor_(rax, rax); |
1174 } else { | 1174 } else { |
1175 __ LoadRoot(rax, Heap::kNanValueRootIndex); | 1175 __ LoadRoot(rax, Heap::kNanValueRootIndex); |
1176 } | 1176 } |
1177 __ bind(&done); | 1177 __ bind(&done); |
1178 | 1178 |
1179 GenerateHeapNumberStub(masm); | 1179 GenerateHeapNumberStub(masm); |
1180 } | 1180 } |
1181 | 1181 |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1270 // xmm1: untagged double input argument | 1270 // xmm1: untagged double input argument |
1271 // Output: | 1271 // Output: |
1272 // xmm1: untagged double result. | 1272 // xmm1: untagged double result. |
1273 | 1273 |
1274 Label runtime_call; | 1274 Label runtime_call; |
1275 Label runtime_call_clear_stack; | 1275 Label runtime_call_clear_stack; |
1276 Label skip_cache; | 1276 Label skip_cache; |
1277 const bool tagged = (argument_type_ == TAGGED); | 1277 const bool tagged = (argument_type_ == TAGGED); |
1278 if (tagged) { | 1278 if (tagged) { |
1279 NearLabel input_not_smi; | 1279 NearLabel input_not_smi; |
1280 NearLabel loaded; | 1280 Label loaded; |
1281 // Test that rax is a number. | 1281 // Test that rax is a number. |
1282 __ movq(rax, Operand(rsp, kPointerSize)); | 1282 __ movq(rax, Operand(rsp, kPointerSize)); |
1283 __ JumpIfNotSmi(rax, &input_not_smi); | 1283 __ JumpIfNotSmi(rax, &input_not_smi); |
1284 // Input is a smi. Untag and load it onto the FPU stack. | 1284 // Input is a smi. Untag and load it onto the FPU stack. |
1285 // Then load the bits of the double into rbx. | 1285 // Then load the bits of the double into rbx. |
1286 __ SmiToInteger32(rax, rax); | 1286 __ SmiToInteger32(rax, rax); |
1287 __ subq(rsp, Immediate(kDoubleSize)); | 1287 __ subq(rsp, Immediate(kDoubleSize)); |
1288 __ cvtlsi2sd(xmm1, rax); | 1288 __ cvtlsi2sd(xmm1, rax); |
1289 __ movsd(Operand(rsp, 0), xmm1); | 1289 __ movsd(Operand(rsp, 0), xmm1); |
1290 __ movq(rbx, xmm1); | 1290 __ movq(rbx, xmm1); |
1291 __ movq(rdx, xmm1); | 1291 __ movq(rdx, xmm1); |
1292 __ fld_d(Operand(rsp, 0)); | 1292 __ fld_d(Operand(rsp, 0)); |
1293 __ addq(rsp, Immediate(kDoubleSize)); | 1293 __ addq(rsp, Immediate(kDoubleSize)); |
1294 __ jmp(&loaded); | 1294 __ jmp(&loaded, Label::kNear); |
1295 | 1295 |
1296 __ bind(&input_not_smi); | 1296 __ bind(&input_not_smi); |
1297 // Check if input is a HeapNumber. | 1297 // Check if input is a HeapNumber. |
1298 __ LoadRoot(rbx, Heap::kHeapNumberMapRootIndex); | 1298 __ LoadRoot(rbx, Heap::kHeapNumberMapRootIndex); |
1299 __ cmpq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); | 1299 __ cmpq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); |
1300 __ j(not_equal, &runtime_call); | 1300 __ j(not_equal, &runtime_call); |
1301 // Input is a HeapNumber. Push it on the FPU stack and load its | 1301 // Input is a HeapNumber. Push it on the FPU stack and load its |
1302 // bits into rbx. | 1302 // bits into rbx. |
1303 __ fld_d(FieldOperand(rax, HeapNumber::kValueOffset)); | 1303 __ fld_d(FieldOperand(rax, HeapNumber::kValueOffset)); |
1304 __ movq(rbx, FieldOperand(rax, HeapNumber::kValueOffset)); | 1304 __ movq(rbx, FieldOperand(rax, HeapNumber::kValueOffset)); |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1359 CHECK_EQ(16, static_cast<int>(elem2_start - elem_start)); | 1359 CHECK_EQ(16, static_cast<int>(elem2_start - elem_start)); |
1360 CHECK_EQ(0, static_cast<int>(elem_in0 - elem_start)); | 1360 CHECK_EQ(0, static_cast<int>(elem_in0 - elem_start)); |
1361 CHECK_EQ(kIntSize, static_cast<int>(elem_in1 - elem_start)); | 1361 CHECK_EQ(kIntSize, static_cast<int>(elem_in1 - elem_start)); |
1362 CHECK_EQ(2 * kIntSize, static_cast<int>(elem_out - elem_start)); | 1362 CHECK_EQ(2 * kIntSize, static_cast<int>(elem_out - elem_start)); |
1363 } | 1363 } |
1364 #endif | 1364 #endif |
1365 // Find the address of the rcx'th entry in the cache, i.e., &rax[rcx*16]. | 1365 // Find the address of the rcx'th entry in the cache, i.e., &rax[rcx*16]. |
1366 __ addl(rcx, rcx); | 1366 __ addl(rcx, rcx); |
1367 __ lea(rcx, Operand(rax, rcx, times_8, 0)); | 1367 __ lea(rcx, Operand(rax, rcx, times_8, 0)); |
1368 // Check if cache matches: Double value is stored in uint32_t[2] array. | 1368 // Check if cache matches: Double value is stored in uint32_t[2] array. |
1369 NearLabel cache_miss; | 1369 Label cache_miss; |
1370 __ cmpq(rbx, Operand(rcx, 0)); | 1370 __ cmpq(rbx, Operand(rcx, 0)); |
1371 __ j(not_equal, &cache_miss); | 1371 __ j(not_equal, &cache_miss, Label::kNear); |
1372 // Cache hit! | 1372 // Cache hit! |
1373 __ movq(rax, Operand(rcx, 2 * kIntSize)); | 1373 __ movq(rax, Operand(rcx, 2 * kIntSize)); |
1374 if (tagged) { | 1374 if (tagged) { |
1375 __ fstp(0); // Clear FPU stack. | 1375 __ fstp(0); // Clear FPU stack. |
1376 __ ret(kPointerSize); | 1376 __ ret(kPointerSize); |
1377 } else { // UNTAGGED. | 1377 } else { // UNTAGGED. |
1378 __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset)); | 1378 __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset)); |
1379 __ Ret(); | 1379 __ Ret(); |
1380 } | 1380 } |
1381 | 1381 |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1469 __ movq(rdi, rbx); | 1469 __ movq(rdi, rbx); |
1470 // Move exponent and sign bits to low bits. | 1470 // Move exponent and sign bits to low bits. |
1471 __ shr(rdi, Immediate(HeapNumber::kMantissaBits)); | 1471 __ shr(rdi, Immediate(HeapNumber::kMantissaBits)); |
1472 // Remove sign bit. | 1472 // Remove sign bit. |
1473 __ andl(rdi, Immediate((1 << HeapNumber::kExponentBits) - 1)); | 1473 __ andl(rdi, Immediate((1 << HeapNumber::kExponentBits) - 1)); |
1474 int supported_exponent_limit = (63 + HeapNumber::kExponentBias); | 1474 int supported_exponent_limit = (63 + HeapNumber::kExponentBias); |
1475 __ cmpl(rdi, Immediate(supported_exponent_limit)); | 1475 __ cmpl(rdi, Immediate(supported_exponent_limit)); |
1476 __ j(below, &in_range); | 1476 __ j(below, &in_range); |
1477 // Check for infinity and NaN. Both return NaN for sin. | 1477 // Check for infinity and NaN. Both return NaN for sin. |
1478 __ cmpl(rdi, Immediate(0x7ff)); | 1478 __ cmpl(rdi, Immediate(0x7ff)); |
1479 NearLabel non_nan_result; | 1479 Label non_nan_result; |
1480 __ j(not_equal, &non_nan_result); | 1480 __ j(not_equal, &non_nan_result, Label::kNear); |
1481 // Input is +/-Infinity or NaN. Result is NaN. | 1481 // Input is +/-Infinity or NaN. Result is NaN. |
1482 __ fstp(0); | 1482 __ fstp(0); |
1483 __ LoadRoot(kScratchRegister, Heap::kNanValueRootIndex); | 1483 __ LoadRoot(kScratchRegister, Heap::kNanValueRootIndex); |
1484 __ fld_d(FieldOperand(kScratchRegister, HeapNumber::kValueOffset)); | 1484 __ fld_d(FieldOperand(kScratchRegister, HeapNumber::kValueOffset)); |
1485 __ jmp(&done); | 1485 __ jmp(&done); |
1486 | 1486 |
1487 __ bind(&non_nan_result); | 1487 __ bind(&non_nan_result); |
1488 | 1488 |
1489 // Use fpmod to restrict argument to the range +/-2*PI. | 1489 // Use fpmod to restrict argument to the range +/-2*PI. |
1490 __ movq(rdi, rax); // Save rax before using fnstsw_ax. | 1490 __ movq(rdi, rax); // Save rax before using fnstsw_ax. |
1491 __ fldpi(); | 1491 __ fldpi(); |
1492 __ fadd(0); | 1492 __ fadd(0); |
1493 __ fld(1); | 1493 __ fld(1); |
1494 // FPU Stack: input, 2*pi, input. | 1494 // FPU Stack: input, 2*pi, input. |
1495 { | 1495 { |
1496 Label no_exceptions; | 1496 Label no_exceptions; |
1497 __ fwait(); | 1497 __ fwait(); |
1498 __ fnstsw_ax(); | 1498 __ fnstsw_ax(); |
1499 // Clear if Illegal Operand or Zero Division exceptions are set. | 1499 // Clear if Illegal Operand or Zero Division exceptions are set. |
1500 __ testl(rax, Immediate(5)); // #IO and #ZD flags of FPU status word. | 1500 __ testl(rax, Immediate(5)); // #IO and #ZD flags of FPU status word. |
1501 __ j(zero, &no_exceptions); | 1501 __ j(zero, &no_exceptions); |
1502 __ fnclex(); | 1502 __ fnclex(); |
1503 __ bind(&no_exceptions); | 1503 __ bind(&no_exceptions); |
1504 } | 1504 } |
1505 | 1505 |
1506 // Compute st(0) % st(1) | 1506 // Compute st(0) % st(1) |
1507 { | 1507 { |
1508 NearLabel partial_remainder_loop; | 1508 Label partial_remainder_loop; |
1509 __ bind(&partial_remainder_loop); | 1509 __ bind(&partial_remainder_loop); |
1510 __ fprem1(); | 1510 __ fprem1(); |
1511 __ fwait(); | 1511 __ fwait(); |
1512 __ fnstsw_ax(); | 1512 __ fnstsw_ax(); |
1513 __ testl(rax, Immediate(0x400)); // Check C2 bit of FPU status word. | 1513 __ testl(rax, Immediate(0x400)); // Check C2 bit of FPU status word. |
1514 // If C2 is set, computation only has partial result. Loop to | 1514 // If C2 is set, computation only has partial result. Loop to |
1515 // continue computation. | 1515 // continue computation. |
1516 __ j(not_zero, &partial_remainder_loop); | 1516 __ j(not_zero, &partial_remainder_loop); |
1517 } | 1517 } |
1518 // FPU Stack: input, 2*pi, input % 2*pi | 1518 // FPU Stack: input, 2*pi, input % 2*pi |
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1691 Register scratch2, | 1691 Register scratch2, |
1692 Register scratch3, | 1692 Register scratch3, |
1693 Label* on_success, | 1693 Label* on_success, |
1694 Label* on_not_smis) { | 1694 Label* on_not_smis) { |
1695 Register heap_number_map = scratch3; | 1695 Register heap_number_map = scratch3; |
1696 Register smi_result = scratch1; | 1696 Register smi_result = scratch1; |
1697 Label done; | 1697 Label done; |
1698 | 1698 |
1699 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); | 1699 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); |
1700 | 1700 |
1701 NearLabel first_smi, check_second; | 1701 NearLabel first_smi; |
1702 __ JumpIfSmi(first, &first_smi); | 1702 __ JumpIfSmi(first, &first_smi); |
1703 __ cmpq(FieldOperand(first, HeapObject::kMapOffset), heap_number_map); | 1703 __ cmpq(FieldOperand(first, HeapObject::kMapOffset), heap_number_map); |
1704 __ j(not_equal, on_not_smis); | 1704 __ j(not_equal, on_not_smis); |
1705 // Convert HeapNumber to smi if possible. | 1705 // Convert HeapNumber to smi if possible. |
1706 __ movsd(xmm0, FieldOperand(first, HeapNumber::kValueOffset)); | 1706 __ movsd(xmm0, FieldOperand(first, HeapNumber::kValueOffset)); |
1707 __ movq(scratch2, xmm0); | 1707 __ movq(scratch2, xmm0); |
1708 __ cvttsd2siq(smi_result, xmm0); | 1708 __ cvttsd2siq(smi_result, xmm0); |
1709 // Check if conversion was successful by converting back and | 1709 // Check if conversion was successful by converting back and |
1710 // comparing to the original double's bits. | 1710 // comparing to the original double's bits. |
1711 __ cvtlsi2sd(xmm1, smi_result); | 1711 __ cvtlsi2sd(xmm1, smi_result); |
1712 __ movq(kScratchRegister, xmm1); | 1712 __ movq(kScratchRegister, xmm1); |
1713 __ cmpq(scratch2, kScratchRegister); | 1713 __ cmpq(scratch2, kScratchRegister); |
1714 __ j(not_equal, on_not_smis); | 1714 __ j(not_equal, on_not_smis); |
1715 __ Integer32ToSmi(first, smi_result); | 1715 __ Integer32ToSmi(first, smi_result); |
1716 | 1716 |
1717 __ bind(&check_second); | |
1718 __ JumpIfSmi(second, (on_success != NULL) ? on_success : &done); | 1717 __ JumpIfSmi(second, (on_success != NULL) ? on_success : &done); |
1719 __ bind(&first_smi); | 1718 __ bind(&first_smi); |
1720 if (FLAG_debug_code) { | 1719 if (FLAG_debug_code) { |
1721 // Second should be non-smi if we get here. | 1720 // Second should be non-smi if we get here. |
1722 __ AbortIfSmi(second); | 1721 __ AbortIfSmi(second); |
1723 } | 1722 } |
1724 __ cmpq(FieldOperand(second, HeapObject::kMapOffset), heap_number_map); | 1723 __ cmpq(FieldOperand(second, HeapObject::kMapOffset), heap_number_map); |
1725 __ j(not_equal, on_not_smis); | 1724 __ j(not_equal, on_not_smis); |
1726 // Convert second to smi, if possible. | 1725 // Convert second to smi, if possible. |
1727 __ movsd(xmm0, FieldOperand(second, HeapNumber::kValueOffset)); | 1726 __ movsd(xmm0, FieldOperand(second, HeapNumber::kValueOffset)); |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1778 // Optimized version of pow if exponent is a smi. | 1777 // Optimized version of pow if exponent is a smi. |
1779 // xmm0 contains the base. | 1778 // xmm0 contains the base. |
1780 __ bind(&powi); | 1779 __ bind(&powi); |
1781 __ SmiToInteger32(rax, rax); | 1780 __ SmiToInteger32(rax, rax); |
1782 | 1781 |
1783 // Save exponent in base as we need to check if exponent is negative later. | 1782 // Save exponent in base as we need to check if exponent is negative later. |
1784 // We know that base and exponent are in different registers. | 1783 // We know that base and exponent are in different registers. |
1785 __ movq(rdx, rax); | 1784 __ movq(rdx, rax); |
1786 | 1785 |
1787 // Get absolute value of exponent. | 1786 // Get absolute value of exponent. |
1788 NearLabel no_neg; | 1787 Label no_neg; |
1789 __ cmpl(rax, Immediate(0)); | 1788 __ cmpl(rax, Immediate(0)); |
1790 __ j(greater_equal, &no_neg); | 1789 __ j(greater_equal, &no_neg, Label::kNear); |
1791 __ negl(rax); | 1790 __ negl(rax); |
1792 __ bind(&no_neg); | 1791 __ bind(&no_neg); |
1793 | 1792 |
1794 // Load xmm1 with 1. | 1793 // Load xmm1 with 1. |
1795 __ movaps(xmm1, xmm3); | 1794 __ movaps(xmm1, xmm3); |
1796 NearLabel while_true; | 1795 Label while_true; |
1797 NearLabel no_multiply; | 1796 Label no_multiply; |
1798 | 1797 |
1799 __ bind(&while_true); | 1798 __ bind(&while_true); |
1800 __ shrl(rax, Immediate(1)); | 1799 __ shrl(rax, Immediate(1)); |
1801 __ j(not_carry, &no_multiply); | 1800 __ j(not_carry, &no_multiply, Label::kNear); |
1802 __ mulsd(xmm1, xmm0); | 1801 __ mulsd(xmm1, xmm0); |
1803 __ bind(&no_multiply); | 1802 __ bind(&no_multiply); |
1804 __ mulsd(xmm0, xmm0); | 1803 __ mulsd(xmm0, xmm0); |
1805 __ j(not_zero, &while_true); | 1804 __ j(not_zero, &while_true); |
1806 | 1805 |
1807 // Base has the original value of the exponent - if the exponent is | 1806 // Base has the original value of the exponent - if the exponent is |
1808 // negative return 1/result. | 1807 // negative return 1/result. |
1809 __ testl(rdx, rdx); | 1808 __ testl(rdx, rdx); |
1810 __ j(positive, &allocate_return); | 1809 __ j(positive, &allocate_return); |
1811 // Special case if xmm1 has reached infinity. | 1810 // Special case if xmm1 has reached infinity. |
(...skipping 10 matching lines...) Expand all Loading... |
1822 __ bind(&exponent_nonsmi); | 1821 __ bind(&exponent_nonsmi); |
1823 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset), | 1822 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset), |
1824 Heap::kHeapNumberMapRootIndex); | 1823 Heap::kHeapNumberMapRootIndex); |
1825 __ j(not_equal, &call_runtime); | 1824 __ j(not_equal, &call_runtime); |
1826 __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset)); | 1825 __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset)); |
1827 // Test if exponent is nan. | 1826 // Test if exponent is nan. |
1828 __ ucomisd(xmm1, xmm1); | 1827 __ ucomisd(xmm1, xmm1); |
1829 __ j(parity_even, &call_runtime); | 1828 __ j(parity_even, &call_runtime); |
1830 | 1829 |
1831 NearLabel base_not_smi; | 1830 NearLabel base_not_smi; |
1832 NearLabel handle_special_cases; | 1831 Label handle_special_cases; |
1833 __ JumpIfNotSmi(rdx, &base_not_smi); | 1832 __ JumpIfNotSmi(rdx, &base_not_smi); |
1834 __ SmiToInteger32(rdx, rdx); | 1833 __ SmiToInteger32(rdx, rdx); |
1835 __ cvtlsi2sd(xmm0, rdx); | 1834 __ cvtlsi2sd(xmm0, rdx); |
1836 __ jmp(&handle_special_cases); | 1835 __ jmp(&handle_special_cases, Label::kNear); |
1837 | 1836 |
1838 __ bind(&base_not_smi); | 1837 __ bind(&base_not_smi); |
1839 __ CompareRoot(FieldOperand(rdx, HeapObject::kMapOffset), | 1838 __ CompareRoot(FieldOperand(rdx, HeapObject::kMapOffset), |
1840 Heap::kHeapNumberMapRootIndex); | 1839 Heap::kHeapNumberMapRootIndex); |
1841 __ j(not_equal, &call_runtime); | 1840 __ j(not_equal, &call_runtime); |
1842 __ movl(rcx, FieldOperand(rdx, HeapNumber::kExponentOffset)); | 1841 __ movl(rcx, FieldOperand(rdx, HeapNumber::kExponentOffset)); |
1843 __ andl(rcx, Immediate(HeapNumber::kExponentMask)); | 1842 __ andl(rcx, Immediate(HeapNumber::kExponentMask)); |
1844 __ cmpl(rcx, Immediate(HeapNumber::kExponentMask)); | 1843 __ cmpl(rcx, Immediate(HeapNumber::kExponentMask)); |
1845 // base is NaN or +/-Infinity | 1844 // base is NaN or +/-Infinity |
1846 __ j(greater_equal, &call_runtime); | 1845 __ j(greater_equal, &call_runtime); |
1847 __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset)); | 1846 __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset)); |
1848 | 1847 |
1849 // base is in xmm0 and exponent is in xmm1. | 1848 // base is in xmm0 and exponent is in xmm1. |
1850 __ bind(&handle_special_cases); | 1849 __ bind(&handle_special_cases); |
1851 NearLabel not_minus_half; | 1850 Label not_minus_half; |
1852 // Test for -0.5. | 1851 // Test for -0.5. |
1853 // Load xmm2 with -0.5. | 1852 // Load xmm2 with -0.5. |
1854 __ movq(rcx, V8_UINT64_C(0xBFE0000000000000), RelocInfo::NONE); | 1853 __ movq(rcx, V8_UINT64_C(0xBFE0000000000000), RelocInfo::NONE); |
1855 __ movq(xmm2, rcx); | 1854 __ movq(xmm2, rcx); |
1856 // xmm2 now has -0.5. | 1855 // xmm2 now has -0.5. |
1857 __ ucomisd(xmm2, xmm1); | 1856 __ ucomisd(xmm2, xmm1); |
1858 __ j(not_equal, ¬_minus_half); | 1857 __ j(not_equal, ¬_minus_half, Label::kNear); |
1859 | 1858 |
1860 // Calculates reciprocal of square root. | 1859 // Calculates reciprocal of square root. |
1861 // sqrtsd returns -0 when input is -0. ECMA spec requires +0. | 1860 // sqrtsd returns -0 when input is -0. ECMA spec requires +0. |
1862 __ xorps(xmm1, xmm1); | 1861 __ xorps(xmm1, xmm1); |
1863 __ addsd(xmm1, xmm0); | 1862 __ addsd(xmm1, xmm0); |
1864 __ sqrtsd(xmm1, xmm1); | 1863 __ sqrtsd(xmm1, xmm1); |
1865 __ divsd(xmm3, xmm1); | 1864 __ divsd(xmm3, xmm1); |
1866 __ movaps(xmm1, xmm3); | 1865 __ movaps(xmm1, xmm3); |
1867 __ jmp(&allocate_return); | 1866 __ jmp(&allocate_return); |
1868 | 1867 |
(...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2167 // Check that the last match info has space for the capture registers and the | 2166 // Check that the last match info has space for the capture registers and the |
2168 // additional information. Ensure no overflow in add. | 2167 // additional information. Ensure no overflow in add. |
2169 STATIC_ASSERT(FixedArray::kMaxLength < kMaxInt - FixedArray::kLengthOffset); | 2168 STATIC_ASSERT(FixedArray::kMaxLength < kMaxInt - FixedArray::kLengthOffset); |
2170 __ SmiToInteger32(rdi, FieldOperand(rbx, FixedArray::kLengthOffset)); | 2169 __ SmiToInteger32(rdi, FieldOperand(rbx, FixedArray::kLengthOffset)); |
2171 __ addl(rdx, Immediate(RegExpImpl::kLastMatchOverhead)); | 2170 __ addl(rdx, Immediate(RegExpImpl::kLastMatchOverhead)); |
2172 __ cmpl(rdx, rdi); | 2171 __ cmpl(rdx, rdi); |
2173 __ j(greater, &runtime); | 2172 __ j(greater, &runtime); |
2174 | 2173 |
2175 // rax: RegExp data (FixedArray) | 2174 // rax: RegExp data (FixedArray) |
2176 // Check the representation and encoding of the subject string. | 2175 // Check the representation and encoding of the subject string. |
2177 NearLabel seq_ascii_string, seq_two_byte_string, check_code; | 2176 Label seq_ascii_string, seq_two_byte_string, check_code; |
2178 __ movq(rdi, Operand(rsp, kSubjectOffset)); | 2177 __ movq(rdi, Operand(rsp, kSubjectOffset)); |
2179 __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); | 2178 __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); |
2180 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); | 2179 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); |
2181 // First check for flat two byte string. | 2180 // First check for flat two byte string. |
2182 __ andb(rbx, Immediate( | 2181 __ andb(rbx, Immediate( |
2183 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask)); | 2182 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask)); |
2184 STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0); | 2183 STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0); |
2185 __ j(zero, &seq_two_byte_string); | 2184 __ j(zero, &seq_two_byte_string, Label::kNear); |
2186 // Any other flat string must be a flat ascii string. | 2185 // Any other flat string must be a flat ascii string. |
2187 __ testb(rbx, Immediate(kIsNotStringMask | kStringRepresentationMask)); | 2186 __ testb(rbx, Immediate(kIsNotStringMask | kStringRepresentationMask)); |
2188 __ j(zero, &seq_ascii_string); | 2187 __ j(zero, &seq_ascii_string, Label::kNear); |
2189 | 2188 |
2190 // Check for flat cons string. | 2189 // Check for flat cons string. |
2191 // A flat cons string is a cons string where the second part is the empty | 2190 // A flat cons string is a cons string where the second part is the empty |
2192 // string. In that case the subject string is just the first part of the cons | 2191 // string. In that case the subject string is just the first part of the cons |
2193 // string. Also in this case the first part of the cons string is known to be | 2192 // string. Also in this case the first part of the cons string is known to be |
2194 // a sequential string or an external string. | 2193 // a sequential string or an external string. |
2195 STATIC_ASSERT(kExternalStringTag !=0); | 2194 STATIC_ASSERT(kExternalStringTag !=0); |
2196 STATIC_ASSERT((kConsStringTag & kExternalStringTag) == 0); | 2195 STATIC_ASSERT((kConsStringTag & kExternalStringTag) == 0); |
2197 __ testb(rbx, Immediate(kIsNotStringMask | kExternalStringTag)); | 2196 __ testb(rbx, Immediate(kIsNotStringMask | kExternalStringTag)); |
2198 __ j(not_zero, &runtime); | 2197 __ j(not_zero, &runtime); |
2199 // String is a cons string. | 2198 // String is a cons string. |
2200 __ CompareRoot(FieldOperand(rdi, ConsString::kSecondOffset), | 2199 __ CompareRoot(FieldOperand(rdi, ConsString::kSecondOffset), |
2201 Heap::kEmptyStringRootIndex); | 2200 Heap::kEmptyStringRootIndex); |
2202 __ j(not_equal, &runtime); | 2201 __ j(not_equal, &runtime); |
2203 __ movq(rdi, FieldOperand(rdi, ConsString::kFirstOffset)); | 2202 __ movq(rdi, FieldOperand(rdi, ConsString::kFirstOffset)); |
2204 __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); | 2203 __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); |
2205 // String is a cons string with empty second part. | 2204 // String is a cons string with empty second part. |
2206 // rdi: first part of cons string. | 2205 // rdi: first part of cons string. |
2207 // rbx: map of first part of cons string. | 2206 // rbx: map of first part of cons string. |
2208 // Is first part a flat two byte string? | 2207 // Is first part a flat two byte string? |
2209 __ testb(FieldOperand(rbx, Map::kInstanceTypeOffset), | 2208 __ testb(FieldOperand(rbx, Map::kInstanceTypeOffset), |
2210 Immediate(kStringRepresentationMask | kStringEncodingMask)); | 2209 Immediate(kStringRepresentationMask | kStringEncodingMask)); |
2211 STATIC_ASSERT((kSeqStringTag | kTwoByteStringTag) == 0); | 2210 STATIC_ASSERT((kSeqStringTag | kTwoByteStringTag) == 0); |
2212 __ j(zero, &seq_two_byte_string); | 2211 __ j(zero, &seq_two_byte_string, Label::kNear); |
2213 // Any other flat string must be ascii. | 2212 // Any other flat string must be ascii. |
2214 __ testb(FieldOperand(rbx, Map::kInstanceTypeOffset), | 2213 __ testb(FieldOperand(rbx, Map::kInstanceTypeOffset), |
2215 Immediate(kStringRepresentationMask)); | 2214 Immediate(kStringRepresentationMask)); |
2216 __ j(not_zero, &runtime); | 2215 __ j(not_zero, &runtime); |
2217 | 2216 |
2218 __ bind(&seq_ascii_string); | 2217 __ bind(&seq_ascii_string); |
2219 // rdi: subject string (sequential ascii) | 2218 // rdi: subject string (sequential ascii) |
2220 // rax: RegExp data (FixedArray) | 2219 // rax: RegExp data (FixedArray) |
2221 __ movq(r11, FieldOperand(rax, JSRegExp::kDataAsciiCodeOffset)); | 2220 __ movq(r11, FieldOperand(rax, JSRegExp::kDataAsciiCodeOffset)); |
2222 __ Set(rcx, 1); // Type is ascii. | 2221 __ Set(rcx, 1); // Type is ascii. |
2223 __ jmp(&check_code); | 2222 __ jmp(&check_code, Label::kNear); |
2224 | 2223 |
2225 __ bind(&seq_two_byte_string); | 2224 __ bind(&seq_two_byte_string); |
2226 // rdi: subject string (flat two-byte) | 2225 // rdi: subject string (flat two-byte) |
2227 // rax: RegExp data (FixedArray) | 2226 // rax: RegExp data (FixedArray) |
2228 __ movq(r11, FieldOperand(rax, JSRegExp::kDataUC16CodeOffset)); | 2227 __ movq(r11, FieldOperand(rax, JSRegExp::kDataUC16CodeOffset)); |
2229 __ Set(rcx, 0); // Type is two byte. | 2228 __ Set(rcx, 0); // Type is two byte. |
2230 | 2229 |
2231 __ bind(&check_code); | 2230 __ bind(&check_code); |
2232 // Check that the irregexp code has been generated for the actual string | 2231 // Check that the irregexp code has been generated for the actual string |
2233 // encoding. If it has, the field contains a code object otherwise it contains | 2232 // encoding. If it has, the field contains a code object otherwise it contains |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2299 #endif | 2298 #endif |
2300 | 2299 |
2301 // Keep track on aliasing between argX defined above and the registers used. | 2300 // Keep track on aliasing between argX defined above and the registers used. |
2302 // rdi: subject string | 2301 // rdi: subject string |
2303 // rbx: previous index | 2302 // rbx: previous index |
2304 // rcx: encoding of subject string (1 if ascii 0 if two_byte); | 2303 // rcx: encoding of subject string (1 if ascii 0 if two_byte); |
2305 // r11: code | 2304 // r11: code |
2306 | 2305 |
2307 // Argument 4: End of string data | 2306 // Argument 4: End of string data |
2308 // Argument 3: Start of string data | 2307 // Argument 3: Start of string data |
2309 NearLabel setup_two_byte, setup_rest; | 2308 Label setup_two_byte, setup_rest; |
2310 __ testb(rcx, rcx); // Last use of rcx as encoding of subject string. | 2309 __ testb(rcx, rcx); // Last use of rcx as encoding of subject string. |
2311 __ j(zero, &setup_two_byte); | 2310 __ j(zero, &setup_two_byte, Label::kNear); |
2312 __ SmiToInteger32(rcx, FieldOperand(rdi, String::kLengthOffset)); | 2311 __ SmiToInteger32(rcx, FieldOperand(rdi, String::kLengthOffset)); |
2313 __ lea(arg4, FieldOperand(rdi, rcx, times_1, SeqAsciiString::kHeaderSize)); | 2312 __ lea(arg4, FieldOperand(rdi, rcx, times_1, SeqAsciiString::kHeaderSize)); |
2314 __ lea(arg3, FieldOperand(rdi, rbx, times_1, SeqAsciiString::kHeaderSize)); | 2313 __ lea(arg3, FieldOperand(rdi, rbx, times_1, SeqAsciiString::kHeaderSize)); |
2315 __ jmp(&setup_rest); | 2314 __ jmp(&setup_rest, Label::kNear); |
2316 __ bind(&setup_two_byte); | 2315 __ bind(&setup_two_byte); |
2317 __ SmiToInteger32(rcx, FieldOperand(rdi, String::kLengthOffset)); | 2316 __ SmiToInteger32(rcx, FieldOperand(rdi, String::kLengthOffset)); |
2318 __ lea(arg4, FieldOperand(rdi, rcx, times_2, SeqTwoByteString::kHeaderSize)); | 2317 __ lea(arg4, FieldOperand(rdi, rcx, times_2, SeqTwoByteString::kHeaderSize)); |
2319 __ lea(arg3, FieldOperand(rdi, rbx, times_2, SeqTwoByteString::kHeaderSize)); | 2318 __ lea(arg3, FieldOperand(rdi, rbx, times_2, SeqTwoByteString::kHeaderSize)); |
2320 | 2319 |
2321 __ bind(&setup_rest); | 2320 __ bind(&setup_rest); |
2322 // Argument 2: Previous index. | 2321 // Argument 2: Previous index. |
2323 __ movq(arg2, rbx); | 2322 __ movq(arg2, rbx); |
2324 | 2323 |
2325 // Argument 1: Subject string. | 2324 // Argument 1: Subject string. |
2326 #ifdef _WIN64 | 2325 #ifdef _WIN64 |
2327 __ movq(arg1, rdi); | 2326 __ movq(arg1, rdi); |
2328 #else | 2327 #else |
2329 // Already there in AMD64 calling convention. | 2328 // Already there in AMD64 calling convention. |
2330 ASSERT(arg1.is(rdi)); | 2329 ASSERT(arg1.is(rdi)); |
2331 #endif | 2330 #endif |
2332 | 2331 |
2333 // Locate the code entry and call it. | 2332 // Locate the code entry and call it. |
2334 __ addq(r11, Immediate(Code::kHeaderSize - kHeapObjectTag)); | 2333 __ addq(r11, Immediate(Code::kHeaderSize - kHeapObjectTag)); |
2335 __ call(r11); | 2334 __ call(r11); |
2336 | 2335 |
2337 __ LeaveApiExitFrame(); | 2336 __ LeaveApiExitFrame(); |
2338 | 2337 |
2339 // Check the result. | 2338 // Check the result. |
2340 NearLabel success; | 2339 Label success; |
2341 Label exception; | 2340 Label exception; |
2342 __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::SUCCESS)); | 2341 __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::SUCCESS)); |
2343 __ j(equal, &success); | 2342 __ j(equal, &success, Label::kNear); |
2344 __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::EXCEPTION)); | 2343 __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::EXCEPTION)); |
2345 __ j(equal, &exception); | 2344 __ j(equal, &exception); |
2346 __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::FAILURE)); | 2345 __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::FAILURE)); |
2347 // If none of the above, it can only be retry. | 2346 // If none of the above, it can only be retry. |
2348 // Handle that in the runtime system. | 2347 // Handle that in the runtime system. |
2349 __ j(not_equal, &runtime); | 2348 __ j(not_equal, &runtime); |
2350 | 2349 |
2351 // For failure return null. | 2350 // For failure return null. |
2352 __ LoadRoot(rax, Heap::kNullValueRootIndex); | 2351 __ LoadRoot(rax, Heap::kNullValueRootIndex); |
2353 __ ret(4 * kPointerSize); | 2352 __ ret(4 * kPointerSize); |
(...skipping 28 matching lines...) Expand all Loading... |
2382 __ movq(rcx, rbx); | 2381 __ movq(rcx, rbx); |
2383 __ RecordWrite(rcx, RegExpImpl::kLastInputOffset, rax, rdi); | 2382 __ RecordWrite(rcx, RegExpImpl::kLastInputOffset, rax, rdi); |
2384 | 2383 |
2385 // Get the static offsets vector filled by the native regexp code. | 2384 // Get the static offsets vector filled by the native regexp code. |
2386 __ LoadAddress(rcx, | 2385 __ LoadAddress(rcx, |
2387 ExternalReference::address_of_static_offsets_vector(isolate)); | 2386 ExternalReference::address_of_static_offsets_vector(isolate)); |
2388 | 2387 |
2389 // rbx: last_match_info backing store (FixedArray) | 2388 // rbx: last_match_info backing store (FixedArray) |
2390 // rcx: offsets vector | 2389 // rcx: offsets vector |
2391 // rdx: number of capture registers | 2390 // rdx: number of capture registers |
2392 NearLabel next_capture, done; | 2391 Label next_capture, done; |
2393 // Capture register counter starts from number of capture registers and | 2392 // Capture register counter starts from number of capture registers and |
2394 // counts down until wraping after zero. | 2393 // counts down until wraping after zero. |
2395 __ bind(&next_capture); | 2394 __ bind(&next_capture); |
2396 __ subq(rdx, Immediate(1)); | 2395 __ subq(rdx, Immediate(1)); |
2397 __ j(negative, &done); | 2396 __ j(negative, &done, Label::kNear); |
2398 // Read the value from the static offsets vector buffer and make it a smi. | 2397 // Read the value from the static offsets vector buffer and make it a smi. |
2399 __ movl(rdi, Operand(rcx, rdx, times_int_size, 0)); | 2398 __ movl(rdi, Operand(rcx, rdx, times_int_size, 0)); |
2400 __ Integer32ToSmi(rdi, rdi); | 2399 __ Integer32ToSmi(rdi, rdi); |
2401 // Store the smi value in the last match info. | 2400 // Store the smi value in the last match info. |
2402 __ movq(FieldOperand(rbx, | 2401 __ movq(FieldOperand(rbx, |
2403 rdx, | 2402 rdx, |
2404 times_pointer_size, | 2403 times_pointer_size, |
2405 RegExpImpl::kFirstCaptureOffset), | 2404 RegExpImpl::kFirstCaptureOffset), |
2406 rdi); | 2405 rdi); |
2407 __ jmp(&next_capture); | 2406 __ jmp(&next_capture); |
(...skipping 12 matching lines...) Expand all Loading... |
2420 Isolate::k_pending_exception_address, isolate); | 2419 Isolate::k_pending_exception_address, isolate); |
2421 Operand pending_exception_operand = | 2420 Operand pending_exception_operand = |
2422 masm->ExternalOperand(pending_exception_address, rbx); | 2421 masm->ExternalOperand(pending_exception_address, rbx); |
2423 __ movq(rax, pending_exception_operand); | 2422 __ movq(rax, pending_exception_operand); |
2424 __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex); | 2423 __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex); |
2425 __ cmpq(rax, rdx); | 2424 __ cmpq(rax, rdx); |
2426 __ j(equal, &runtime); | 2425 __ j(equal, &runtime); |
2427 __ movq(pending_exception_operand, rdx); | 2426 __ movq(pending_exception_operand, rdx); |
2428 | 2427 |
2429 __ CompareRoot(rax, Heap::kTerminationExceptionRootIndex); | 2428 __ CompareRoot(rax, Heap::kTerminationExceptionRootIndex); |
2430 NearLabel termination_exception; | 2429 Label termination_exception; |
2431 __ j(equal, &termination_exception); | 2430 __ j(equal, &termination_exception, Label::kNear); |
2432 __ Throw(rax); | 2431 __ Throw(rax); |
2433 | 2432 |
2434 __ bind(&termination_exception); | 2433 __ bind(&termination_exception); |
2435 __ ThrowUncatchable(TERMINATION, rax); | 2434 __ ThrowUncatchable(TERMINATION, rax); |
2436 | 2435 |
2437 // Do the runtime call to execute the regexp. | 2436 // Do the runtime call to execute the regexp. |
2438 __ bind(&runtime); | 2437 __ bind(&runtime); |
2439 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); | 2438 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); |
2440 #endif // V8_INTERPRETED_REGEXP | 2439 #endif // V8_INTERPRETED_REGEXP |
2441 } | 2440 } |
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2664 __ bind(&ok); | 2663 __ bind(&ok); |
2665 } | 2664 } |
2666 | 2665 |
2667 // The compare stub returns a positive, negative, or zero 64-bit integer | 2666 // The compare stub returns a positive, negative, or zero 64-bit integer |
2668 // value in rax, corresponding to result of comparing the two inputs. | 2667 // value in rax, corresponding to result of comparing the two inputs. |
2669 // NOTICE! This code is only reached after a smi-fast-case check, so | 2668 // NOTICE! This code is only reached after a smi-fast-case check, so |
2670 // it is certain that at least one operand isn't a smi. | 2669 // it is certain that at least one operand isn't a smi. |
2671 | 2670 |
2672 // Two identical objects are equal unless they are both NaN or undefined. | 2671 // Two identical objects are equal unless they are both NaN or undefined. |
2673 { | 2672 { |
2674 NearLabel not_identical; | 2673 Label not_identical; |
2675 __ cmpq(rax, rdx); | 2674 __ cmpq(rax, rdx); |
2676 __ j(not_equal, ¬_identical); | 2675 __ j(not_equal, ¬_identical, Label::kNear); |
2677 | 2676 |
2678 if (cc_ != equal) { | 2677 if (cc_ != equal) { |
2679 // Check for undefined. undefined OP undefined is false even though | 2678 // Check for undefined. undefined OP undefined is false even though |
2680 // undefined == undefined. | 2679 // undefined == undefined. |
2681 NearLabel check_for_nan; | 2680 Label check_for_nan; |
2682 __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex); | 2681 __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex); |
2683 __ j(not_equal, &check_for_nan); | 2682 __ j(not_equal, &check_for_nan, Label::kNear); |
2684 __ Set(rax, NegativeComparisonResult(cc_)); | 2683 __ Set(rax, NegativeComparisonResult(cc_)); |
2685 __ ret(0); | 2684 __ ret(0); |
2686 __ bind(&check_for_nan); | 2685 __ bind(&check_for_nan); |
2687 } | 2686 } |
2688 | 2687 |
2689 // Test for NaN. Sadly, we can't just compare to FACTORY->nan_value(), | 2688 // Test for NaN. Sadly, we can't just compare to FACTORY->nan_value(), |
2690 // so we do the second best thing - test it ourselves. | 2689 // so we do the second best thing - test it ourselves. |
2691 // Note: if cc_ != equal, never_nan_nan_ is not used. | 2690 // Note: if cc_ != equal, never_nan_nan_ is not used. |
2692 // We cannot set rax to EQUAL until just before return because | 2691 // We cannot set rax to EQUAL until just before return because |
2693 // rax must be unchanged on jump to not_identical. | 2692 // rax must be unchanged on jump to not_identical. |
2694 if (never_nan_nan_ && (cc_ == equal)) { | 2693 if (never_nan_nan_ && (cc_ == equal)) { |
2695 __ Set(rax, EQUAL); | 2694 __ Set(rax, EQUAL); |
2696 __ ret(0); | 2695 __ ret(0); |
2697 } else { | 2696 } else { |
2698 NearLabel heap_number; | 2697 Label heap_number; |
2699 // If it's not a heap number, then return equal for (in)equality operator. | 2698 // If it's not a heap number, then return equal for (in)equality operator. |
2700 __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), | 2699 __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), |
2701 factory->heap_number_map()); | 2700 factory->heap_number_map()); |
2702 __ j(equal, &heap_number); | 2701 __ j(equal, &heap_number, Label::kNear); |
2703 if (cc_ != equal) { | 2702 if (cc_ != equal) { |
2704 // Call runtime on identical JSObjects. Otherwise return equal. | 2703 // Call runtime on identical JSObjects. Otherwise return equal. |
2705 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx); | 2704 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx); |
2706 __ j(above_equal, ¬_identical); | 2705 __ j(above_equal, ¬_identical, Label::kNear); |
2707 } | 2706 } |
2708 __ Set(rax, EQUAL); | 2707 __ Set(rax, EQUAL); |
2709 __ ret(0); | 2708 __ ret(0); |
2710 | 2709 |
2711 __ bind(&heap_number); | 2710 __ bind(&heap_number); |
2712 // It is a heap number, so return equal if it's not NaN. | 2711 // It is a heap number, so return equal if it's not NaN. |
2713 // For NaN, return 1 for every condition except greater and | 2712 // For NaN, return 1 for every condition except greater and |
2714 // greater-equal. Return -1 for them, so the comparison yields | 2713 // greater-equal. Return -1 for them, so the comparison yields |
2715 // false for all conditions except not-equal. | 2714 // false for all conditions except not-equal. |
2716 __ Set(rax, EQUAL); | 2715 __ Set(rax, EQUAL); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2752 | 2751 |
2753 __ bind(¬_smis); | 2752 __ bind(¬_smis); |
2754 } | 2753 } |
2755 | 2754 |
2756 // If either operand is a JSObject or an oddball value, then they are not | 2755 // If either operand is a JSObject or an oddball value, then they are not |
2757 // equal since their pointers are different | 2756 // equal since their pointers are different |
2758 // There is no test for undetectability in strict equality. | 2757 // There is no test for undetectability in strict equality. |
2759 | 2758 |
2760 // If the first object is a JS object, we have done pointer comparison. | 2759 // If the first object is a JS object, we have done pointer comparison. |
2761 STATIC_ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | 2760 STATIC_ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); |
2762 NearLabel first_non_object; | 2761 Label first_non_object; |
2763 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx); | 2762 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx); |
2764 __ j(below, &first_non_object); | 2763 __ j(below, &first_non_object, Label::kNear); |
2765 // Return non-zero (eax (not rax) is not zero) | 2764 // Return non-zero (eax (not rax) is not zero) |
2766 Label return_not_equal; | 2765 Label return_not_equal; |
2767 STATIC_ASSERT(kHeapObjectTag != 0); | 2766 STATIC_ASSERT(kHeapObjectTag != 0); |
2768 __ bind(&return_not_equal); | 2767 __ bind(&return_not_equal); |
2769 __ ret(0); | 2768 __ ret(0); |
2770 | 2769 |
2771 __ bind(&first_non_object); | 2770 __ bind(&first_non_object); |
2772 // Check for oddballs: true, false, null, undefined. | 2771 // Check for oddballs: true, false, null, undefined. |
2773 __ CmpInstanceType(rcx, ODDBALL_TYPE); | 2772 __ CmpInstanceType(rcx, ODDBALL_TYPE); |
2774 __ j(equal, &return_not_equal); | 2773 __ j(equal, &return_not_equal); |
2775 | 2774 |
2776 __ CmpObjectType(rdx, FIRST_JS_OBJECT_TYPE, rcx); | 2775 __ CmpObjectType(rdx, FIRST_JS_OBJECT_TYPE, rcx); |
2777 __ j(above_equal, &return_not_equal); | 2776 __ j(above_equal, &return_not_equal); |
2778 | 2777 |
2779 // Check for oddballs: true, false, null, undefined. | 2778 // Check for oddballs: true, false, null, undefined. |
2780 __ CmpInstanceType(rcx, ODDBALL_TYPE); | 2779 __ CmpInstanceType(rcx, ODDBALL_TYPE); |
2781 __ j(equal, &return_not_equal); | 2780 __ j(equal, &return_not_equal); |
2782 | 2781 |
2783 // Fall through to the general case. | 2782 // Fall through to the general case. |
2784 } | 2783 } |
2785 __ bind(&slow); | 2784 __ bind(&slow); |
2786 } | 2785 } |
2787 | 2786 |
2788 // Generate the number comparison code. | 2787 // Generate the number comparison code. |
2789 if (include_number_compare_) { | 2788 if (include_number_compare_) { |
2790 Label non_number_comparison; | 2789 Label non_number_comparison; |
2791 NearLabel unordered; | 2790 Label unordered; |
2792 FloatingPointHelper::LoadSSE2UnknownOperands(masm, &non_number_comparison); | 2791 FloatingPointHelper::LoadSSE2UnknownOperands(masm, &non_number_comparison); |
2793 __ xorl(rax, rax); | 2792 __ xorl(rax, rax); |
2794 __ xorl(rcx, rcx); | 2793 __ xorl(rcx, rcx); |
2795 __ ucomisd(xmm0, xmm1); | 2794 __ ucomisd(xmm0, xmm1); |
2796 | 2795 |
2797 // Don't base result on EFLAGS when a NaN is involved. | 2796 // Don't base result on EFLAGS when a NaN is involved. |
2798 __ j(parity_even, &unordered); | 2797 __ j(parity_even, &unordered, Label::kNear); |
2799 // Return a result of -1, 0, or 1, based on EFLAGS. | 2798 // Return a result of -1, 0, or 1, based on EFLAGS. |
2800 __ setcc(above, rax); | 2799 __ setcc(above, rax); |
2801 __ setcc(below, rcx); | 2800 __ setcc(below, rcx); |
2802 __ subq(rax, rcx); | 2801 __ subq(rax, rcx); |
2803 __ ret(0); | 2802 __ ret(0); |
2804 | 2803 |
2805 // If one of the numbers was NaN, then the result is always false. | 2804 // If one of the numbers was NaN, then the result is always false. |
2806 // The cc is never not-equal. | 2805 // The cc is never not-equal. |
2807 __ bind(&unordered); | 2806 __ bind(&unordered); |
2808 ASSERT(cc_ != not_equal); | 2807 ASSERT(cc_ != not_equal); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2853 | 2852 |
2854 #ifdef DEBUG | 2853 #ifdef DEBUG |
2855 __ Abort("Unexpected fall-through from string comparison"); | 2854 __ Abort("Unexpected fall-through from string comparison"); |
2856 #endif | 2855 #endif |
2857 | 2856 |
2858 __ bind(&check_unequal_objects); | 2857 __ bind(&check_unequal_objects); |
2859 if (cc_ == equal && !strict_) { | 2858 if (cc_ == equal && !strict_) { |
2860 // Not strict equality. Objects are unequal if | 2859 // Not strict equality. Objects are unequal if |
2861 // they are both JSObjects and not undetectable, | 2860 // they are both JSObjects and not undetectable, |
2862 // and their pointers are different. | 2861 // and their pointers are different. |
2863 NearLabel not_both_objects, return_unequal; | 2862 Label not_both_objects, return_unequal; |
2864 // At most one is a smi, so we can test for smi by adding the two. | 2863 // At most one is a smi, so we can test for smi by adding the two. |
2865 // A smi plus a heap object has the low bit set, a heap object plus | 2864 // A smi plus a heap object has the low bit set, a heap object plus |
2866 // a heap object has the low bit clear. | 2865 // a heap object has the low bit clear. |
2867 STATIC_ASSERT(kSmiTag == 0); | 2866 STATIC_ASSERT(kSmiTag == 0); |
2868 STATIC_ASSERT(kSmiTagMask == 1); | 2867 STATIC_ASSERT(kSmiTagMask == 1); |
2869 __ lea(rcx, Operand(rax, rdx, times_1, 0)); | 2868 __ lea(rcx, Operand(rax, rdx, times_1, 0)); |
2870 __ testb(rcx, Immediate(kSmiTagMask)); | 2869 __ testb(rcx, Immediate(kSmiTagMask)); |
2871 __ j(not_zero, ¬_both_objects); | 2870 __ j(not_zero, ¬_both_objects, Label::kNear); |
2872 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rbx); | 2871 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rbx); |
2873 __ j(below, ¬_both_objects); | 2872 __ j(below, ¬_both_objects, Label::kNear); |
2874 __ CmpObjectType(rdx, FIRST_JS_OBJECT_TYPE, rcx); | 2873 __ CmpObjectType(rdx, FIRST_JS_OBJECT_TYPE, rcx); |
2875 __ j(below, ¬_both_objects); | 2874 __ j(below, ¬_both_objects, Label::kNear); |
2876 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), | 2875 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), |
2877 Immediate(1 << Map::kIsUndetectable)); | 2876 Immediate(1 << Map::kIsUndetectable)); |
2878 __ j(zero, &return_unequal); | 2877 __ j(zero, &return_unequal, Label::kNear); |
2879 __ testb(FieldOperand(rcx, Map::kBitFieldOffset), | 2878 __ testb(FieldOperand(rcx, Map::kBitFieldOffset), |
2880 Immediate(1 << Map::kIsUndetectable)); | 2879 Immediate(1 << Map::kIsUndetectable)); |
2881 __ j(zero, &return_unequal); | 2880 __ j(zero, &return_unequal, Label::kNear); |
2882 // The objects are both undetectable, so they both compare as the value | 2881 // The objects are both undetectable, so they both compare as the value |
2883 // undefined, and are equal. | 2882 // undefined, and are equal. |
2884 __ Set(rax, EQUAL); | 2883 __ Set(rax, EQUAL); |
2885 __ bind(&return_unequal); | 2884 __ bind(&return_unequal); |
2886 // Return non-equal by returning the non-zero object pointer in rax, | 2885 // Return non-equal by returning the non-zero object pointer in rax, |
2887 // or return equal if we fell through to here. | 2886 // or return equal if we fell through to here. |
2888 __ ret(0); | 2887 __ ret(0); |
2889 __ bind(¬_both_objects); | 2888 __ bind(¬_both_objects); |
2890 } | 2889 } |
2891 | 2890 |
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3101 __ testl(rcx, Immediate(kFailureTagMask)); | 3100 __ testl(rcx, Immediate(kFailureTagMask)); |
3102 __ j(zero, &failure_returned); | 3101 __ j(zero, &failure_returned); |
3103 | 3102 |
3104 // Exit the JavaScript to C++ exit frame. | 3103 // Exit the JavaScript to C++ exit frame. |
3105 __ LeaveExitFrame(save_doubles_); | 3104 __ LeaveExitFrame(save_doubles_); |
3106 __ ret(0); | 3105 __ ret(0); |
3107 | 3106 |
3108 // Handling of failure. | 3107 // Handling of failure. |
3109 __ bind(&failure_returned); | 3108 __ bind(&failure_returned); |
3110 | 3109 |
3111 NearLabel retry; | 3110 Label retry; |
3112 // If the returned exception is RETRY_AFTER_GC continue at retry label | 3111 // If the returned exception is RETRY_AFTER_GC continue at retry label |
3113 STATIC_ASSERT(Failure::RETRY_AFTER_GC == 0); | 3112 STATIC_ASSERT(Failure::RETRY_AFTER_GC == 0); |
3114 __ testl(rax, Immediate(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize)); | 3113 __ testl(rax, Immediate(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize)); |
3115 __ j(zero, &retry); | 3114 __ j(zero, &retry, Label::kNear); |
3116 | 3115 |
3117 // Special handling of out of memory exceptions. | 3116 // Special handling of out of memory exceptions. |
3118 __ movq(kScratchRegister, Failure::OutOfMemoryException(), RelocInfo::NONE); | 3117 __ movq(kScratchRegister, Failure::OutOfMemoryException(), RelocInfo::NONE); |
3119 __ cmpq(rax, kScratchRegister); | 3118 __ cmpq(rax, kScratchRegister); |
3120 __ j(equal, throw_out_of_memory_exception); | 3119 __ j(equal, throw_out_of_memory_exception); |
3121 | 3120 |
3122 // Retrieve the pending exception and clear the variable. | 3121 // Retrieve the pending exception and clear the variable. |
3123 ExternalReference pending_exception_address( | 3122 ExternalReference pending_exception_address( |
3124 Isolate::k_pending_exception_address, masm->isolate()); | 3123 Isolate::k_pending_exception_address, masm->isolate()); |
3125 Operand pending_exception_operand = | 3124 Operand pending_exception_operand = |
(...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3406 __ j(above, &slow); | 3405 __ j(above, &slow); |
3407 | 3406 |
3408 // Get the prototype of the function. | 3407 // Get the prototype of the function. |
3409 __ movq(rdx, Operand(rsp, 1 * kPointerSize + extra_stack_space)); | 3408 __ movq(rdx, Operand(rsp, 1 * kPointerSize + extra_stack_space)); |
3410 // rdx is function, rax is map. | 3409 // rdx is function, rax is map. |
3411 | 3410 |
3412 // If there is a call site cache don't look in the global cache, but do the | 3411 // If there is a call site cache don't look in the global cache, but do the |
3413 // real lookup and update the call site cache. | 3412 // real lookup and update the call site cache. |
3414 if (!HasCallSiteInlineCheck()) { | 3413 if (!HasCallSiteInlineCheck()) { |
3415 // Look up the function and the map in the instanceof cache. | 3414 // Look up the function and the map in the instanceof cache. |
3416 NearLabel miss; | 3415 Label miss; |
3417 __ CompareRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex); | 3416 __ CompareRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex); |
3418 __ j(not_equal, &miss); | 3417 __ j(not_equal, &miss, Label::kNear); |
3419 __ CompareRoot(rax, Heap::kInstanceofCacheMapRootIndex); | 3418 __ CompareRoot(rax, Heap::kInstanceofCacheMapRootIndex); |
3420 __ j(not_equal, &miss); | 3419 __ j(not_equal, &miss, Label::kNear); |
3421 __ LoadRoot(rax, Heap::kInstanceofCacheAnswerRootIndex); | 3420 __ LoadRoot(rax, Heap::kInstanceofCacheAnswerRootIndex); |
3422 __ ret(2 * kPointerSize); | 3421 __ ret(2 * kPointerSize); |
3423 __ bind(&miss); | 3422 __ bind(&miss); |
3424 } | 3423 } |
3425 | 3424 |
3426 __ TryGetFunctionPrototype(rdx, rbx, &slow); | 3425 __ TryGetFunctionPrototype(rdx, rbx, &slow); |
3427 | 3426 |
3428 // Check that the function prototype is a JS object. | 3427 // Check that the function prototype is a JS object. |
3429 __ JumpIfSmi(rbx, &slow); | 3428 __ JumpIfSmi(rbx, &slow); |
3430 __ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, kScratchRegister); | 3429 __ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, kScratchRegister); |
(...skipping 15 matching lines...) Expand all Loading... |
3446 if (FLAG_debug_code) { | 3445 if (FLAG_debug_code) { |
3447 __ movl(rdi, Immediate(kWordBeforeMapCheckValue)); | 3446 __ movl(rdi, Immediate(kWordBeforeMapCheckValue)); |
3448 __ cmpl(Operand(kScratchRegister, kOffsetToMapCheckValue - 4), rdi); | 3447 __ cmpl(Operand(kScratchRegister, kOffsetToMapCheckValue - 4), rdi); |
3449 __ Assert(equal, "InstanceofStub unexpected call site cache (check)."); | 3448 __ Assert(equal, "InstanceofStub unexpected call site cache (check)."); |
3450 } | 3449 } |
3451 } | 3450 } |
3452 | 3451 |
3453 __ movq(rcx, FieldOperand(rax, Map::kPrototypeOffset)); | 3452 __ movq(rcx, FieldOperand(rax, Map::kPrototypeOffset)); |
3454 | 3453 |
3455 // Loop through the prototype chain looking for the function prototype. | 3454 // Loop through the prototype chain looking for the function prototype. |
3456 NearLabel loop, is_instance, is_not_instance; | 3455 Label loop, is_instance, is_not_instance; |
3457 __ LoadRoot(kScratchRegister, Heap::kNullValueRootIndex); | 3456 __ LoadRoot(kScratchRegister, Heap::kNullValueRootIndex); |
3458 __ bind(&loop); | 3457 __ bind(&loop); |
3459 __ cmpq(rcx, rbx); | 3458 __ cmpq(rcx, rbx); |
3460 __ j(equal, &is_instance); | 3459 __ j(equal, &is_instance, Label::kNear); |
3461 __ cmpq(rcx, kScratchRegister); | 3460 __ cmpq(rcx, kScratchRegister); |
3462 // The code at is_not_instance assumes that kScratchRegister contains a | 3461 // The code at is_not_instance assumes that kScratchRegister contains a |
3463 // non-zero GCable value (the null object in this case). | 3462 // non-zero GCable value (the null object in this case). |
3464 __ j(equal, &is_not_instance); | 3463 __ j(equal, &is_not_instance, Label::kNear); |
3465 __ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset)); | 3464 __ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset)); |
3466 __ movq(rcx, FieldOperand(rcx, Map::kPrototypeOffset)); | 3465 __ movq(rcx, FieldOperand(rcx, Map::kPrototypeOffset)); |
3467 __ jmp(&loop); | 3466 __ jmp(&loop); |
3468 | 3467 |
3469 __ bind(&is_instance); | 3468 __ bind(&is_instance); |
3470 if (!HasCallSiteInlineCheck()) { | 3469 if (!HasCallSiteInlineCheck()) { |
3471 __ xorl(rax, rax); | 3470 __ xorl(rax, rax); |
3472 // Store bitwise zero in the cache. This is a Smi in GC terms. | 3471 // Store bitwise zero in the cache. This is a Smi in GC terms. |
3473 STATIC_ASSERT(kSmiTag == 0); | 3472 STATIC_ASSERT(kSmiTag == 0); |
3474 __ StoreRoot(rax, Heap::kInstanceofCacheAnswerRootIndex); | 3473 __ StoreRoot(rax, Heap::kInstanceofCacheAnswerRootIndex); |
(...skipping 344 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3819 GenerateConvertArgument(masm, 1 * kPointerSize, rdx, rbx, rcx, rdi, | 3818 GenerateConvertArgument(masm, 1 * kPointerSize, rdx, rbx, rcx, rdi, |
3820 &call_builtin); | 3819 &call_builtin); |
3821 builtin_id = Builtins::STRING_ADD_LEFT; | 3820 builtin_id = Builtins::STRING_ADD_LEFT; |
3822 } | 3821 } |
3823 } | 3822 } |
3824 | 3823 |
3825 // Both arguments are strings. | 3824 // Both arguments are strings. |
3826 // rax: first string | 3825 // rax: first string |
3827 // rdx: second string | 3826 // rdx: second string |
3828 // Check if either of the strings are empty. In that case return the other. | 3827 // Check if either of the strings are empty. In that case return the other. |
3829 NearLabel second_not_zero_length, both_not_zero_length; | 3828 Label second_not_zero_length, both_not_zero_length; |
3830 __ movq(rcx, FieldOperand(rdx, String::kLengthOffset)); | 3829 __ movq(rcx, FieldOperand(rdx, String::kLengthOffset)); |
3831 __ SmiTest(rcx); | 3830 __ SmiTest(rcx); |
3832 __ j(not_zero, &second_not_zero_length); | 3831 __ j(not_zero, &second_not_zero_length, Label::kNear); |
3833 // Second string is empty, result is first string which is already in rax. | 3832 // Second string is empty, result is first string which is already in rax. |
3834 Counters* counters = masm->isolate()->counters(); | 3833 Counters* counters = masm->isolate()->counters(); |
3835 __ IncrementCounter(counters->string_add_native(), 1); | 3834 __ IncrementCounter(counters->string_add_native(), 1); |
3836 __ ret(2 * kPointerSize); | 3835 __ ret(2 * kPointerSize); |
3837 __ bind(&second_not_zero_length); | 3836 __ bind(&second_not_zero_length); |
3838 __ movq(rbx, FieldOperand(rax, String::kLengthOffset)); | 3837 __ movq(rbx, FieldOperand(rax, String::kLengthOffset)); |
3839 __ SmiTest(rbx); | 3838 __ SmiTest(rbx); |
3840 __ j(not_zero, &both_not_zero_length); | 3839 __ j(not_zero, &both_not_zero_length, Label::kNear); |
3841 // First string is empty, result is second string which is in rdx. | 3840 // First string is empty, result is second string which is in rdx. |
3842 __ movq(rax, rdx); | 3841 __ movq(rax, rdx); |
3843 __ IncrementCounter(counters->string_add_native(), 1); | 3842 __ IncrementCounter(counters->string_add_native(), 1); |
3844 __ ret(2 * kPointerSize); | 3843 __ ret(2 * kPointerSize); |
3845 | 3844 |
3846 // Both strings are non-empty. | 3845 // Both strings are non-empty. |
3847 // rax: first string | 3846 // rax: first string |
3848 // rbx: length of first string | 3847 // rbx: length of first string |
3849 // rcx: length of second string | 3848 // rcx: length of second string |
3850 // rdx: second string | 3849 // rdx: second string |
(...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4124 bool ascii) { | 4123 bool ascii) { |
4125 // Copy characters using rep movs of doublewords. Align destination on 4 byte | 4124 // Copy characters using rep movs of doublewords. Align destination on 4 byte |
4126 // boundary before starting rep movs. Copy remaining characters after running | 4125 // boundary before starting rep movs. Copy remaining characters after running |
4127 // rep movs. | 4126 // rep movs. |
4128 // Count is positive int32, dest and src are character pointers. | 4127 // Count is positive int32, dest and src are character pointers. |
4129 ASSERT(dest.is(rdi)); // rep movs destination | 4128 ASSERT(dest.is(rdi)); // rep movs destination |
4130 ASSERT(src.is(rsi)); // rep movs source | 4129 ASSERT(src.is(rsi)); // rep movs source |
4131 ASSERT(count.is(rcx)); // rep movs count | 4130 ASSERT(count.is(rcx)); // rep movs count |
4132 | 4131 |
4133 // Nothing to do for zero characters. | 4132 // Nothing to do for zero characters. |
4134 NearLabel done; | 4133 Label done; |
4135 __ testl(count, count); | 4134 __ testl(count, count); |
4136 __ j(zero, &done); | 4135 __ j(zero, &done, Label::kNear); |
4137 | 4136 |
4138 // Make count the number of bytes to copy. | 4137 // Make count the number of bytes to copy. |
4139 if (!ascii) { | 4138 if (!ascii) { |
4140 STATIC_ASSERT(2 == sizeof(uc16)); | 4139 STATIC_ASSERT(2 == sizeof(uc16)); |
4141 __ addl(count, count); | 4140 __ addl(count, count); |
4142 } | 4141 } |
4143 | 4142 |
4144 // Don't enter the rep movs if there are less than 4 bytes to copy. | 4143 // Don't enter the rep movs if there are less than 4 bytes to copy. |
4145 NearLabel last_bytes; | 4144 Label last_bytes; |
4146 __ testl(count, Immediate(~7)); | 4145 __ testl(count, Immediate(~7)); |
4147 __ j(zero, &last_bytes); | 4146 __ j(zero, &last_bytes, Label::kNear); |
4148 | 4147 |
4149 // Copy from edi to esi using rep movs instruction. | 4148 // Copy from edi to esi using rep movs instruction. |
4150 __ movl(kScratchRegister, count); | 4149 __ movl(kScratchRegister, count); |
4151 __ shr(count, Immediate(3)); // Number of doublewords to copy. | 4150 __ shr(count, Immediate(3)); // Number of doublewords to copy. |
4152 __ repmovsq(); | 4151 __ repmovsq(); |
4153 | 4152 |
4154 // Find number of bytes left. | 4153 // Find number of bytes left. |
4155 __ movl(count, kScratchRegister); | 4154 __ movl(count, kScratchRegister); |
4156 __ and_(count, Immediate(7)); | 4155 __ and_(count, Immediate(7)); |
4157 | 4156 |
4158 // Check if there are more bytes to copy. | 4157 // Check if there are more bytes to copy. |
4159 __ bind(&last_bytes); | 4158 __ bind(&last_bytes); |
4160 __ testl(count, count); | 4159 __ testl(count, count); |
4161 __ j(zero, &done); | 4160 __ j(zero, &done, Label::kNear); |
4162 | 4161 |
4163 // Copy remaining characters. | 4162 // Copy remaining characters. |
4164 Label loop; | 4163 Label loop; |
4165 __ bind(&loop); | 4164 __ bind(&loop); |
4166 __ movb(kScratchRegister, Operand(src, 0)); | 4165 __ movb(kScratchRegister, Operand(src, 0)); |
4167 __ movb(Operand(dest, 0), kScratchRegister); | 4166 __ movb(Operand(dest, 0), kScratchRegister); |
4168 __ incq(src); | 4167 __ incq(src); |
4169 __ incq(dest); | 4168 __ incq(dest); |
4170 __ decl(count); | 4169 __ decl(count); |
4171 __ j(not_zero, &loop); | 4170 __ j(not_zero, &loop); |
4172 | 4171 |
4173 __ bind(&done); | 4172 __ bind(&done); |
4174 } | 4173 } |
4175 | 4174 |
4176 void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, | 4175 void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, |
4177 Register c1, | 4176 Register c1, |
4178 Register c2, | 4177 Register c2, |
4179 Register scratch1, | 4178 Register scratch1, |
4180 Register scratch2, | 4179 Register scratch2, |
4181 Register scratch3, | 4180 Register scratch3, |
4182 Register scratch4, | 4181 Register scratch4, |
4183 Label* not_found) { | 4182 Label* not_found) { |
4184 // Register scratch3 is the general scratch register in this function. | 4183 // Register scratch3 is the general scratch register in this function. |
4185 Register scratch = scratch3; | 4184 Register scratch = scratch3; |
4186 | 4185 |
4187 // Make sure that both characters are not digits as such strings has a | 4186 // Make sure that both characters are not digits as such strings has a |
4188 // different hash algorithm. Don't try to look for these in the symbol table. | 4187 // different hash algorithm. Don't try to look for these in the symbol table. |
4189 NearLabel not_array_index; | 4188 Label not_array_index; |
4190 __ leal(scratch, Operand(c1, -'0')); | 4189 __ leal(scratch, Operand(c1, -'0')); |
4191 __ cmpl(scratch, Immediate(static_cast<int>('9' - '0'))); | 4190 __ cmpl(scratch, Immediate(static_cast<int>('9' - '0'))); |
4192 __ j(above, ¬_array_index); | 4191 __ j(above, ¬_array_index, Label::kNear); |
4193 __ leal(scratch, Operand(c2, -'0')); | 4192 __ leal(scratch, Operand(c2, -'0')); |
4194 __ cmpl(scratch, Immediate(static_cast<int>('9' - '0'))); | 4193 __ cmpl(scratch, Immediate(static_cast<int>('9' - '0'))); |
4195 __ j(below_equal, not_found); | 4194 __ j(below_equal, not_found); |
4196 | 4195 |
4197 __ bind(¬_array_index); | 4196 __ bind(¬_array_index); |
4198 // Calculate the two character string hash. | 4197 // Calculate the two character string hash. |
4199 Register hash = scratch1; | 4198 Register hash = scratch1; |
4200 GenerateHashInit(masm, hash, c1, scratch); | 4199 GenerateHashInit(masm, hash, c1, scratch); |
4201 GenerateHashAddCharacter(masm, hash, c2, scratch); | 4200 GenerateHashAddCharacter(masm, hash, c2, scratch); |
4202 GenerateHashGetHash(masm, hash, scratch); | 4201 GenerateHashGetHash(masm, hash, scratch); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4244 // Load the entry from the symbol table. | 4243 // Load the entry from the symbol table. |
4245 Register candidate = scratch; // Scratch register contains candidate. | 4244 Register candidate = scratch; // Scratch register contains candidate. |
4246 STATIC_ASSERT(SymbolTable::kEntrySize == 1); | 4245 STATIC_ASSERT(SymbolTable::kEntrySize == 1); |
4247 __ movq(candidate, | 4246 __ movq(candidate, |
4248 FieldOperand(symbol_table, | 4247 FieldOperand(symbol_table, |
4249 scratch, | 4248 scratch, |
4250 times_pointer_size, | 4249 times_pointer_size, |
4251 SymbolTable::kElementsStartOffset)); | 4250 SymbolTable::kElementsStartOffset)); |
4252 | 4251 |
4253 // If entry is undefined no string with this hash can be found. | 4252 // If entry is undefined no string with this hash can be found. |
4254 NearLabel is_string; | 4253 Label is_string; |
4255 __ CmpObjectType(candidate, ODDBALL_TYPE, map); | 4254 __ CmpObjectType(candidate, ODDBALL_TYPE, map); |
4256 __ j(not_equal, &is_string); | 4255 __ j(not_equal, &is_string, Label::kNear); |
4257 | 4256 |
4258 __ CompareRoot(candidate, Heap::kUndefinedValueRootIndex); | 4257 __ CompareRoot(candidate, Heap::kUndefinedValueRootIndex); |
4259 __ j(equal, not_found); | 4258 __ j(equal, not_found); |
4260 // Must be null (deleted entry). | 4259 // Must be null (deleted entry). |
4261 __ jmp(&next_probe[i]); | 4260 __ jmp(&next_probe[i]); |
4262 | 4261 |
4263 __ bind(&is_string); | 4262 __ bind(&is_string); |
4264 | 4263 |
4265 // If length is not 2 the string is not a candidate. | 4264 // If length is not 2 the string is not a candidate. |
4266 __ SmiCompare(FieldOperand(candidate, String::kLengthOffset), | 4265 __ SmiCompare(FieldOperand(candidate, String::kLengthOffset), |
(...skipping 300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4567 STATIC_ASSERT(String::kMaxLength < 0x7fffffff); | 4566 STATIC_ASSERT(String::kMaxLength < 0x7fffffff); |
4568 | 4567 |
4569 // Find minimum length and length difference. | 4568 // Find minimum length and length difference. |
4570 __ movq(scratch1, FieldOperand(left, String::kLengthOffset)); | 4569 __ movq(scratch1, FieldOperand(left, String::kLengthOffset)); |
4571 __ movq(scratch4, scratch1); | 4570 __ movq(scratch4, scratch1); |
4572 __ SmiSub(scratch4, | 4571 __ SmiSub(scratch4, |
4573 scratch4, | 4572 scratch4, |
4574 FieldOperand(right, String::kLengthOffset)); | 4573 FieldOperand(right, String::kLengthOffset)); |
4575 // Register scratch4 now holds left.length - right.length. | 4574 // Register scratch4 now holds left.length - right.length. |
4576 const Register length_difference = scratch4; | 4575 const Register length_difference = scratch4; |
4577 NearLabel left_shorter; | 4576 Label left_shorter; |
4578 __ j(less, &left_shorter); | 4577 __ j(less, &left_shorter, Label::kNear); |
4579 // The right string isn't longer that the left one. | 4578 // The right string isn't longer that the left one. |
4580 // Get the right string's length by subtracting the (non-negative) difference | 4579 // Get the right string's length by subtracting the (non-negative) difference |
4581 // from the left string's length. | 4580 // from the left string's length. |
4582 __ SmiSub(scratch1, scratch1, length_difference); | 4581 __ SmiSub(scratch1, scratch1, length_difference); |
4583 __ bind(&left_shorter); | 4582 __ bind(&left_shorter); |
4584 // Register scratch1 now holds Min(left.length, right.length). | 4583 // Register scratch1 now holds Min(left.length, right.length). |
4585 const Register min_length = scratch1; | 4584 const Register min_length = scratch1; |
4586 | 4585 |
4587 NearLabel compare_lengths; | 4586 Label compare_lengths; |
4588 // If min-length is zero, go directly to comparing lengths. | 4587 // If min-length is zero, go directly to comparing lengths. |
4589 __ SmiTest(min_length); | 4588 __ SmiTest(min_length); |
4590 __ j(zero, &compare_lengths); | 4589 __ j(zero, &compare_lengths, Label::kNear); |
4591 | 4590 |
4592 __ SmiToInteger32(min_length, min_length); | 4591 __ SmiToInteger32(min_length, min_length); |
4593 | 4592 |
4594 // Registers scratch2 and scratch3 are free. | 4593 // Registers scratch2 and scratch3 are free. |
4595 NearLabel result_not_equal; | 4594 Label result_not_equal; |
4596 Label loop; | 4595 Label loop; |
4597 { | 4596 { |
4598 // Check characters 0 .. min_length - 1 in a loop. | 4597 // Check characters 0 .. min_length - 1 in a loop. |
4599 // Use scratch3 as loop index, min_length as limit and scratch2 | 4598 // Use scratch3 as loop index, min_length as limit and scratch2 |
4600 // for computation. | 4599 // for computation. |
4601 const Register index = scratch3; | 4600 const Register index = scratch3; |
4602 __ Set(index, 0); // Index into strings. | 4601 __ Set(index, 0); // Index into strings. |
4603 __ bind(&loop); | 4602 __ bind(&loop); |
4604 // Compare characters. | 4603 // Compare characters. |
4605 // TODO(lrn): Could we load more than one character at a time? | 4604 // TODO(lrn): Could we load more than one character at a time? |
4606 __ movb(scratch2, FieldOperand(left, | 4605 __ movb(scratch2, FieldOperand(left, |
4607 index, | 4606 index, |
4608 times_1, | 4607 times_1, |
4609 SeqAsciiString::kHeaderSize)); | 4608 SeqAsciiString::kHeaderSize)); |
4610 // Increment index and use -1 modifier on next load to give | 4609 // Increment index and use -1 modifier on next load to give |
4611 // the previous load extra time to complete. | 4610 // the previous load extra time to complete. |
4612 __ addl(index, Immediate(1)); | 4611 __ addl(index, Immediate(1)); |
4613 __ cmpb(scratch2, FieldOperand(right, | 4612 __ cmpb(scratch2, FieldOperand(right, |
4614 index, | 4613 index, |
4615 times_1, | 4614 times_1, |
4616 SeqAsciiString::kHeaderSize - 1)); | 4615 SeqAsciiString::kHeaderSize - 1)); |
4617 __ j(not_equal, &result_not_equal); | 4616 __ j(not_equal, &result_not_equal, Label::kNear); |
4618 __ cmpl(index, min_length); | 4617 __ cmpl(index, min_length); |
4619 __ j(not_equal, &loop); | 4618 __ j(not_equal, &loop); |
4620 } | 4619 } |
4621 // Completed loop without finding different characters. | 4620 // Completed loop without finding different characters. |
4622 // Compare lengths (precomputed). | 4621 // Compare lengths (precomputed). |
4623 __ bind(&compare_lengths); | 4622 __ bind(&compare_lengths); |
4624 __ SmiTest(length_difference); | 4623 __ SmiTest(length_difference); |
4625 __ j(not_zero, &result_not_equal); | 4624 __ j(not_zero, &result_not_equal, Label::kNear); |
4626 | 4625 |
4627 // Result is EQUAL. | 4626 // Result is EQUAL. |
4628 __ Move(rax, Smi::FromInt(EQUAL)); | 4627 __ Move(rax, Smi::FromInt(EQUAL)); |
4629 __ ret(0); | 4628 __ ret(0); |
4630 | 4629 |
4631 NearLabel result_greater; | 4630 Label result_greater; |
4632 __ bind(&result_not_equal); | 4631 __ bind(&result_not_equal); |
4633 // Unequal comparison of left to right, either character or length. | 4632 // Unequal comparison of left to right, either character or length. |
4634 __ j(greater, &result_greater); | 4633 __ j(greater, &result_greater, Label::kNear); |
4635 | 4634 |
4636 // Result is LESS. | 4635 // Result is LESS. |
4637 __ Move(rax, Smi::FromInt(LESS)); | 4636 __ Move(rax, Smi::FromInt(LESS)); |
4638 __ ret(0); | 4637 __ ret(0); |
4639 | 4638 |
4640 // Result is GREATER. | 4639 // Result is GREATER. |
4641 __ bind(&result_greater); | 4640 __ bind(&result_greater); |
4642 __ Move(rax, Smi::FromInt(GREATER)); | 4641 __ Move(rax, Smi::FromInt(GREATER)); |
4643 __ ret(0); | 4642 __ ret(0); |
4644 } | 4643 } |
4645 | 4644 |
4646 | 4645 |
4647 void StringCompareStub::Generate(MacroAssembler* masm) { | 4646 void StringCompareStub::Generate(MacroAssembler* masm) { |
4648 Label runtime; | 4647 Label runtime; |
4649 | 4648 |
4650 // Stack frame on entry. | 4649 // Stack frame on entry. |
4651 // rsp[0]: return address | 4650 // rsp[0]: return address |
4652 // rsp[8]: right string | 4651 // rsp[8]: right string |
4653 // rsp[16]: left string | 4652 // rsp[16]: left string |
4654 | 4653 |
4655 __ movq(rdx, Operand(rsp, 2 * kPointerSize)); // left | 4654 __ movq(rdx, Operand(rsp, 2 * kPointerSize)); // left |
4656 __ movq(rax, Operand(rsp, 1 * kPointerSize)); // right | 4655 __ movq(rax, Operand(rsp, 1 * kPointerSize)); // right |
4657 | 4656 |
4658 // Check for identity. | 4657 // Check for identity. |
4659 NearLabel not_same; | 4658 Label not_same; |
4660 __ cmpq(rdx, rax); | 4659 __ cmpq(rdx, rax); |
4661 __ j(not_equal, ¬_same); | 4660 __ j(not_equal, ¬_same, Label::kNear); |
4662 __ Move(rax, Smi::FromInt(EQUAL)); | 4661 __ Move(rax, Smi::FromInt(EQUAL)); |
4663 Counters* counters = masm->isolate()->counters(); | 4662 Counters* counters = masm->isolate()->counters(); |
4664 __ IncrementCounter(counters->string_compare_native(), 1); | 4663 __ IncrementCounter(counters->string_compare_native(), 1); |
4665 __ ret(2 * kPointerSize); | 4664 __ ret(2 * kPointerSize); |
4666 | 4665 |
4667 __ bind(¬_same); | 4666 __ bind(¬_same); |
4668 | 4667 |
4669 // Check that both are sequential ASCII strings. | 4668 // Check that both are sequential ASCII strings. |
4670 __ JumpIfNotBothSequentialAsciiStrings(rdx, rax, rcx, rbx, &runtime); | 4669 __ JumpIfNotBothSequentialAsciiStrings(rdx, rax, rcx, rbx, &runtime); |
4671 | 4670 |
(...skipping 14 matching lines...) Expand all Loading... |
4686 | 4685 |
4687 void ICCompareStub::GenerateSmis(MacroAssembler* masm) { | 4686 void ICCompareStub::GenerateSmis(MacroAssembler* masm) { |
4688 ASSERT(state_ == CompareIC::SMIS); | 4687 ASSERT(state_ == CompareIC::SMIS); |
4689 NearLabel miss; | 4688 NearLabel miss; |
4690 __ JumpIfNotBothSmi(rdx, rax, &miss); | 4689 __ JumpIfNotBothSmi(rdx, rax, &miss); |
4691 | 4690 |
4692 if (GetCondition() == equal) { | 4691 if (GetCondition() == equal) { |
4693 // For equality we do not care about the sign of the result. | 4692 // For equality we do not care about the sign of the result. |
4694 __ subq(rax, rdx); | 4693 __ subq(rax, rdx); |
4695 } else { | 4694 } else { |
4696 NearLabel done; | 4695 Label done; |
4697 __ subq(rdx, rax); | 4696 __ subq(rdx, rax); |
4698 __ j(no_overflow, &done); | 4697 __ j(no_overflow, &done, Label::kNear); |
4699 // Correct sign of result in case of overflow. | 4698 // Correct sign of result in case of overflow. |
4700 __ SmiNot(rdx, rdx); | 4699 __ SmiNot(rdx, rdx); |
4701 __ bind(&done); | 4700 __ bind(&done); |
4702 __ movq(rax, rdx); | 4701 __ movq(rax, rdx); |
4703 } | 4702 } |
4704 __ ret(0); | 4703 __ ret(0); |
4705 | 4704 |
4706 __ bind(&miss); | 4705 __ bind(&miss); |
4707 GenerateMiss(masm); | 4706 GenerateMiss(masm); |
4708 } | 4707 } |
4709 | 4708 |
4710 | 4709 |
4711 void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { | 4710 void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { |
4712 ASSERT(state_ == CompareIC::HEAP_NUMBERS); | 4711 ASSERT(state_ == CompareIC::HEAP_NUMBERS); |
4713 | 4712 |
4714 NearLabel generic_stub; | 4713 Label generic_stub; |
4715 NearLabel unordered; | 4714 Label unordered; |
4716 NearLabel miss; | 4715 Label miss; |
4717 Condition either_smi = masm->CheckEitherSmi(rax, rdx); | 4716 Condition either_smi = masm->CheckEitherSmi(rax, rdx); |
4718 __ j(either_smi, &generic_stub); | 4717 __ j(either_smi, &generic_stub, Label::kNear); |
4719 | 4718 |
4720 __ CmpObjectType(rax, HEAP_NUMBER_TYPE, rcx); | 4719 __ CmpObjectType(rax, HEAP_NUMBER_TYPE, rcx); |
4721 __ j(not_equal, &miss); | 4720 __ j(not_equal, &miss, Label::kNear); |
4722 __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rcx); | 4721 __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rcx); |
4723 __ j(not_equal, &miss); | 4722 __ j(not_equal, &miss, Label::kNear); |
4724 | 4723 |
4725 // Load left and right operand | 4724 // Load left and right operand |
4726 __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset)); | 4725 __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset)); |
4727 __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset)); | 4726 __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset)); |
4728 | 4727 |
4729 // Compare operands | 4728 // Compare operands |
4730 __ ucomisd(xmm0, xmm1); | 4729 __ ucomisd(xmm0, xmm1); |
4731 | 4730 |
4732 // Don't base result on EFLAGS when a NaN is involved. | 4731 // Don't base result on EFLAGS when a NaN is involved. |
4733 __ j(parity_even, &unordered); | 4732 __ j(parity_even, &unordered, Label::kNear); |
4734 | 4733 |
4735 // Return a result of -1, 0, or 1, based on EFLAGS. | 4734 // Return a result of -1, 0, or 1, based on EFLAGS. |
4736 // Performing mov, because xor would destroy the flag register. | 4735 // Performing mov, because xor would destroy the flag register. |
4737 __ movl(rax, Immediate(0)); | 4736 __ movl(rax, Immediate(0)); |
4738 __ movl(rcx, Immediate(0)); | 4737 __ movl(rcx, Immediate(0)); |
4739 __ setcc(above, rax); // Add one to zero if carry clear and not equal. | 4738 __ setcc(above, rax); // Add one to zero if carry clear and not equal. |
4740 __ sbbq(rax, rcx); // Subtract one if below (aka. carry set). | 4739 __ sbbq(rax, rcx); // Subtract one if below (aka. carry set). |
4741 __ ret(0); | 4740 __ ret(0); |
4742 | 4741 |
4743 __ bind(&unordered); | 4742 __ bind(&unordered); |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4820 __ push(tmp1); | 4819 __ push(tmp1); |
4821 __ TailCallRuntime(Runtime::kStringEquals, 2, 1); | 4820 __ TailCallRuntime(Runtime::kStringEquals, 2, 1); |
4822 | 4821 |
4823 __ bind(&miss); | 4822 __ bind(&miss); |
4824 GenerateMiss(masm); | 4823 GenerateMiss(masm); |
4825 } | 4824 } |
4826 | 4825 |
4827 | 4826 |
4828 void ICCompareStub::GenerateObjects(MacroAssembler* masm) { | 4827 void ICCompareStub::GenerateObjects(MacroAssembler* masm) { |
4829 ASSERT(state_ == CompareIC::OBJECTS); | 4828 ASSERT(state_ == CompareIC::OBJECTS); |
4830 NearLabel miss; | 4829 Label miss; |
4831 Condition either_smi = masm->CheckEitherSmi(rdx, rax); | 4830 Condition either_smi = masm->CheckEitherSmi(rdx, rax); |
4832 __ j(either_smi, &miss); | 4831 __ j(either_smi, &miss, Label::kNear); |
4833 | 4832 |
4834 __ CmpObjectType(rax, JS_OBJECT_TYPE, rcx); | 4833 __ CmpObjectType(rax, JS_OBJECT_TYPE, rcx); |
4835 __ j(not_equal, &miss, not_taken); | 4834 __ j(not_equal, &miss, not_taken, Label::kNear); |
4836 __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx); | 4835 __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx); |
4837 __ j(not_equal, &miss, not_taken); | 4836 __ j(not_equal, &miss, not_taken, Label::kNear); |
4838 | 4837 |
4839 ASSERT(GetCondition() == equal); | 4838 ASSERT(GetCondition() == equal); |
4840 __ subq(rax, rdx); | 4839 __ subq(rax, rdx); |
4841 __ ret(0); | 4840 __ ret(0); |
4842 | 4841 |
4843 __ bind(&miss); | 4842 __ bind(&miss); |
4844 GenerateMiss(masm); | 4843 GenerateMiss(masm); |
4845 } | 4844 } |
4846 | 4845 |
4847 | 4846 |
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5071 __ Drop(1); | 5070 __ Drop(1); |
5072 __ ret(2 * kPointerSize); | 5071 __ ret(2 * kPointerSize); |
5073 } | 5072 } |
5074 | 5073 |
5075 | 5074 |
5076 #undef __ | 5075 #undef __ |
5077 | 5076 |
5078 } } // namespace v8::internal | 5077 } } // namespace v8::internal |
5079 | 5078 |
5080 #endif // V8_TARGET_ARCH_X64 | 5079 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |