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