OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 1984 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1995 if (right_side.is_constant()) { | 1995 if (right_side.is_constant()) { |
1996 right_side_constant_smi = right_side.handle()->IsSmi(); | 1996 right_side_constant_smi = right_side.handle()->IsSmi(); |
1997 right_side_constant_null = right_side.handle()->IsNull(); | 1997 right_side_constant_null = right_side.handle()->IsNull(); |
1998 right_side_constant_1_char_string = | 1998 right_side_constant_1_char_string = |
1999 (right_side.handle()->IsString() && | 1999 (right_side.handle()->IsString() && |
2000 String::cast(*right_side.handle())->length() == 1 && | 2000 String::cast(*right_side.handle())->length() == 1 && |
2001 String::cast(*right_side.handle())->IsAsciiRepresentation()); | 2001 String::cast(*right_side.handle())->IsAsciiRepresentation()); |
2002 } | 2002 } |
2003 | 2003 |
2004 if (left_side_constant_smi || right_side_constant_smi) { | 2004 if (left_side_constant_smi || right_side_constant_smi) { |
2005 if (left_side_constant_smi && right_side_constant_smi) { | 2005 bool is_loop_condition = (node->AsExpression() != NULL) && |
2006 // Trivial case, comparing two constants. | 2006 node->AsExpression()->is_loop_condition(); |
2007 int left_value = Smi::cast(*left_side.handle())->value(); | 2007 ConstantSmiComparison(cc, strict, dest, &left_side, &right_side, |
2008 int right_value = Smi::cast(*right_side.handle())->value(); | 2008 left_side_constant_smi, right_side_constant_smi, |
2009 switch (cc) { | 2009 is_loop_condition); |
2010 case less: | |
2011 dest->Goto(left_value < right_value); | |
2012 break; | |
2013 case equal: | |
2014 dest->Goto(left_value == right_value); | |
2015 break; | |
2016 case greater_equal: | |
2017 dest->Goto(left_value >= right_value); | |
2018 break; | |
2019 default: | |
2020 UNREACHABLE(); | |
2021 } | |
2022 } else { | |
2023 // Only one side is a constant Smi. | |
2024 // If left side is a constant Smi, reverse the operands. | |
2025 // Since one side is a constant Smi, conversion order does not matter. | |
2026 if (left_side_constant_smi) { | |
2027 Result temp = left_side; | |
2028 left_side = right_side; | |
2029 right_side = temp; | |
2030 cc = ReverseCondition(cc); | |
2031 // This may re-introduce greater or less_equal as the value of cc. | |
2032 // CompareStub and the inline code both support all values of cc. | |
2033 } | |
2034 // Implement comparison against a constant Smi, inlining the case | |
2035 // where both sides are Smis. | |
2036 left_side.ToRegister(); | |
2037 Register left_reg = left_side.reg(); | |
2038 Handle<Object> right_val = right_side.handle(); | |
2039 | |
2040 // Here we split control flow to the stub call and inlined cases | |
2041 // before finally splitting it to the control destination. We use | |
2042 // a jump target and branching to duplicate the virtual frame at | |
2043 // the first split. We manually handle the off-frame references | |
2044 // by reconstituting them on the non-fall-through path. | |
2045 JumpTarget is_smi; | |
2046 | |
2047 if (left_side.is_smi()) { | |
2048 if (FLAG_debug_code) { | |
2049 __ AbortIfNotSmi(left_side.reg()); | |
2050 } | |
2051 } else { | |
2052 Condition left_is_smi = masm_->CheckSmi(left_side.reg()); | |
2053 is_smi.Branch(left_is_smi); | |
2054 | |
2055 bool is_loop_condition = (node->AsExpression() != NULL) && | |
2056 node->AsExpression()->is_loop_condition(); | |
2057 if (!is_loop_condition && right_val->IsSmi()) { | |
2058 // Right side is a constant smi and left side has been checked | |
2059 // not to be a smi. | |
2060 JumpTarget not_number; | |
2061 __ Cmp(FieldOperand(left_reg, HeapObject::kMapOffset), | |
2062 Factory::heap_number_map()); | |
2063 not_number.Branch(not_equal, &left_side); | |
2064 __ movsd(xmm1, | |
2065 FieldOperand(left_reg, HeapNumber::kValueOffset)); | |
2066 int value = Smi::cast(*right_val)->value(); | |
2067 if (value == 0) { | |
2068 __ xorpd(xmm0, xmm0); | |
2069 } else { | |
2070 Result temp = allocator()->Allocate(); | |
2071 __ movl(temp.reg(), Immediate(value)); | |
2072 __ cvtlsi2sd(xmm0, temp.reg()); | |
2073 temp.Unuse(); | |
2074 } | |
2075 __ ucomisd(xmm1, xmm0); | |
2076 // Jump to builtin for NaN. | |
2077 not_number.Branch(parity_even, &left_side); | |
2078 left_side.Unuse(); | |
2079 dest->true_target()->Branch(DoubleCondition(cc)); | |
2080 dest->false_target()->Jump(); | |
2081 not_number.Bind(&left_side); | |
2082 } | |
2083 | |
2084 // Setup and call the compare stub. | |
2085 CompareStub stub(cc, strict, kCantBothBeNaN); | |
2086 Result result = frame_->CallStub(&stub, &left_side, &right_side); | |
2087 result.ToRegister(); | |
2088 __ testq(result.reg(), result.reg()); | |
2089 result.Unuse(); | |
2090 dest->true_target()->Branch(cc); | |
2091 dest->false_target()->Jump(); | |
2092 | |
2093 is_smi.Bind(); | |
2094 } | |
2095 | |
2096 left_side = Result(left_reg); | |
2097 right_side = Result(right_val); | |
2098 // Test smi equality and comparison by signed int comparison. | |
2099 // Both sides are smis, so we can use an Immediate. | |
2100 __ SmiCompare(left_side.reg(), Smi::cast(*right_side.handle())); | |
2101 left_side.Unuse(); | |
2102 right_side.Unuse(); | |
2103 dest->Split(cc); | |
2104 } | |
2105 } else if (cc == equal && | 2010 } else if (cc == equal && |
2106 (left_side_constant_null || right_side_constant_null)) { | 2011 (left_side_constant_null || right_side_constant_null)) { |
2107 // To make null checks efficient, we check if either the left side or | 2012 // To make null checks efficient, we check if either the left side or |
2108 // the right side is the constant 'null'. | 2013 // the right side is the constant 'null'. |
2109 // If so, we optimize the code by inlining a null check instead of | 2014 // If so, we optimize the code by inlining a null check instead of |
2110 // calling the (very) general runtime routine for checking equality. | 2015 // calling the (very) general runtime routine for checking equality. |
2111 Result operand = left_side_constant_null ? right_side : left_side; | 2016 Result operand = left_side_constant_null ? right_side : left_side; |
2112 right_side.Unuse(); | 2017 right_side.Unuse(); |
2113 left_side.Unuse(); | 2018 left_side.Unuse(); |
2114 operand.ToRegister(); | 2019 operand.ToRegister(); |
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2359 right_side = Result(right_reg); | 2264 right_side = Result(right_reg); |
2360 __ SmiCompare(left_side.reg(), right_side.reg()); | 2265 __ SmiCompare(left_side.reg(), right_side.reg()); |
2361 right_side.Unuse(); | 2266 right_side.Unuse(); |
2362 left_side.Unuse(); | 2267 left_side.Unuse(); |
2363 dest->Split(cc); | 2268 dest->Split(cc); |
2364 } | 2269 } |
2365 } | 2270 } |
2366 } | 2271 } |
2367 | 2272 |
2368 | 2273 |
| 2274 void CodeGenerator::ConstantSmiComparison(Condition cc, |
| 2275 bool strict, |
| 2276 ControlDestination* dest, |
| 2277 Result* left_side, |
| 2278 Result* right_side, |
| 2279 bool left_side_constant_smi, |
| 2280 bool right_side_constant_smi, |
| 2281 bool is_loop_condition) { |
| 2282 if (left_side_constant_smi && right_side_constant_smi) { |
| 2283 // Trivial case, comparing two constants. |
| 2284 int left_value = Smi::cast(*left_side->handle())->value(); |
| 2285 int right_value = Smi::cast(*right_side->handle())->value(); |
| 2286 switch (cc) { |
| 2287 case less: |
| 2288 dest->Goto(left_value < right_value); |
| 2289 break; |
| 2290 case equal: |
| 2291 dest->Goto(left_value == right_value); |
| 2292 break; |
| 2293 case greater_equal: |
| 2294 dest->Goto(left_value >= right_value); |
| 2295 break; |
| 2296 default: |
| 2297 UNREACHABLE(); |
| 2298 } |
| 2299 } else { |
| 2300 // Only one side is a constant Smi. |
| 2301 // If left side is a constant Smi, reverse the operands. |
| 2302 // Since one side is a constant Smi, conversion order does not matter. |
| 2303 if (left_side_constant_smi) { |
| 2304 Result* temp = left_side; |
| 2305 left_side = right_side; |
| 2306 right_side = temp; |
| 2307 cc = ReverseCondition(cc); |
| 2308 // This may re-introduce greater or less_equal as the value of cc. |
| 2309 // CompareStub and the inline code both support all values of cc. |
| 2310 } |
| 2311 // Implement comparison against a constant Smi, inlining the case |
| 2312 // where both sides are Smis. |
| 2313 left_side->ToRegister(); |
| 2314 Register left_reg = left_side->reg(); |
| 2315 Smi* constant_smi = Smi::cast(*right_side->handle()); |
| 2316 |
| 2317 if (left_side->is_smi()) { |
| 2318 if (FLAG_debug_code) { |
| 2319 __ AbortIfNotSmi(left_reg); |
| 2320 } |
| 2321 // Test smi equality and comparison by signed int comparison. |
| 2322 // Both sides are smis, so we can use an Immediate. |
| 2323 __ SmiCompare(left_reg, constant_smi); |
| 2324 left_side->Unuse(); |
| 2325 right_side->Unuse(); |
| 2326 dest->Split(cc); |
| 2327 } else { |
| 2328 // Only the case where the left side could possibly be a non-smi is left. |
| 2329 JumpTarget is_smi; |
| 2330 if (cc == equal) { |
| 2331 // We can do the equality comparison before the smi check. |
| 2332 __ SmiCompare(left_reg, constant_smi); |
| 2333 dest->true_target()->Branch(equal); |
| 2334 Condition left_is_smi = masm_->CheckSmi(left_reg); |
| 2335 dest->false_target()->Branch(left_is_smi); |
| 2336 } else { |
| 2337 // Do the smi check, then the comparison. |
| 2338 Condition left_is_smi = masm_->CheckSmi(left_reg); |
| 2339 is_smi.Branch(left_is_smi, left_side, right_side); |
| 2340 } |
| 2341 |
| 2342 // Jump or fall through to here if we are comparing a non-smi to a |
| 2343 // constant smi. If the non-smi is a heap number and this is not |
| 2344 // a loop condition, inline the floating point code. |
| 2345 if (!is_loop_condition) { |
| 2346 // Right side is a constant smi and left side has been checked |
| 2347 // not to be a smi. |
| 2348 JumpTarget not_number; |
| 2349 __ Cmp(FieldOperand(left_reg, HeapObject::kMapOffset), |
| 2350 Factory::heap_number_map()); |
| 2351 not_number.Branch(not_equal, left_side); |
| 2352 __ movsd(xmm1, |
| 2353 FieldOperand(left_reg, HeapNumber::kValueOffset)); |
| 2354 int value = constant_smi->value(); |
| 2355 if (value == 0) { |
| 2356 __ xorpd(xmm0, xmm0); |
| 2357 } else { |
| 2358 Result temp = allocator()->Allocate(); |
| 2359 __ movl(temp.reg(), Immediate(value)); |
| 2360 __ cvtlsi2sd(xmm0, temp.reg()); |
| 2361 temp.Unuse(); |
| 2362 } |
| 2363 __ ucomisd(xmm1, xmm0); |
| 2364 // Jump to builtin for NaN. |
| 2365 not_number.Branch(parity_even, left_side); |
| 2366 left_side->Unuse(); |
| 2367 dest->true_target()->Branch(DoubleCondition(cc)); |
| 2368 dest->false_target()->Jump(); |
| 2369 not_number.Bind(left_side); |
| 2370 } |
| 2371 |
| 2372 // Setup and call the compare stub. |
| 2373 CompareStub stub(cc, strict, kCantBothBeNaN); |
| 2374 Result result = frame_->CallStub(&stub, left_side, right_side); |
| 2375 result.ToRegister(); |
| 2376 __ testq(result.reg(), result.reg()); |
| 2377 result.Unuse(); |
| 2378 if (cc == equal) { |
| 2379 dest->Split(cc); |
| 2380 } else { |
| 2381 dest->true_target()->Branch(cc); |
| 2382 dest->false_target()->Jump(); |
| 2383 |
| 2384 // It is important for performance for this case to be at the end. |
| 2385 is_smi.Bind(left_side, right_side); |
| 2386 __ SmiCompare(left_reg, constant_smi); |
| 2387 left_side->Unuse(); |
| 2388 right_side->Unuse(); |
| 2389 dest->Split(cc); |
| 2390 } |
| 2391 } |
| 2392 } |
| 2393 } |
| 2394 |
| 2395 |
2369 // Load a comparison operand into into a XMM register. Jump to not_numbers jump | 2396 // Load a comparison operand into into a XMM register. Jump to not_numbers jump |
2370 // target passing the left and right result if the operand is not a number. | 2397 // target passing the left and right result if the operand is not a number. |
2371 static void LoadComparisonOperand(MacroAssembler* masm_, | 2398 static void LoadComparisonOperand(MacroAssembler* masm_, |
2372 Result* operand, | 2399 Result* operand, |
2373 XMMRegister xmm_reg, | 2400 XMMRegister xmm_reg, |
2374 Result* left_side, | 2401 Result* left_side, |
2375 Result* right_side, | 2402 Result* right_side, |
2376 JumpTarget* not_numbers) { | 2403 JumpTarget* not_numbers) { |
2377 Label done; | 2404 Label done; |
2378 if (operand->type_info().IsDouble()) { | 2405 if (operand->type_info().IsDouble()) { |
(...skipping 9678 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12057 #undef __ | 12084 #undef __ |
12058 | 12085 |
12059 void RecordWriteStub::Generate(MacroAssembler* masm) { | 12086 void RecordWriteStub::Generate(MacroAssembler* masm) { |
12060 masm->RecordWriteHelper(object_, addr_, scratch_); | 12087 masm->RecordWriteHelper(object_, addr_, scratch_); |
12061 masm->ret(0); | 12088 masm->ret(0); |
12062 } | 12089 } |
12063 | 12090 |
12064 } } // namespace v8::internal | 12091 } } // namespace v8::internal |
12065 | 12092 |
12066 #endif // V8_TARGET_ARCH_X64 | 12093 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |