| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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 1315 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1326 Result right_side(this); | 1326 Result right_side(this); |
| 1327 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. | 1327 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. |
| 1328 if (cc == greater || cc == less_equal) { | 1328 if (cc == greater || cc == less_equal) { |
| 1329 cc = ReverseCondition(cc); | 1329 cc = ReverseCondition(cc); |
| 1330 left_side = frame_->Pop(); | 1330 left_side = frame_->Pop(); |
| 1331 right_side = frame_->Pop(); | 1331 right_side = frame_->Pop(); |
| 1332 } else { | 1332 } else { |
| 1333 right_side = frame_->Pop(); | 1333 right_side = frame_->Pop(); |
| 1334 left_side = frame_->Pop(); | 1334 left_side = frame_->Pop(); |
| 1335 } | 1335 } |
| 1336 left_side.ToRegister(); | 1336 // If either side is a constant smi, optimize the comparison. |
| 1337 right_side.ToRegister(); | 1337 bool left_side_constant_smi = |
| 1338 ASSERT(left_side.is_valid()); | 1338 left_side.is_constant() && left_side.handle()->IsSmi(); |
| 1339 ASSERT(right_side.is_valid()); | 1339 bool right_side_constant_smi = |
| 1340 // Check for the smi case. | 1340 right_side.is_constant() && right_side.handle()->IsSmi(); |
| 1341 JumpTarget is_smi(this); | |
| 1342 Result temp = allocator_->Allocate(); | |
| 1343 ASSERT(temp.is_valid()); | |
| 1344 __ mov(temp.reg(), left_side.reg()); | |
| 1345 __ or_(temp.reg(), Operand(right_side.reg())); | |
| 1346 __ test(temp.reg(), Immediate(kSmiTagMask)); | |
| 1347 temp.Unuse(); | |
| 1348 is_smi.Branch(zero, &left_side, &right_side, taken); | |
| 1349 | 1341 |
| 1350 // When non-smi, call out to the compare stub. "parameters" setup by | 1342 if (left_side_constant_smi || right_side_constant_smi) { |
| 1351 // calling code in edx and eax and "result" is returned in the flags. | 1343 if (left_side_constant_smi && right_side_constant_smi) { |
| 1352 if (!left_side.reg().is(eax)) { | 1344 // Trivial case, comparing two constants. |
| 1353 right_side.ToRegister(eax); | 1345 int left_value = Smi::cast(*left_side.handle())->value(); |
| 1354 left_side.ToRegister(edx); | 1346 int right_value = Smi::cast(*right_side.handle())->value(); |
| 1355 } else if (!right_side.reg().is(edx)) { | 1347 if (left_value < right_value && |
| 1356 left_side.ToRegister(edx); | 1348 (cc == less || cc == less_equal || cc == not_equal) || |
| 1357 right_side.ToRegister(eax); | 1349 left_value == right_value && |
| 1358 } else { | 1350 (cc == less_equal || cc == equal || cc == greater_equal) || |
| 1359 frame_->Spill(eax); // Can be multiply referenced, even now. | 1351 left_value > right_value && |
| 1360 frame_->Spill(edx); | 1352 (cc == greater || cc == greater_equal || cc == not_equal)) { |
| 1361 __ xchg(eax, edx); | 1353 // Comparison is unconditionally true. |
| 1362 // If left_side and right_side become real (non-dummy) arguments | 1354 if (true_target->is_bound()) { |
| 1363 // to CallStub, they need to be swapped in this case. | 1355 true_target->Jump(); |
| 1356 } else { |
| 1357 true_target->Bind(); |
| 1358 } |
| 1359 } else { // Comparison is always false. |
| 1360 if (false_target->is_bound()) { |
| 1361 false_target->Jump(); |
| 1362 } else { |
| 1363 false_target->Bind(); |
| 1364 } |
| 1365 } |
| 1366 } else { // Only one side is a constant Smi. |
| 1367 // If left side is a constant Smi, reverse the operands. |
| 1368 // Since one side is a constant Smi, conversion order does not matter. |
| 1369 if (left_side_constant_smi) { |
| 1370 Result temp = left_side; |
| 1371 left_side = right_side; |
| 1372 right_side = temp; |
| 1373 cc = ReverseCondition(cc); |
| 1374 } |
| 1375 // Implement comparison against a constant Smi, inlining the case |
| 1376 // where both sides are Smis. |
| 1377 left_side.ToRegister(); |
| 1378 ASSERT(left_side.is_valid()); |
| 1379 JumpTarget is_smi(this); |
| 1380 __ test(left_side.reg(), Immediate(kSmiTagMask)); |
| 1381 is_smi.Branch(zero, &left_side, &right_side, taken); |
| 1382 |
| 1383 // Setup and call the compare stub, which expects arguments in edx |
| 1384 // and eax. |
| 1385 CompareStub stub(cc, strict); |
| 1386 left_side.ToRegister(eax); |
| 1387 right_side.ToRegister(edx); |
| 1388 Result result = frame_->CallStub(&stub, &left_side, &right_side, 0); |
| 1389 result.ToRegister(); |
| 1390 __ cmp(result.reg(), 0); |
| 1391 result.Unuse(); |
| 1392 true_target->Branch(cc); |
| 1393 false_target->Jump(); |
| 1394 |
| 1395 is_smi.Bind(&left_side, &right_side); |
| 1396 left_side.ToRegister(); |
| 1397 // Test smi equality and comparison by signed int comparison. |
| 1398 __ cmp(Operand(left_side.reg()), Immediate(right_side.handle())); |
| 1399 left_side.Unuse(); |
| 1400 right_side.Unuse(); |
| 1401 Branch(cc, true_target, false_target, fall_through); |
| 1402 } |
| 1403 } else { // Neither side is a constant Smi, normal comparison operation. |
| 1404 left_side.ToRegister(); |
| 1405 right_side.ToRegister(); |
| 1406 ASSERT(left_side.is_valid()); |
| 1407 ASSERT(right_side.is_valid()); |
| 1408 // Check for the smi case. |
| 1409 JumpTarget is_smi(this); |
| 1410 Result temp = allocator_->Allocate(); |
| 1411 ASSERT(temp.is_valid()); |
| 1412 __ mov(temp.reg(), left_side.reg()); |
| 1413 __ or_(temp.reg(), Operand(right_side.reg())); |
| 1414 __ test(temp.reg(), Immediate(kSmiTagMask)); |
| 1415 temp.Unuse(); |
| 1416 is_smi.Branch(zero, &left_side, &right_side, taken); |
| 1417 |
| 1418 // When non-smi, call out to the compare stub. "parameters" setup by |
| 1419 // calling code in edx and eax and "result" is returned in the flags. |
| 1420 if (!left_side.reg().is(eax)) { |
| 1421 right_side.ToRegister(eax); |
| 1422 left_side.ToRegister(edx); |
| 1423 } else if (!right_side.reg().is(edx)) { |
| 1424 left_side.ToRegister(edx); |
| 1425 right_side.ToRegister(eax); |
| 1426 } else { |
| 1427 frame_->Spill(eax); // Can be multiply referenced, even now. |
| 1428 frame_->Spill(edx); |
| 1429 __ xchg(eax, edx); |
| 1430 // If left_side and right_side become real (non-dummy) arguments |
| 1431 // to CallStub, they need to be swapped in this case. |
| 1432 } |
| 1433 CompareStub stub(cc, strict); |
| 1434 Result answer = frame_->CallStub(&stub, &right_side, &left_side, 0); |
| 1435 if (cc == equal) { |
| 1436 __ test(answer.reg(), Operand(answer.reg())); |
| 1437 } else { |
| 1438 __ cmp(answer.reg(), 0); |
| 1439 } |
| 1440 answer.Unuse(); |
| 1441 true_target->Branch(cc); |
| 1442 false_target->Jump(); |
| 1443 |
| 1444 is_smi.Bind(&left_side, &right_side); |
| 1445 left_side.ToRegister(); |
| 1446 right_side.ToRegister(); |
| 1447 __ cmp(left_side.reg(), Operand(right_side.reg())); |
| 1448 right_side.Unuse(); |
| 1449 left_side.Unuse(); |
| 1450 Branch(cc, true_target, false_target, fall_through); |
| 1364 } | 1451 } |
| 1365 CompareStub stub(cc, strict); | |
| 1366 Result answer = frame_->CallStub(&stub, &right_side, &left_side, 0); | |
| 1367 if (cc == equal) { | |
| 1368 __ test(answer.reg(), Operand(answer.reg())); | |
| 1369 } else { | |
| 1370 __ cmp(answer.reg(), 0); | |
| 1371 } | |
| 1372 answer.Unuse(); | |
| 1373 true_target->Branch(cc); | |
| 1374 false_target->Jump(); | |
| 1375 | |
| 1376 is_smi.Bind(&left_side, &right_side); | |
| 1377 left_side.ToRegister(); | |
| 1378 right_side.ToRegister(); | |
| 1379 __ cmp(left_side.reg(), Operand(right_side.reg())); | |
| 1380 right_side.Unuse(); | |
| 1381 left_side.Unuse(); | |
| 1382 Branch(cc, true_target, false_target, fall_through); | |
| 1383 } | 1452 } |
| 1384 | 1453 |
| 1385 | 1454 |
| 1386 void CodeGenerator::SmiComparison(Condition cc, | 1455 void CodeGenerator::SmiComparison(Condition cc, |
| 1387 Handle<Object> smi_value, | 1456 Handle<Object> smi_value, |
| 1388 bool strict) { | 1457 bool strict) { |
| 1389 // Strict only makes sense for equality comparisons. | 1458 // Strict only makes sense for equality comparisons. |
| 1390 ASSERT(!strict || cc == equal); | 1459 ASSERT(!strict || cc == equal); |
| 1391 ASSERT(is_intn(Smi::cast(*smi_value)->value(), kMaxSmiInlinedBits)); | 1460 ASSERT(is_intn(Smi::cast(*smi_value)->value(), kMaxSmiInlinedBits)); |
| 1392 | 1461 |
| (...skipping 552 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1945 for (int i = 0; i < length; i++) { | 2014 for (int i = 0; i < length; i++) { |
| 1946 CaseClause* clause = cases->at(i); | 2015 CaseClause* clause = cases->at(i); |
| 1947 if (clause->is_default()) { | 2016 if (clause->is_default()) { |
| 1948 // Remember the default clause and compile it at the end. | 2017 // Remember the default clause and compile it at the end. |
| 1949 default_clause = clause; | 2018 default_clause = clause; |
| 1950 continue; | 2019 continue; |
| 1951 } | 2020 } |
| 1952 | 2021 |
| 1953 // Compile each non-default clause. | 2022 // Compile each non-default clause. |
| 1954 Comment cmnt(masm_, "[ Case clause"); | 2023 Comment cmnt(masm_, "[ Case clause"); |
| 1955 // Label and compile the test. | |
| 1956 if (next_test.is_linked()) { | 2024 if (next_test.is_linked()) { |
| 1957 // Recycle the same label for each test. | 2025 // Recycle the same label for each test. |
| 1958 next_test.Bind(); | 2026 next_test.Bind(); |
| 1959 next_test.Unuse(); | 2027 next_test.Unuse(); |
| 1960 } | 2028 } |
| 1961 // Duplicate the switch value. | 2029 |
| 1962 frame_->Dup(); | |
| 1963 Load(clause->label()); | |
| 1964 JumpTarget enter_body(this); | 2030 JumpTarget enter_body(this); |
| 1965 Comparison(equal, true, &enter_body, &next_test, &enter_body); | 2031 // Control flow reaches this test if it is the first non-default case, |
| 2032 // or if a previous test links to this as the next test through the |
| 2033 // next_test JumpTarget. If so, then has_valid_frame() is true. |
| 2034 if (has_valid_frame()) { |
| 2035 // Duplicate the switch value. |
| 2036 frame_->Dup(); |
| 2037 Load(clause->label()); |
| 2038 Comparison(equal, true, &enter_body, &next_test, &enter_body); |
| 2039 } |
| 1966 | 2040 |
| 1967 // Before entering the body from the test remove the switch value from | 2041 bool previous_was_default = (i > 0 && cases->at(i - 1)->is_default()); |
| 1968 // the frame. | 2042 // If the body is unreachable, don't compile it. |
| 1969 frame_->Drop(); | 2043 if (!enter_body.is_bound() && |
| 2044 !previous_was_default && |
| 2045 !fall_through.is_linked()) { |
| 2046 next_test.Unuse(); |
| 2047 continue; |
| 2048 } |
| 2049 // Compile the body, since it is reachable from the test or a fall-through. |
| 2050 if (next_test.is_bound()) { |
| 2051 // The test unconditionally failed, we should go to the next test. |
| 2052 // We still need to compile the body for the fall-through cases. |
| 2053 // In this case, we need to jump over the body. |
| 2054 next_test.Unuse(); |
| 2055 next_test.Jump(); |
| 2056 } else if (enter_body.is_bound()) { |
| 2057 // Otherwise we got here by passing the test. |
| 2058 frame_->Drop(); // The switch value is no longer needed. |
| 2059 } else { |
| 2060 // The tests are being skipped due to an earlier unconditional match, |
| 2061 // and only fall-through to bodies is generating control flow. |
| 2062 ASSERT(!has_valid_frame()); |
| 2063 } |
| 1970 | 2064 |
| 1971 // Label the body so that fall through is enabled. | 2065 // Label the body so that fall through is enabled. |
| 1972 if (i > 0 && cases->at(i - 1)->is_default()) { | 2066 if (previous_was_default) { |
| 1973 // The previous case was the default. This will be the target of a | 2067 // Because the default is compiled last, there is always a potential |
| 1974 // possible backward edge. | 2068 // backwards edge to here, falling through from the default. |
| 1975 default_exit.Bind(); | 2069 default_exit.Bind(); |
| 1976 } else if (fall_through.is_linked()) { | 2070 } else if (fall_through.is_linked()) { |
| 1977 // Recycle the same label for each fall through except for the default | 2071 // Recycle the same label for each fall through. |
| 1978 // case. | |
| 1979 fall_through.Bind(); | 2072 fall_through.Bind(); |
| 1980 fall_through.Unuse(); | 2073 fall_through.Unuse(); |
| 1981 } | 2074 } |
| 1982 VisitStatements(clause->statements()); | 2075 VisitStatements(clause->statements()); |
| 1983 | 2076 |
| 1984 // If control flow can fall through from the body jump to the next body | 2077 // If control flow can fall through from the body jump to the next body |
| 1985 // or the end of the statement. | 2078 // or the end of the statement. |
| 1986 if (has_valid_frame()) { | 2079 if (has_valid_frame()) { |
| 1987 if (i < length - 1 && cases->at(i + 1)->is_default()) { | 2080 if (i < length - 1 && cases->at(i + 1)->is_default()) { |
| 1988 // The next case is the default. | 2081 // The next case is the default. |
| 1989 default_entry.Jump(); | 2082 default_entry.Jump(); |
| 1990 } else { | 2083 } else { |
| 1991 fall_through.Jump(); | 2084 fall_through.Jump(); |
| 1992 } | 2085 } |
| 1993 } | 2086 } |
| 1994 } | 2087 } |
| 1995 | 2088 |
| 1996 // The block at the final "test" label removes the switch value. | 2089 // The block at the final "test" label removes the switch value. |
| 1997 next_test.Bind(); | 2090 if (next_test.is_linked()) { |
| 1998 frame_->Drop(); | 2091 // JumpTarget next_test could have been bound, rather than linked to, |
| 1999 | 2092 // if the previous test was unconditionally false. |
| 2000 // If there is a default clause, compile it now. | 2093 next_test.Bind(); |
| 2094 } |
| 2095 if (has_valid_frame()) { |
| 2096 frame_->Drop(); |
| 2097 } |
| 2098 // If there is a default clause, compile it now. If it is determined |
| 2099 // at compile time to be unreachable, then it has no valid entry frame, |
| 2100 // and it is not compiled. |
| 2001 if (default_clause != NULL) { | 2101 if (default_clause != NULL) { |
| 2002 Comment cmnt(masm_, "[ Default clause"); | 2102 Comment cmnt(masm_, "[ Default clause"); |
| 2003 default_entry.Bind(); | 2103 default_entry.Bind(); |
| 2004 VisitStatements(default_clause->statements()); | 2104 if (has_valid_frame()) { |
| 2105 VisitStatements(default_clause->statements()); |
| 2106 } |
| 2005 // If control flow can fall out of the default and there is a case after | 2107 // If control flow can fall out of the default and there is a case after |
| 2006 // it, jump to that case's body. | 2108 // it, jump to that case's body. |
| 2007 if (has_valid_frame() && default_exit.is_bound()) { | 2109 if (has_valid_frame() && default_exit.is_bound()) { |
| 2008 default_exit.Jump(); | 2110 default_exit.Jump(); |
| 2009 } | 2111 } |
| 2010 } | 2112 } |
| 2011 | 2113 |
| 2012 fall_through.Bind(); | 2114 fall_through.Bind(); |
| 2013 node->break_target()->Bind(); | 2115 node->break_target()->Bind(); |
| 2014 } | 2116 } |
| (...skipping 4335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6350 | 6452 |
| 6351 // Slow-case: Go through the JavaScript implementation. | 6453 // Slow-case: Go through the JavaScript implementation. |
| 6352 __ bind(&slow); | 6454 __ bind(&slow); |
| 6353 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 6455 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 6354 } | 6456 } |
| 6355 | 6457 |
| 6356 | 6458 |
| 6357 #undef __ | 6459 #undef __ |
| 6358 | 6460 |
| 6359 } } // namespace v8::internal | 6461 } } // namespace v8::internal |
| OLD | NEW |