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