Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: src/arm64/lithium-codegen-arm64.cc

Issue 598953002: Make the detailed reason for deopts mandatory on all platforms. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: rebased Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/arm64/lithium-codegen-arm64.h ('k') | src/mips/lithium-codegen-mips.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 the V8 project authors. All rights reserved. 1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/v8.h" 5 #include "src/v8.h"
6 6
7 #include "src/arm64/lithium-codegen-arm64.h" 7 #include "src/arm64/lithium-codegen-arm64.h"
8 #include "src/arm64/lithium-gap-resolver-arm64.h" 8 #include "src/arm64/lithium-gap-resolver-arm64.h"
9 #include "src/base/bits.h" 9 #include "src/base/bits.h"
10 #include "src/code-factory.h" 10 #include "src/code-factory.h"
(...skipping 1045 matching lines...) Expand 10 before | Expand all | Expand 10 after
1056 // jump entry if this is the case. 1056 // jump entry if this is the case.
1057 if (jump_table_.is_empty() || 1057 if (jump_table_.is_empty() ||
1058 !table_entry->IsEquivalentTo(*jump_table_.last())) { 1058 !table_entry->IsEquivalentTo(*jump_table_.last())) {
1059 jump_table_.Add(table_entry, zone()); 1059 jump_table_.Add(table_entry, zone());
1060 } 1060 }
1061 __ B(&jump_table_.last()->label, branch_type, reg, bit); 1061 __ B(&jump_table_.last()->label, branch_type, reg, bit);
1062 } 1062 }
1063 } 1063 }
1064 1064
1065 1065
1066 void LCodeGen::Deoptimize(LInstruction* instr, 1066 void LCodeGen::Deoptimize(LInstruction* instr, const char* detail,
1067 Deoptimizer::BailoutType* override_bailout_type, 1067 Deoptimizer::BailoutType* override_bailout_type) {
1068 const char* detail) {
1069 DeoptimizeBranch(instr, detail, always, NoReg, -1, override_bailout_type); 1068 DeoptimizeBranch(instr, detail, always, NoReg, -1, override_bailout_type);
1070 } 1069 }
1071 1070
1072 1071
1073 void LCodeGen::DeoptimizeIf(Condition cond, LInstruction* instr, 1072 void LCodeGen::DeoptimizeIf(Condition cond, LInstruction* instr,
1074 const char* detail) { 1073 const char* detail) {
1075 DeoptimizeBranch(instr, detail, static_cast<BranchType>(cond)); 1074 DeoptimizeBranch(instr, detail, static_cast<BranchType>(cond));
1076 } 1075 }
1077 1076
1078 1077
(...skipping 430 matching lines...) Expand 10 before | Expand all | Expand 10 after
1509 1508
1510 1509
1511 void LCodeGen::DoAddI(LAddI* instr) { 1510 void LCodeGen::DoAddI(LAddI* instr) {
1512 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); 1511 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
1513 Register result = ToRegister32(instr->result()); 1512 Register result = ToRegister32(instr->result());
1514 Register left = ToRegister32(instr->left()); 1513 Register left = ToRegister32(instr->left());
1515 Operand right = ToShiftedRightOperand32(instr->right(), instr); 1514 Operand right = ToShiftedRightOperand32(instr->right(), instr);
1516 1515
1517 if (can_overflow) { 1516 if (can_overflow) {
1518 __ Adds(result, left, right); 1517 __ Adds(result, left, right);
1519 DeoptimizeIf(vs, instr); 1518 DeoptimizeIf(vs, instr, "overflow");
1520 } else { 1519 } else {
1521 __ Add(result, left, right); 1520 __ Add(result, left, right);
1522 } 1521 }
1523 } 1522 }
1524 1523
1525 1524
1526 void LCodeGen::DoAddS(LAddS* instr) { 1525 void LCodeGen::DoAddS(LAddS* instr) {
1527 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); 1526 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
1528 Register result = ToRegister(instr->result()); 1527 Register result = ToRegister(instr->result());
1529 Register left = ToRegister(instr->left()); 1528 Register left = ToRegister(instr->left());
1530 Operand right = ToOperand(instr->right()); 1529 Operand right = ToOperand(instr->right());
1531 if (can_overflow) { 1530 if (can_overflow) {
1532 __ Adds(result, left, right); 1531 __ Adds(result, left, right);
1533 DeoptimizeIf(vs, instr); 1532 DeoptimizeIf(vs, instr, "overflow");
1534 } else { 1533 } else {
1535 __ Add(result, left, right); 1534 __ Add(result, left, right);
1536 } 1535 }
1537 } 1536 }
1538 1537
1539 1538
1540 void LCodeGen::DoAllocate(LAllocate* instr) { 1539 void LCodeGen::DoAllocate(LAllocate* instr) {
1541 class DeferredAllocate: public LDeferredCode { 1540 class DeferredAllocate: public LDeferredCode {
1542 public: 1541 public:
1543 DeferredAllocate(LCodeGen* codegen, LAllocate* instr) 1542 DeferredAllocate(LCodeGen* codegen, LAllocate* instr)
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
1649 Register scratch = x5; 1648 Register scratch = x5;
1650 DCHECK(receiver.Is(x0)); // Used for parameter count. 1649 DCHECK(receiver.Is(x0)); // Used for parameter count.
1651 DCHECK(function.Is(x1)); // Required by InvokeFunction. 1650 DCHECK(function.Is(x1)); // Required by InvokeFunction.
1652 DCHECK(ToRegister(instr->result()).Is(x0)); 1651 DCHECK(ToRegister(instr->result()).Is(x0));
1653 DCHECK(instr->IsMarkedAsCall()); 1652 DCHECK(instr->IsMarkedAsCall());
1654 1653
1655 // Copy the arguments to this function possibly from the 1654 // Copy the arguments to this function possibly from the
1656 // adaptor frame below it. 1655 // adaptor frame below it.
1657 const uint32_t kArgumentsLimit = 1 * KB; 1656 const uint32_t kArgumentsLimit = 1 * KB;
1658 __ Cmp(length, kArgumentsLimit); 1657 __ Cmp(length, kArgumentsLimit);
1659 DeoptimizeIf(hi, instr); 1658 DeoptimizeIf(hi, instr, "too many arguments");
1660 1659
1661 // Push the receiver and use the register to keep the original 1660 // Push the receiver and use the register to keep the original
1662 // number of arguments. 1661 // number of arguments.
1663 __ Push(receiver); 1662 __ Push(receiver);
1664 Register argc = receiver; 1663 Register argc = receiver;
1665 receiver = NoReg; 1664 receiver = NoReg;
1666 __ Sxtw(argc, length); 1665 __ Sxtw(argc, length);
1667 // The arguments are at a one pointer size offset from elements. 1666 // The arguments are at a one pointer size offset from elements.
1668 __ Add(elements, elements, 1 * kPointerSize); 1667 __ Add(elements, elements, 1 * kPointerSize);
1669 1668
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
1831 __ Cmp(length, index); 1830 __ Cmp(length, index);
1832 cond = CommuteCondition(cond); 1831 cond = CommuteCondition(cond);
1833 } else { 1832 } else {
1834 Register index = ToRegister32(instr->index()); 1833 Register index = ToRegister32(instr->index());
1835 Operand length = ToOperand32(instr->length()); 1834 Operand length = ToOperand32(instr->length());
1836 __ Cmp(index, length); 1835 __ Cmp(index, length);
1837 } 1836 }
1838 if (FLAG_debug_code && instr->hydrogen()->skip_check()) { 1837 if (FLAG_debug_code && instr->hydrogen()->skip_check()) {
1839 __ Assert(NegateCondition(cond), kEliminatedBoundsCheckFailed); 1838 __ Assert(NegateCondition(cond), kEliminatedBoundsCheckFailed);
1840 } else { 1839 } else {
1841 DeoptimizeIf(cond, instr); 1840 DeoptimizeIf(cond, instr, "out of bounds");
1842 } 1841 }
1843 } 1842 }
1844 1843
1845 1844
1846 void LCodeGen::DoBranch(LBranch* instr) { 1845 void LCodeGen::DoBranch(LBranch* instr) {
1847 Representation r = instr->hydrogen()->value()->representation(); 1846 Representation r = instr->hydrogen()->value()->representation();
1848 Label* true_label = instr->TrueLabel(chunk_); 1847 Label* true_label = instr->TrueLabel(chunk_);
1849 Label* false_label = instr->FalseLabel(chunk_); 1848 Label* false_label = instr->FalseLabel(chunk_);
1850 1849
1851 if (r.IsInteger32()) { 1850 if (r.IsInteger32()) {
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
1910 value, Heap::kNullValueRootIndex, false_label); 1909 value, Heap::kNullValueRootIndex, false_label);
1911 } 1910 }
1912 1911
1913 if (expected.Contains(ToBooleanStub::SMI)) { 1912 if (expected.Contains(ToBooleanStub::SMI)) {
1914 // Smis: 0 -> false, all other -> true. 1913 // Smis: 0 -> false, all other -> true.
1915 DCHECK(Smi::FromInt(0) == 0); 1914 DCHECK(Smi::FromInt(0) == 0);
1916 __ Cbz(value, false_label); 1915 __ Cbz(value, false_label);
1917 __ JumpIfSmi(value, true_label); 1916 __ JumpIfSmi(value, true_label);
1918 } else if (expected.NeedsMap()) { 1917 } else if (expected.NeedsMap()) {
1919 // If we need a map later and have a smi, deopt. 1918 // If we need a map later and have a smi, deopt.
1920 DeoptimizeIfSmi(value, instr); 1919 DeoptimizeIfSmi(value, instr, "Smi");
1921 } 1920 }
1922 1921
1923 Register map = NoReg; 1922 Register map = NoReg;
1924 Register scratch = NoReg; 1923 Register scratch = NoReg;
1925 1924
1926 if (expected.NeedsMap()) { 1925 if (expected.NeedsMap()) {
1927 DCHECK((instr->temp1() != NULL) && (instr->temp2() != NULL)); 1926 DCHECK((instr->temp1() != NULL) && (instr->temp2() != NULL));
1928 map = ToRegister(instr->temp1()); 1927 map = ToRegister(instr->temp1());
1929 scratch = ToRegister(instr->temp2()); 1928 scratch = ToRegister(instr->temp2());
1930 1929
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
1971 // If we got a NaN (overflow bit is set), jump to the false branch. 1970 // If we got a NaN (overflow bit is set), jump to the false branch.
1972 __ B(vs, false_label); 1971 __ B(vs, false_label);
1973 __ B(eq, false_label); 1972 __ B(eq, false_label);
1974 __ B(true_label); 1973 __ B(true_label);
1975 __ Bind(&not_heap_number); 1974 __ Bind(&not_heap_number);
1976 } 1975 }
1977 1976
1978 if (!expected.IsGeneric()) { 1977 if (!expected.IsGeneric()) {
1979 // We've seen something for the first time -> deopt. 1978 // We've seen something for the first time -> deopt.
1980 // This can only happen if we are not generic already. 1979 // This can only happen if we are not generic already.
1981 Deoptimize(instr); 1980 Deoptimize(instr, "unexpected object");
1982 } 1981 }
1983 } 1982 }
1984 } 1983 }
1985 } 1984 }
1986 1985
1987 1986
1988 void LCodeGen::CallKnownFunction(Handle<JSFunction> function, 1987 void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
1989 int formal_parameter_count, 1988 int formal_parameter_count,
1990 int arity, 1989 int arity,
1991 LInstruction* instr, 1990 LInstruction* instr,
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after
2156 Register temp = ToRegister(instr->temp()); 2155 Register temp = ToRegister(instr->temp());
2157 { 2156 {
2158 PushSafepointRegistersScope scope(this); 2157 PushSafepointRegistersScope scope(this);
2159 __ Push(object); 2158 __ Push(object);
2160 __ Mov(cp, 0); 2159 __ Mov(cp, 0);
2161 __ CallRuntimeSaveDoubles(Runtime::kTryMigrateInstance); 2160 __ CallRuntimeSaveDoubles(Runtime::kTryMigrateInstance);
2162 RecordSafepointWithRegisters( 2161 RecordSafepointWithRegisters(
2163 instr->pointer_map(), 1, Safepoint::kNoLazyDeopt); 2162 instr->pointer_map(), 1, Safepoint::kNoLazyDeopt);
2164 __ StoreToSafepointRegisterSlot(x0, temp); 2163 __ StoreToSafepointRegisterSlot(x0, temp);
2165 } 2164 }
2166 DeoptimizeIfSmi(temp, instr); 2165 DeoptimizeIfSmi(temp, instr, "instance migration failed");
2167 } 2166 }
2168 2167
2169 2168
2170 void LCodeGen::DoCheckMaps(LCheckMaps* instr) { 2169 void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
2171 class DeferredCheckMaps: public LDeferredCode { 2170 class DeferredCheckMaps: public LDeferredCode {
2172 public: 2171 public:
2173 DeferredCheckMaps(LCodeGen* codegen, LCheckMaps* instr, Register object) 2172 DeferredCheckMaps(LCodeGen* codegen, LCheckMaps* instr, Register object)
2174 : LDeferredCode(codegen), instr_(instr), object_(object) { 2173 : LDeferredCode(codegen), instr_(instr), object_(object) {
2175 SetExit(check_maps()); 2174 SetExit(check_maps());
2176 } 2175 }
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
2211 __ CompareMap(map_reg, map); 2210 __ CompareMap(map_reg, map);
2212 __ B(eq, &success); 2211 __ B(eq, &success);
2213 } 2212 }
2214 Handle<Map> map = maps->at(maps->size() - 1).handle(); 2213 Handle<Map> map = maps->at(maps->size() - 1).handle();
2215 __ CompareMap(map_reg, map); 2214 __ CompareMap(map_reg, map);
2216 2215
2217 // We didn't match a map. 2216 // We didn't match a map.
2218 if (instr->hydrogen()->HasMigrationTarget()) { 2217 if (instr->hydrogen()->HasMigrationTarget()) {
2219 __ B(ne, deferred->entry()); 2218 __ B(ne, deferred->entry());
2220 } else { 2219 } else {
2221 DeoptimizeIf(ne, instr); 2220 DeoptimizeIf(ne, instr, "wrong map");
2222 } 2221 }
2223 2222
2224 __ Bind(&success); 2223 __ Bind(&success);
2225 } 2224 }
2226 2225
2227 2226
2228 void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) { 2227 void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
2229 if (!instr->hydrogen()->value()->type().IsHeapObject()) { 2228 if (!instr->hydrogen()->value()->type().IsHeapObject()) {
2230 DeoptimizeIfSmi(ToRegister(instr->value()), instr); 2229 DeoptimizeIfSmi(ToRegister(instr->value()), instr, "Smi");
2231 } 2230 }
2232 } 2231 }
2233 2232
2234 2233
2235 void LCodeGen::DoCheckSmi(LCheckSmi* instr) { 2234 void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
2236 Register value = ToRegister(instr->value()); 2235 Register value = ToRegister(instr->value());
2237 DCHECK(!instr->result() || ToRegister(instr->result()).Is(value)); 2236 DCHECK(!instr->result() || ToRegister(instr->result()).Is(value));
2238 DeoptimizeIfNotSmi(value, instr); 2237 DeoptimizeIfNotSmi(value, instr, "not a Smi");
2239 } 2238 }
2240 2239
2241 2240
2242 void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { 2241 void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
2243 Register input = ToRegister(instr->value()); 2242 Register input = ToRegister(instr->value());
2244 Register scratch = ToRegister(instr->temp()); 2243 Register scratch = ToRegister(instr->temp());
2245 2244
2246 __ Ldr(scratch, FieldMemOperand(input, HeapObject::kMapOffset)); 2245 __ Ldr(scratch, FieldMemOperand(input, HeapObject::kMapOffset));
2247 __ Ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset)); 2246 __ Ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
2248 2247
2249 if (instr->hydrogen()->is_interval_check()) { 2248 if (instr->hydrogen()->is_interval_check()) {
2250 InstanceType first, last; 2249 InstanceType first, last;
2251 instr->hydrogen()->GetCheckInterval(&first, &last); 2250 instr->hydrogen()->GetCheckInterval(&first, &last);
2252 2251
2253 __ Cmp(scratch, first); 2252 __ Cmp(scratch, first);
2254 if (first == last) { 2253 if (first == last) {
2255 // If there is only one type in the interval check for equality. 2254 // If there is only one type in the interval check for equality.
2256 DeoptimizeIf(ne, instr); 2255 DeoptimizeIf(ne, instr, "wrong instance type");
2257 } else if (last == LAST_TYPE) { 2256 } else if (last == LAST_TYPE) {
2258 // We don't need to compare with the higher bound of the interval. 2257 // We don't need to compare with the higher bound of the interval.
2259 DeoptimizeIf(lo, instr); 2258 DeoptimizeIf(lo, instr, "wrong instance type");
2260 } else { 2259 } else {
2261 // If we are below the lower bound, set the C flag and clear the Z flag 2260 // If we are below the lower bound, set the C flag and clear the Z flag
2262 // to force a deopt. 2261 // to force a deopt.
2263 __ Ccmp(scratch, last, CFlag, hs); 2262 __ Ccmp(scratch, last, CFlag, hs);
2264 DeoptimizeIf(hi, instr); 2263 DeoptimizeIf(hi, instr, "wrong instance type");
2265 } 2264 }
2266 } else { 2265 } else {
2267 uint8_t mask; 2266 uint8_t mask;
2268 uint8_t tag; 2267 uint8_t tag;
2269 instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag); 2268 instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag);
2270 2269
2271 if (base::bits::IsPowerOfTwo32(mask)) { 2270 if (base::bits::IsPowerOfTwo32(mask)) {
2272 DCHECK((tag == 0) || (tag == mask)); 2271 DCHECK((tag == 0) || (tag == mask));
2273 if (tag == 0) { 2272 if (tag == 0) {
2274 DeoptimizeIfBitSet(scratch, MaskToBit(mask), instr); 2273 DeoptimizeIfBitSet(scratch, MaskToBit(mask), instr,
2274 "wrong instance type");
2275 } else { 2275 } else {
2276 DeoptimizeIfBitClear(scratch, MaskToBit(mask), instr); 2276 DeoptimizeIfBitClear(scratch, MaskToBit(mask), instr,
2277 "wrong instance type");
2277 } 2278 }
2278 } else { 2279 } else {
2279 if (tag == 0) { 2280 if (tag == 0) {
2280 __ Tst(scratch, mask); 2281 __ Tst(scratch, mask);
2281 } else { 2282 } else {
2282 __ And(scratch, scratch, mask); 2283 __ And(scratch, scratch, mask);
2283 __ Cmp(scratch, tag); 2284 __ Cmp(scratch, tag);
2284 } 2285 }
2285 DeoptimizeIf(ne, instr); 2286 DeoptimizeIf(ne, instr, "wrong instance type");
2286 } 2287 }
2287 } 2288 }
2288 } 2289 }
2289 2290
2290 2291
2291 void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) { 2292 void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
2292 DoubleRegister input = ToDoubleRegister(instr->unclamped()); 2293 DoubleRegister input = ToDoubleRegister(instr->unclamped());
2293 Register result = ToRegister32(instr->result()); 2294 Register result = ToRegister32(instr->result());
2294 __ ClampDoubleToUint8(result, input, double_scratch()); 2295 __ ClampDoubleToUint8(result, input, double_scratch());
2295 } 2296 }
(...skipping 18 matching lines...) Expand all
2314 __ ClampInt32ToUint8(result); 2315 __ ClampInt32ToUint8(result);
2315 __ B(&done); 2316 __ B(&done);
2316 2317
2317 __ Bind(&is_not_smi); 2318 __ Bind(&is_not_smi);
2318 2319
2319 // Check for heap number. 2320 // Check for heap number.
2320 Label is_heap_number; 2321 Label is_heap_number;
2321 __ JumpIfHeapNumber(input, &is_heap_number); 2322 __ JumpIfHeapNumber(input, &is_heap_number);
2322 2323
2323 // Check for undefined. Undefined is coverted to zero for clamping conversion. 2324 // Check for undefined. Undefined is coverted to zero for clamping conversion.
2324 DeoptimizeIfNotRoot(input, Heap::kUndefinedValueRootIndex, instr); 2325 DeoptimizeIfNotRoot(input, Heap::kUndefinedValueRootIndex, instr,
2326 "not a heap number/undefined");
2325 __ Mov(result, 0); 2327 __ Mov(result, 0);
2326 __ B(&done); 2328 __ B(&done);
2327 2329
2328 // Heap number case. 2330 // Heap number case.
2329 __ Bind(&is_heap_number); 2331 __ Bind(&is_heap_number);
2330 DoubleRegister dbl_scratch = double_scratch(); 2332 DoubleRegister dbl_scratch = double_scratch();
2331 DoubleRegister dbl_scratch2 = ToDoubleRegister(instr->temp1()); 2333 DoubleRegister dbl_scratch2 = ToDoubleRegister(instr->temp1());
2332 __ Ldr(dbl_scratch, FieldMemOperand(input, HeapNumber::kValueOffset)); 2334 __ Ldr(dbl_scratch, FieldMemOperand(input, HeapNumber::kValueOffset));
2333 __ ClampDoubleToUint8(result, dbl_scratch, dbl_scratch2); 2335 __ ClampDoubleToUint8(result, dbl_scratch, dbl_scratch2);
2334 2336
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after
2619 if (isolate()->heap()->InNewSpace(*object)) { 2621 if (isolate()->heap()->InNewSpace(*object)) {
2620 UseScratchRegisterScope temps(masm()); 2622 UseScratchRegisterScope temps(masm());
2621 Register temp = temps.AcquireX(); 2623 Register temp = temps.AcquireX();
2622 Handle<Cell> cell = isolate()->factory()->NewCell(object); 2624 Handle<Cell> cell = isolate()->factory()->NewCell(object);
2623 __ Mov(temp, Operand(Handle<Object>(cell))); 2625 __ Mov(temp, Operand(Handle<Object>(cell)));
2624 __ Ldr(temp, FieldMemOperand(temp, Cell::kValueOffset)); 2626 __ Ldr(temp, FieldMemOperand(temp, Cell::kValueOffset));
2625 __ Cmp(reg, temp); 2627 __ Cmp(reg, temp);
2626 } else { 2628 } else {
2627 __ Cmp(reg, Operand(object)); 2629 __ Cmp(reg, Operand(object));
2628 } 2630 }
2629 DeoptimizeIf(ne, instr); 2631 DeoptimizeIf(ne, instr, "value mismatch");
2630 } 2632 }
2631 2633
2632 2634
2633 void LCodeGen::DoLazyBailout(LLazyBailout* instr) { 2635 void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
2634 last_lazy_deopt_pc_ = masm()->pc_offset(); 2636 last_lazy_deopt_pc_ = masm()->pc_offset();
2635 DCHECK(instr->HasEnvironment()); 2637 DCHECK(instr->HasEnvironment());
2636 LEnvironment* env = instr->environment(); 2638 LEnvironment* env = instr->environment();
2637 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt); 2639 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
2638 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); 2640 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
2639 } 2641 }
2640 2642
2641 2643
2642 void LCodeGen::DoDateField(LDateField* instr) { 2644 void LCodeGen::DoDateField(LDateField* instr) {
2643 Register object = ToRegister(instr->date()); 2645 Register object = ToRegister(instr->date());
2644 Register result = ToRegister(instr->result()); 2646 Register result = ToRegister(instr->result());
2645 Register temp1 = x10; 2647 Register temp1 = x10;
2646 Register temp2 = x11; 2648 Register temp2 = x11;
2647 Smi* index = instr->index(); 2649 Smi* index = instr->index();
2648 Label runtime, done; 2650 Label runtime, done;
2649 2651
2650 DCHECK(object.is(result) && object.Is(x0)); 2652 DCHECK(object.is(result) && object.Is(x0));
2651 DCHECK(instr->IsMarkedAsCall()); 2653 DCHECK(instr->IsMarkedAsCall());
2652 2654
2653 DeoptimizeIfSmi(object, instr); 2655 DeoptimizeIfSmi(object, instr, "Smi");
2654 __ CompareObjectType(object, temp1, temp1, JS_DATE_TYPE); 2656 __ CompareObjectType(object, temp1, temp1, JS_DATE_TYPE);
2655 DeoptimizeIf(ne, instr); 2657 DeoptimizeIf(ne, instr, "not a date object");
2656 2658
2657 if (index->value() == 0) { 2659 if (index->value() == 0) {
2658 __ Ldr(result, FieldMemOperand(object, JSDate::kValueOffset)); 2660 __ Ldr(result, FieldMemOperand(object, JSDate::kValueOffset));
2659 } else { 2661 } else {
2660 if (index->value() < JSDate::kFirstUncachedField) { 2662 if (index->value() < JSDate::kFirstUncachedField) {
2661 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate()); 2663 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
2662 __ Mov(temp1, Operand(stamp)); 2664 __ Mov(temp1, Operand(stamp));
2663 __ Ldr(temp1, MemOperand(temp1)); 2665 __ Ldr(temp1, MemOperand(temp1));
2664 __ Ldr(temp2, FieldMemOperand(object, JSDate::kCacheStampOffset)); 2666 __ Ldr(temp2, FieldMemOperand(object, JSDate::kCacheStampOffset));
2665 __ Cmp(temp1, temp2); 2667 __ Cmp(temp1, temp2);
(...skipping 15 matching lines...) Expand all
2681 void LCodeGen::DoDeoptimize(LDeoptimize* instr) { 2683 void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
2682 Deoptimizer::BailoutType type = instr->hydrogen()->type(); 2684 Deoptimizer::BailoutType type = instr->hydrogen()->type();
2683 // TODO(danno): Stubs expect all deopts to be lazy for historical reasons (the 2685 // TODO(danno): Stubs expect all deopts to be lazy for historical reasons (the
2684 // needed return address), even though the implementation of LAZY and EAGER is 2686 // needed return address), even though the implementation of LAZY and EAGER is
2685 // now identical. When LAZY is eventually completely folded into EAGER, remove 2687 // now identical. When LAZY is eventually completely folded into EAGER, remove
2686 // the special case below. 2688 // the special case below.
2687 if (info()->IsStub() && (type == Deoptimizer::EAGER)) { 2689 if (info()->IsStub() && (type == Deoptimizer::EAGER)) {
2688 type = Deoptimizer::LAZY; 2690 type = Deoptimizer::LAZY;
2689 } 2691 }
2690 2692
2691 Deoptimize(instr, &type, instr->hydrogen()->reason()); 2693 Deoptimize(instr, instr->hydrogen()->reason(), &type);
2692 } 2694 }
2693 2695
2694 2696
2695 void LCodeGen::DoDivByPowerOf2I(LDivByPowerOf2I* instr) { 2697 void LCodeGen::DoDivByPowerOf2I(LDivByPowerOf2I* instr) {
2696 Register dividend = ToRegister32(instr->dividend()); 2698 Register dividend = ToRegister32(instr->dividend());
2697 int32_t divisor = instr->divisor(); 2699 int32_t divisor = instr->divisor();
2698 Register result = ToRegister32(instr->result()); 2700 Register result = ToRegister32(instr->result());
2699 DCHECK(divisor == kMinInt || base::bits::IsPowerOfTwo32(Abs(divisor))); 2701 DCHECK(divisor == kMinInt || base::bits::IsPowerOfTwo32(Abs(divisor)));
2700 DCHECK(!result.is(dividend)); 2702 DCHECK(!result.is(dividend));
2701 2703
2702 // Check for (0 / -x) that will produce negative zero. 2704 // Check for (0 / -x) that will produce negative zero.
2703 HDiv* hdiv = instr->hydrogen(); 2705 HDiv* hdiv = instr->hydrogen();
2704 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) { 2706 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) {
2705 DeoptimizeIfZero(dividend, instr); 2707 DeoptimizeIfZero(dividend, instr, "division by zero");
2706 } 2708 }
2707 // Check for (kMinInt / -1). 2709 // Check for (kMinInt / -1).
2708 if (hdiv->CheckFlag(HValue::kCanOverflow) && divisor == -1) { 2710 if (hdiv->CheckFlag(HValue::kCanOverflow) && divisor == -1) {
2709 // Test dividend for kMinInt by subtracting one (cmp) and checking for 2711 // Test dividend for kMinInt by subtracting one (cmp) and checking for
2710 // overflow. 2712 // overflow.
2711 __ Cmp(dividend, 1); 2713 __ Cmp(dividend, 1);
2712 DeoptimizeIf(vs, instr); 2714 DeoptimizeIf(vs, instr, "overflow");
2713 } 2715 }
2714 // Deoptimize if remainder will not be 0. 2716 // Deoptimize if remainder will not be 0.
2715 if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) && 2717 if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
2716 divisor != 1 && divisor != -1) { 2718 divisor != 1 && divisor != -1) {
2717 int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1); 2719 int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1);
2718 __ Tst(dividend, mask); 2720 __ Tst(dividend, mask);
2719 DeoptimizeIf(ne, instr); 2721 DeoptimizeIf(ne, instr, "lost precision");
2720 } 2722 }
2721 2723
2722 if (divisor == -1) { // Nice shortcut, not needed for correctness. 2724 if (divisor == -1) { // Nice shortcut, not needed for correctness.
2723 __ Neg(result, dividend); 2725 __ Neg(result, dividend);
2724 return; 2726 return;
2725 } 2727 }
2726 int32_t shift = WhichPowerOf2Abs(divisor); 2728 int32_t shift = WhichPowerOf2Abs(divisor);
2727 if (shift == 0) { 2729 if (shift == 0) {
2728 __ Mov(result, dividend); 2730 __ Mov(result, dividend);
2729 } else if (shift == 1) { 2731 } else if (shift == 1) {
2730 __ Add(result, dividend, Operand(dividend, LSR, 31)); 2732 __ Add(result, dividend, Operand(dividend, LSR, 31));
2731 } else { 2733 } else {
2732 __ Mov(result, Operand(dividend, ASR, 31)); 2734 __ Mov(result, Operand(dividend, ASR, 31));
2733 __ Add(result, dividend, Operand(result, LSR, 32 - shift)); 2735 __ Add(result, dividend, Operand(result, LSR, 32 - shift));
2734 } 2736 }
2735 if (shift > 0) __ Mov(result, Operand(result, ASR, shift)); 2737 if (shift > 0) __ Mov(result, Operand(result, ASR, shift));
2736 if (divisor < 0) __ Neg(result, result); 2738 if (divisor < 0) __ Neg(result, result);
2737 } 2739 }
2738 2740
2739 2741
2740 void LCodeGen::DoDivByConstI(LDivByConstI* instr) { 2742 void LCodeGen::DoDivByConstI(LDivByConstI* instr) {
2741 Register dividend = ToRegister32(instr->dividend()); 2743 Register dividend = ToRegister32(instr->dividend());
2742 int32_t divisor = instr->divisor(); 2744 int32_t divisor = instr->divisor();
2743 Register result = ToRegister32(instr->result()); 2745 Register result = ToRegister32(instr->result());
2744 DCHECK(!AreAliased(dividend, result)); 2746 DCHECK(!AreAliased(dividend, result));
2745 2747
2746 if (divisor == 0) { 2748 if (divisor == 0) {
2747 Deoptimize(instr); 2749 Deoptimize(instr, "division by zero");
2748 return; 2750 return;
2749 } 2751 }
2750 2752
2751 // Check for (0 / -x) that will produce negative zero. 2753 // Check for (0 / -x) that will produce negative zero.
2752 HDiv* hdiv = instr->hydrogen(); 2754 HDiv* hdiv = instr->hydrogen();
2753 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) { 2755 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) {
2754 DeoptimizeIfZero(dividend, instr); 2756 DeoptimizeIfZero(dividend, instr, "minus zero");
2755 } 2757 }
2756 2758
2757 __ TruncatingDiv(result, dividend, Abs(divisor)); 2759 __ TruncatingDiv(result, dividend, Abs(divisor));
2758 if (divisor < 0) __ Neg(result, result); 2760 if (divisor < 0) __ Neg(result, result);
2759 2761
2760 if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) { 2762 if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) {
2761 Register temp = ToRegister32(instr->temp()); 2763 Register temp = ToRegister32(instr->temp());
2762 DCHECK(!AreAliased(dividend, result, temp)); 2764 DCHECK(!AreAliased(dividend, result, temp));
2763 __ Sxtw(dividend.X(), dividend); 2765 __ Sxtw(dividend.X(), dividend);
2764 __ Mov(temp, divisor); 2766 __ Mov(temp, divisor);
2765 __ Smsubl(temp.X(), result, temp, dividend.X()); 2767 __ Smsubl(temp.X(), result, temp, dividend.X());
2766 DeoptimizeIfNotZero(temp, instr); 2768 DeoptimizeIfNotZero(temp, instr, "lost precision");
2767 } 2769 }
2768 } 2770 }
2769 2771
2770 2772
2771 // TODO(svenpanne) Refactor this to avoid code duplication with DoFlooringDivI. 2773 // TODO(svenpanne) Refactor this to avoid code duplication with DoFlooringDivI.
2772 void LCodeGen::DoDivI(LDivI* instr) { 2774 void LCodeGen::DoDivI(LDivI* instr) {
2773 HBinaryOperation* hdiv = instr->hydrogen(); 2775 HBinaryOperation* hdiv = instr->hydrogen();
2774 Register dividend = ToRegister32(instr->dividend()); 2776 Register dividend = ToRegister32(instr->dividend());
2775 Register divisor = ToRegister32(instr->divisor()); 2777 Register divisor = ToRegister32(instr->divisor());
2776 Register result = ToRegister32(instr->result()); 2778 Register result = ToRegister32(instr->result());
2777 2779
2778 // Issue the division first, and then check for any deopt cases whilst the 2780 // Issue the division first, and then check for any deopt cases whilst the
2779 // result is computed. 2781 // result is computed.
2780 __ Sdiv(result, dividend, divisor); 2782 __ Sdiv(result, dividend, divisor);
2781 2783
2782 if (hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) { 2784 if (hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
2783 DCHECK_EQ(NULL, instr->temp()); 2785 DCHECK_EQ(NULL, instr->temp());
2784 return; 2786 return;
2785 } 2787 }
2786 2788
2787 // Check for x / 0. 2789 // Check for x / 0.
2788 if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) { 2790 if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) {
2789 DeoptimizeIfZero(divisor, instr); 2791 DeoptimizeIfZero(divisor, instr, "division by zero");
2790 } 2792 }
2791 2793
2792 // Check for (0 / -x) as that will produce negative zero. 2794 // Check for (0 / -x) as that will produce negative zero.
2793 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) { 2795 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) {
2794 __ Cmp(divisor, 0); 2796 __ Cmp(divisor, 0);
2795 2797
2796 // If the divisor < 0 (mi), compare the dividend, and deopt if it is 2798 // If the divisor < 0 (mi), compare the dividend, and deopt if it is
2797 // zero, ie. zero dividend with negative divisor deopts. 2799 // zero, ie. zero dividend with negative divisor deopts.
2798 // If the divisor >= 0 (pl, the opposite of mi) set the flags to 2800 // If the divisor >= 0 (pl, the opposite of mi) set the flags to
2799 // condition ne, so we don't deopt, ie. positive divisor doesn't deopt. 2801 // condition ne, so we don't deopt, ie. positive divisor doesn't deopt.
2800 __ Ccmp(dividend, 0, NoFlag, mi); 2802 __ Ccmp(dividend, 0, NoFlag, mi);
2801 DeoptimizeIf(eq, instr); 2803 DeoptimizeIf(eq, instr, "minus zero");
2802 } 2804 }
2803 2805
2804 // Check for (kMinInt / -1). 2806 // Check for (kMinInt / -1).
2805 if (hdiv->CheckFlag(HValue::kCanOverflow)) { 2807 if (hdiv->CheckFlag(HValue::kCanOverflow)) {
2806 // Test dividend for kMinInt by subtracting one (cmp) and checking for 2808 // Test dividend for kMinInt by subtracting one (cmp) and checking for
2807 // overflow. 2809 // overflow.
2808 __ Cmp(dividend, 1); 2810 __ Cmp(dividend, 1);
2809 // If overflow is set, ie. dividend = kMinInt, compare the divisor with 2811 // If overflow is set, ie. dividend = kMinInt, compare the divisor with
2810 // -1. If overflow is clear, set the flags for condition ne, as the 2812 // -1. If overflow is clear, set the flags for condition ne, as the
2811 // dividend isn't -1, and thus we shouldn't deopt. 2813 // dividend isn't -1, and thus we shouldn't deopt.
2812 __ Ccmp(divisor, -1, NoFlag, vs); 2814 __ Ccmp(divisor, -1, NoFlag, vs);
2813 DeoptimizeIf(eq, instr); 2815 DeoptimizeIf(eq, instr, "overflow");
2814 } 2816 }
2815 2817
2816 // Compute remainder and deopt if it's not zero. 2818 // Compute remainder and deopt if it's not zero.
2817 Register remainder = ToRegister32(instr->temp()); 2819 Register remainder = ToRegister32(instr->temp());
2818 __ Msub(remainder, result, divisor, dividend); 2820 __ Msub(remainder, result, divisor, dividend);
2819 DeoptimizeIfNotZero(remainder, instr); 2821 DeoptimizeIfNotZero(remainder, instr, "lost precision");
2820 } 2822 }
2821 2823
2822 2824
2823 void LCodeGen::DoDoubleToIntOrSmi(LDoubleToIntOrSmi* instr) { 2825 void LCodeGen::DoDoubleToIntOrSmi(LDoubleToIntOrSmi* instr) {
2824 DoubleRegister input = ToDoubleRegister(instr->value()); 2826 DoubleRegister input = ToDoubleRegister(instr->value());
2825 Register result = ToRegister32(instr->result()); 2827 Register result = ToRegister32(instr->result());
2826 2828
2827 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 2829 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
2828 DeoptimizeIfMinusZero(input, instr); 2830 DeoptimizeIfMinusZero(input, instr, "minus zero");
2829 } 2831 }
2830 2832
2831 __ TryRepresentDoubleAsInt32(result, input, double_scratch()); 2833 __ TryRepresentDoubleAsInt32(result, input, double_scratch());
2832 DeoptimizeIf(ne, instr); 2834 DeoptimizeIf(ne, instr, "lost precision or NaN");
2833 2835
2834 if (instr->tag_result()) { 2836 if (instr->tag_result()) {
2835 __ SmiTag(result.X()); 2837 __ SmiTag(result.X());
2836 } 2838 }
2837 } 2839 }
2838 2840
2839 2841
2840 void LCodeGen::DoDrop(LDrop* instr) { 2842 void LCodeGen::DoDrop(LDrop* instr) {
2841 __ Drop(instr->count()); 2843 __ Drop(instr->count());
2842 } 2844 }
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
2883 __ EnumLengthUntagged(result, map); 2885 __ EnumLengthUntagged(result, map);
2884 __ Cbnz(result, &load_cache); 2886 __ Cbnz(result, &load_cache);
2885 2887
2886 __ Mov(result, Operand(isolate()->factory()->empty_fixed_array())); 2888 __ Mov(result, Operand(isolate()->factory()->empty_fixed_array()));
2887 __ B(&done); 2889 __ B(&done);
2888 2890
2889 __ Bind(&load_cache); 2891 __ Bind(&load_cache);
2890 __ LoadInstanceDescriptors(map, result); 2892 __ LoadInstanceDescriptors(map, result);
2891 __ Ldr(result, FieldMemOperand(result, DescriptorArray::kEnumCacheOffset)); 2893 __ Ldr(result, FieldMemOperand(result, DescriptorArray::kEnumCacheOffset));
2892 __ Ldr(result, FieldMemOperand(result, FixedArray::SizeFor(instr->idx()))); 2894 __ Ldr(result, FieldMemOperand(result, FixedArray::SizeFor(instr->idx())));
2893 DeoptimizeIfZero(result, instr); 2895 DeoptimizeIfZero(result, instr, "no cache");
2894 2896
2895 __ Bind(&done); 2897 __ Bind(&done);
2896 } 2898 }
2897 2899
2898 2900
2899 void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) { 2901 void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) {
2900 Register object = ToRegister(instr->object()); 2902 Register object = ToRegister(instr->object());
2901 Register null_value = x5; 2903 Register null_value = x5;
2902 2904
2903 DCHECK(instr->IsMarkedAsCall()); 2905 DCHECK(instr->IsMarkedAsCall());
2904 DCHECK(object.Is(x0)); 2906 DCHECK(object.Is(x0));
2905 2907
2906 DeoptimizeIfRoot(object, Heap::kUndefinedValueRootIndex, instr); 2908 DeoptimizeIfRoot(object, Heap::kUndefinedValueRootIndex, instr, "undefined");
2907 2909
2908 __ LoadRoot(null_value, Heap::kNullValueRootIndex); 2910 __ LoadRoot(null_value, Heap::kNullValueRootIndex);
2909 __ Cmp(object, null_value); 2911 __ Cmp(object, null_value);
2910 DeoptimizeIf(eq, instr); 2912 DeoptimizeIf(eq, instr, "null");
2911 2913
2912 DeoptimizeIfSmi(object, instr); 2914 DeoptimizeIfSmi(object, instr, "Smi");
2913 2915
2914 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); 2916 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
2915 __ CompareObjectType(object, x1, x1, LAST_JS_PROXY_TYPE); 2917 __ CompareObjectType(object, x1, x1, LAST_JS_PROXY_TYPE);
2916 DeoptimizeIf(le, instr); 2918 DeoptimizeIf(le, instr, "not a JavaScript object");
2917 2919
2918 Label use_cache, call_runtime; 2920 Label use_cache, call_runtime;
2919 __ CheckEnumCache(object, null_value, x1, x2, x3, x4, &call_runtime); 2921 __ CheckEnumCache(object, null_value, x1, x2, x3, x4, &call_runtime);
2920 2922
2921 __ Ldr(object, FieldMemOperand(object, HeapObject::kMapOffset)); 2923 __ Ldr(object, FieldMemOperand(object, HeapObject::kMapOffset));
2922 __ B(&use_cache); 2924 __ B(&use_cache);
2923 2925
2924 // Get the set of properties to enumerate. 2926 // Get the set of properties to enumerate.
2925 __ Bind(&call_runtime); 2927 __ Bind(&call_runtime);
2926 __ Push(object); 2928 __ Push(object);
2927 CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr); 2929 CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr);
2928 2930
2929 __ Ldr(x1, FieldMemOperand(object, HeapObject::kMapOffset)); 2931 __ Ldr(x1, FieldMemOperand(object, HeapObject::kMapOffset));
2930 DeoptimizeIfNotRoot(x1, Heap::kMetaMapRootIndex, instr); 2932 DeoptimizeIfNotRoot(x1, Heap::kMetaMapRootIndex, instr, "wrong map");
2931 2933
2932 __ Bind(&use_cache); 2934 __ Bind(&use_cache);
2933 } 2935 }
2934 2936
2935 2937
2936 void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) { 2938 void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
2937 Register input = ToRegister(instr->value()); 2939 Register input = ToRegister(instr->value());
2938 Register result = ToRegister(instr->result()); 2940 Register result = ToRegister(instr->result());
2939 2941
2940 __ AssertString(input); 2942 __ AssertString(input);
(...skipping 372 matching lines...) Expand 10 before | Expand all | Expand 10 after
3313 DoGap(label); 3315 DoGap(label);
3314 } 3316 }
3315 3317
3316 3318
3317 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) { 3319 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
3318 Register context = ToRegister(instr->context()); 3320 Register context = ToRegister(instr->context());
3319 Register result = ToRegister(instr->result()); 3321 Register result = ToRegister(instr->result());
3320 __ Ldr(result, ContextMemOperand(context, instr->slot_index())); 3322 __ Ldr(result, ContextMemOperand(context, instr->slot_index()));
3321 if (instr->hydrogen()->RequiresHoleCheck()) { 3323 if (instr->hydrogen()->RequiresHoleCheck()) {
3322 if (instr->hydrogen()->DeoptimizesOnHole()) { 3324 if (instr->hydrogen()->DeoptimizesOnHole()) {
3323 DeoptimizeIfRoot(result, Heap::kTheHoleValueRootIndex, instr); 3325 DeoptimizeIfRoot(result, Heap::kTheHoleValueRootIndex, instr, "hole");
3324 } else { 3326 } else {
3325 Label not_the_hole; 3327 Label not_the_hole;
3326 __ JumpIfNotRoot(result, Heap::kTheHoleValueRootIndex, &not_the_hole); 3328 __ JumpIfNotRoot(result, Heap::kTheHoleValueRootIndex, &not_the_hole);
3327 __ LoadRoot(result, Heap::kUndefinedValueRootIndex); 3329 __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
3328 __ Bind(&not_the_hole); 3330 __ Bind(&not_the_hole);
3329 } 3331 }
3330 } 3332 }
3331 } 3333 }
3332 3334
3333 3335
3334 void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) { 3336 void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
3335 Register function = ToRegister(instr->function()); 3337 Register function = ToRegister(instr->function());
3336 Register result = ToRegister(instr->result()); 3338 Register result = ToRegister(instr->result());
3337 Register temp = ToRegister(instr->temp()); 3339 Register temp = ToRegister(instr->temp());
3338 3340
3339 // Get the prototype or initial map from the function. 3341 // Get the prototype or initial map from the function.
3340 __ Ldr(result, FieldMemOperand(function, 3342 __ Ldr(result, FieldMemOperand(function,
3341 JSFunction::kPrototypeOrInitialMapOffset)); 3343 JSFunction::kPrototypeOrInitialMapOffset));
3342 3344
3343 // Check that the function has a prototype or an initial map. 3345 // Check that the function has a prototype or an initial map.
3344 DeoptimizeIfRoot(result, Heap::kTheHoleValueRootIndex, instr); 3346 DeoptimizeIfRoot(result, Heap::kTheHoleValueRootIndex, instr, "hole");
3345 3347
3346 // If the function does not have an initial map, we're done. 3348 // If the function does not have an initial map, we're done.
3347 Label done; 3349 Label done;
3348 __ CompareObjectType(result, temp, temp, MAP_TYPE); 3350 __ CompareObjectType(result, temp, temp, MAP_TYPE);
3349 __ B(ne, &done); 3351 __ B(ne, &done);
3350 3352
3351 // Get the prototype from the initial map. 3353 // Get the prototype from the initial map.
3352 __ Ldr(result, FieldMemOperand(result, Map::kPrototypeOffset)); 3354 __ Ldr(result, FieldMemOperand(result, Map::kPrototypeOffset));
3353 3355
3354 // All done. 3356 // All done.
3355 __ Bind(&done); 3357 __ Bind(&done);
3356 } 3358 }
3357 3359
3358 3360
3359 void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) { 3361 void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
3360 Register result = ToRegister(instr->result()); 3362 Register result = ToRegister(instr->result());
3361 __ Mov(result, Operand(Handle<Object>(instr->hydrogen()->cell().handle()))); 3363 __ Mov(result, Operand(Handle<Object>(instr->hydrogen()->cell().handle())));
3362 __ Ldr(result, FieldMemOperand(result, Cell::kValueOffset)); 3364 __ Ldr(result, FieldMemOperand(result, Cell::kValueOffset));
3363 if (instr->hydrogen()->RequiresHoleCheck()) { 3365 if (instr->hydrogen()->RequiresHoleCheck()) {
3364 DeoptimizeIfRoot(result, Heap::kTheHoleValueRootIndex, instr); 3366 DeoptimizeIfRoot(result, Heap::kTheHoleValueRootIndex, instr, "hole");
3365 } 3367 }
3366 } 3368 }
3367 3369
3368 3370
3369 template <class T> 3371 template <class T>
3370 void LCodeGen::EmitVectorLoadICRegisters(T* instr) { 3372 void LCodeGen::EmitVectorLoadICRegisters(T* instr) {
3371 DCHECK(FLAG_vector_ics); 3373 DCHECK(FLAG_vector_ics);
3372 Register vector = ToRegister(instr->temp_vector()); 3374 Register vector = ToRegister(instr->temp_vector());
3373 DCHECK(vector.is(VectorLoadICDescriptor::VectorRegister())); 3375 DCHECK(vector.is(VectorLoadICDescriptor::VectorRegister()));
3374 __ Mov(vector, instr->hydrogen()->feedback_vector()); 3376 __ Mov(vector, instr->hydrogen()->feedback_vector());
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
3485 case EXTERNAL_INT32_ELEMENTS: 3487 case EXTERNAL_INT32_ELEMENTS:
3486 case INT32_ELEMENTS: 3488 case INT32_ELEMENTS:
3487 __ Ldrsw(result, mem_op); 3489 __ Ldrsw(result, mem_op);
3488 break; 3490 break;
3489 case EXTERNAL_UINT32_ELEMENTS: 3491 case EXTERNAL_UINT32_ELEMENTS:
3490 case UINT32_ELEMENTS: 3492 case UINT32_ELEMENTS:
3491 __ Ldr(result.W(), mem_op); 3493 __ Ldr(result.W(), mem_op);
3492 if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) { 3494 if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) {
3493 // Deopt if value > 0x80000000. 3495 // Deopt if value > 0x80000000.
3494 __ Tst(result, 0xFFFFFFFF80000000); 3496 __ Tst(result, 0xFFFFFFFF80000000);
3495 DeoptimizeIf(ne, instr); 3497 DeoptimizeIf(ne, instr, "negative value");
3496 } 3498 }
3497 break; 3499 break;
3498 case FLOAT32_ELEMENTS: 3500 case FLOAT32_ELEMENTS:
3499 case FLOAT64_ELEMENTS: 3501 case FLOAT64_ELEMENTS:
3500 case EXTERNAL_FLOAT32_ELEMENTS: 3502 case EXTERNAL_FLOAT32_ELEMENTS:
3501 case EXTERNAL_FLOAT64_ELEMENTS: 3503 case EXTERNAL_FLOAT64_ELEMENTS:
3502 case FAST_HOLEY_DOUBLE_ELEMENTS: 3504 case FAST_HOLEY_DOUBLE_ELEMENTS:
3503 case FAST_HOLEY_ELEMENTS: 3505 case FAST_HOLEY_ELEMENTS:
3504 case FAST_HOLEY_SMI_ELEMENTS: 3506 case FAST_HOLEY_SMI_ELEMENTS:
3505 case FAST_DOUBLE_ELEMENTS: 3507 case FAST_DOUBLE_ELEMENTS:
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
3582 3584
3583 __ Ldr(result, mem_op); 3585 __ Ldr(result, mem_op);
3584 3586
3585 if (instr->hydrogen()->RequiresHoleCheck()) { 3587 if (instr->hydrogen()->RequiresHoleCheck()) {
3586 Register scratch = ToRegister(instr->temp()); 3588 Register scratch = ToRegister(instr->temp());
3587 // Detect the hole NaN by adding one to the integer representation of the 3589 // Detect the hole NaN by adding one to the integer representation of the
3588 // result, and checking for overflow. 3590 // result, and checking for overflow.
3589 STATIC_ASSERT(kHoleNanInt64 == 0x7fffffffffffffff); 3591 STATIC_ASSERT(kHoleNanInt64 == 0x7fffffffffffffff);
3590 __ Ldr(scratch, mem_op); 3592 __ Ldr(scratch, mem_op);
3591 __ Cmn(scratch, 1); 3593 __ Cmn(scratch, 1);
3592 DeoptimizeIf(vs, instr); 3594 DeoptimizeIf(vs, instr, "hole");
3593 } 3595 }
3594 } 3596 }
3595 3597
3596 3598
3597 void LCodeGen::DoLoadKeyedFixed(LLoadKeyedFixed* instr) { 3599 void LCodeGen::DoLoadKeyedFixed(LLoadKeyedFixed* instr) {
3598 Register elements = ToRegister(instr->elements()); 3600 Register elements = ToRegister(instr->elements());
3599 Register result = ToRegister(instr->result()); 3601 Register result = ToRegister(instr->result());
3600 MemOperand mem_op; 3602 MemOperand mem_op;
3601 3603
3602 Representation representation = instr->hydrogen()->representation(); 3604 Representation representation = instr->hydrogen()->representation();
(...skipping 17 matching lines...) Expand all
3620 3622
3621 mem_op = PrepareKeyedArrayOperand(load_base, elements, key, key_is_tagged, 3623 mem_op = PrepareKeyedArrayOperand(load_base, elements, key, key_is_tagged,
3622 instr->hydrogen()->elements_kind(), 3624 instr->hydrogen()->elements_kind(),
3623 representation, instr->base_offset()); 3625 representation, instr->base_offset());
3624 } 3626 }
3625 3627
3626 __ Load(result, mem_op, representation); 3628 __ Load(result, mem_op, representation);
3627 3629
3628 if (instr->hydrogen()->RequiresHoleCheck()) { 3630 if (instr->hydrogen()->RequiresHoleCheck()) {
3629 if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) { 3631 if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) {
3630 DeoptimizeIfNotSmi(result, instr); 3632 DeoptimizeIfNotSmi(result, instr, "not a Smi");
3631 } else { 3633 } else {
3632 DeoptimizeIfRoot(result, Heap::kTheHoleValueRootIndex, instr); 3634 DeoptimizeIfRoot(result, Heap::kTheHoleValueRootIndex, instr, "hole");
3633 } 3635 }
3634 } 3636 }
3635 } 3637 }
3636 3638
3637 3639
3638 void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { 3640 void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
3639 DCHECK(ToRegister(instr->context()).is(cp)); 3641 DCHECK(ToRegister(instr->context()).is(cp));
3640 DCHECK(ToRegister(instr->object()).is(LoadDescriptor::ReceiverRegister())); 3642 DCHECK(ToRegister(instr->object()).is(LoadDescriptor::ReceiverRegister()));
3641 DCHECK(ToRegister(instr->key()).is(LoadDescriptor::NameRegister())); 3643 DCHECK(ToRegister(instr->key()).is(LoadDescriptor::NameRegister()));
3642 if (FLAG_vector_ics) { 3644 if (FLAG_vector_ics) {
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
3724 if (r.IsDouble()) { 3726 if (r.IsDouble()) {
3725 DoubleRegister input = ToDoubleRegister(instr->value()); 3727 DoubleRegister input = ToDoubleRegister(instr->value());
3726 DoubleRegister result = ToDoubleRegister(instr->result()); 3728 DoubleRegister result = ToDoubleRegister(instr->result());
3727 __ Fabs(result, input); 3729 __ Fabs(result, input);
3728 } else if (r.IsSmi() || r.IsInteger32()) { 3730 } else if (r.IsSmi() || r.IsInteger32()) {
3729 Register input = r.IsSmi() ? ToRegister(instr->value()) 3731 Register input = r.IsSmi() ? ToRegister(instr->value())
3730 : ToRegister32(instr->value()); 3732 : ToRegister32(instr->value());
3731 Register result = r.IsSmi() ? ToRegister(instr->result()) 3733 Register result = r.IsSmi() ? ToRegister(instr->result())
3732 : ToRegister32(instr->result()); 3734 : ToRegister32(instr->result());
3733 __ Abs(result, input); 3735 __ Abs(result, input);
3734 DeoptimizeIf(vs, instr); 3736 DeoptimizeIf(vs, instr, "overflow");
3735 } 3737 }
3736 } 3738 }
3737 3739
3738 3740
3739 void LCodeGen::DoDeferredMathAbsTagged(LMathAbsTagged* instr, 3741 void LCodeGen::DoDeferredMathAbsTagged(LMathAbsTagged* instr,
3740 Label* exit, 3742 Label* exit,
3741 Label* allocation_entry) { 3743 Label* allocation_entry) {
3742 // Handle the tricky cases of MathAbsTagged: 3744 // Handle the tricky cases of MathAbsTagged:
3743 // - HeapNumber inputs. 3745 // - HeapNumber inputs.
3744 // - Negative inputs produce a positive result, so a new HeapNumber is 3746 // - Negative inputs produce a positive result, so a new HeapNumber is
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
3876 3878
3877 __ Frintm(result, input); 3879 __ Frintm(result, input);
3878 } 3880 }
3879 3881
3880 3882
3881 void LCodeGen::DoMathFloorI(LMathFloorI* instr) { 3883 void LCodeGen::DoMathFloorI(LMathFloorI* instr) {
3882 DoubleRegister input = ToDoubleRegister(instr->value()); 3884 DoubleRegister input = ToDoubleRegister(instr->value());
3883 Register result = ToRegister(instr->result()); 3885 Register result = ToRegister(instr->result());
3884 3886
3885 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 3887 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3886 DeoptimizeIfMinusZero(input, instr); 3888 DeoptimizeIfMinusZero(input, instr, "minus zero");
3887 } 3889 }
3888 3890
3889 __ Fcvtms(result, input); 3891 __ Fcvtms(result, input);
3890 3892
3891 // Check that the result fits into a 32-bit integer. 3893 // Check that the result fits into a 32-bit integer.
3892 // - The result did not overflow. 3894 // - The result did not overflow.
3893 __ Cmp(result, Operand(result, SXTW)); 3895 __ Cmp(result, Operand(result, SXTW));
3894 // - The input was not NaN. 3896 // - The input was not NaN.
3895 __ Fccmp(input, input, NoFlag, eq); 3897 __ Fccmp(input, input, NoFlag, eq);
3896 DeoptimizeIf(ne, instr); 3898 DeoptimizeIf(ne, instr, "lost precision or NaN");
3897 } 3899 }
3898 3900
3899 3901
3900 void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) { 3902 void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) {
3901 Register dividend = ToRegister32(instr->dividend()); 3903 Register dividend = ToRegister32(instr->dividend());
3902 Register result = ToRegister32(instr->result()); 3904 Register result = ToRegister32(instr->result());
3903 int32_t divisor = instr->divisor(); 3905 int32_t divisor = instr->divisor();
3904 3906
3905 // If the divisor is 1, return the dividend. 3907 // If the divisor is 1, return the dividend.
3906 if (divisor == 1) { 3908 if (divisor == 1) {
3907 __ Mov(result, dividend, kDiscardForSameWReg); 3909 __ Mov(result, dividend, kDiscardForSameWReg);
3908 return; 3910 return;
3909 } 3911 }
3910 3912
3911 // If the divisor is positive, things are easy: There can be no deopts and we 3913 // If the divisor is positive, things are easy: There can be no deopts and we
3912 // can simply do an arithmetic right shift. 3914 // can simply do an arithmetic right shift.
3913 int32_t shift = WhichPowerOf2Abs(divisor); 3915 int32_t shift = WhichPowerOf2Abs(divisor);
3914 if (divisor > 1) { 3916 if (divisor > 1) {
3915 __ Mov(result, Operand(dividend, ASR, shift)); 3917 __ Mov(result, Operand(dividend, ASR, shift));
3916 return; 3918 return;
3917 } 3919 }
3918 3920
3919 // If the divisor is negative, we have to negate and handle edge cases. 3921 // If the divisor is negative, we have to negate and handle edge cases.
3920 __ Negs(result, dividend); 3922 __ Negs(result, dividend);
3921 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 3923 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3922 DeoptimizeIf(eq, instr); 3924 DeoptimizeIf(eq, instr, "minus zero");
3923 } 3925 }
3924 3926
3925 // Dividing by -1 is basically negation, unless we overflow. 3927 // Dividing by -1 is basically negation, unless we overflow.
3926 if (divisor == -1) { 3928 if (divisor == -1) {
3927 if (instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) { 3929 if (instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) {
3928 DeoptimizeIf(vs, instr); 3930 DeoptimizeIf(vs, instr, "overflow");
3929 } 3931 }
3930 return; 3932 return;
3931 } 3933 }
3932 3934
3933 // If the negation could not overflow, simply shifting is OK. 3935 // If the negation could not overflow, simply shifting is OK.
3934 if (!instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) { 3936 if (!instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) {
3935 __ Mov(result, Operand(dividend, ASR, shift)); 3937 __ Mov(result, Operand(dividend, ASR, shift));
3936 return; 3938 return;
3937 } 3939 }
3938 3940
3939 __ Asr(result, result, shift); 3941 __ Asr(result, result, shift);
3940 __ Csel(result, result, kMinInt / divisor, vc); 3942 __ Csel(result, result, kMinInt / divisor, vc);
3941 } 3943 }
3942 3944
3943 3945
3944 void LCodeGen::DoFlooringDivByConstI(LFlooringDivByConstI* instr) { 3946 void LCodeGen::DoFlooringDivByConstI(LFlooringDivByConstI* instr) {
3945 Register dividend = ToRegister32(instr->dividend()); 3947 Register dividend = ToRegister32(instr->dividend());
3946 int32_t divisor = instr->divisor(); 3948 int32_t divisor = instr->divisor();
3947 Register result = ToRegister32(instr->result()); 3949 Register result = ToRegister32(instr->result());
3948 DCHECK(!AreAliased(dividend, result)); 3950 DCHECK(!AreAliased(dividend, result));
3949 3951
3950 if (divisor == 0) { 3952 if (divisor == 0) {
3951 Deoptimize(instr); 3953 Deoptimize(instr, "division by zero");
3952 return; 3954 return;
3953 } 3955 }
3954 3956
3955 // Check for (0 / -x) that will produce negative zero. 3957 // Check for (0 / -x) that will produce negative zero.
3956 HMathFloorOfDiv* hdiv = instr->hydrogen(); 3958 HMathFloorOfDiv* hdiv = instr->hydrogen();
3957 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) { 3959 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) {
3958 DeoptimizeIfZero(dividend, instr); 3960 DeoptimizeIfZero(dividend, instr, "minus zero");
3959 } 3961 }
3960 3962
3961 // Easy case: We need no dynamic check for the dividend and the flooring 3963 // Easy case: We need no dynamic check for the dividend and the flooring
3962 // division is the same as the truncating division. 3964 // division is the same as the truncating division.
3963 if ((divisor > 0 && !hdiv->CheckFlag(HValue::kLeftCanBeNegative)) || 3965 if ((divisor > 0 && !hdiv->CheckFlag(HValue::kLeftCanBeNegative)) ||
3964 (divisor < 0 && !hdiv->CheckFlag(HValue::kLeftCanBePositive))) { 3966 (divisor < 0 && !hdiv->CheckFlag(HValue::kLeftCanBePositive))) {
3965 __ TruncatingDiv(result, dividend, Abs(divisor)); 3967 __ TruncatingDiv(result, dividend, Abs(divisor));
3966 if (divisor < 0) __ Neg(result, result); 3968 if (divisor < 0) __ Neg(result, result);
3967 return; 3969 return;
3968 } 3970 }
(...skipping 22 matching lines...) Expand all
3991 Register dividend = ToRegister32(instr->dividend()); 3993 Register dividend = ToRegister32(instr->dividend());
3992 Register divisor = ToRegister32(instr->divisor()); 3994 Register divisor = ToRegister32(instr->divisor());
3993 Register remainder = ToRegister32(instr->temp()); 3995 Register remainder = ToRegister32(instr->temp());
3994 Register result = ToRegister32(instr->result()); 3996 Register result = ToRegister32(instr->result());
3995 3997
3996 // This can't cause an exception on ARM, so we can speculatively 3998 // This can't cause an exception on ARM, so we can speculatively
3997 // execute it already now. 3999 // execute it already now.
3998 __ Sdiv(result, dividend, divisor); 4000 __ Sdiv(result, dividend, divisor);
3999 4001
4000 // Check for x / 0. 4002 // Check for x / 0.
4001 DeoptimizeIfZero(divisor, instr); 4003 DeoptimizeIfZero(divisor, instr, "division by zero");
4002 4004
4003 // Check for (kMinInt / -1). 4005 // Check for (kMinInt / -1).
4004 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { 4006 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
4005 // The V flag will be set iff dividend == kMinInt. 4007 // The V flag will be set iff dividend == kMinInt.
4006 __ Cmp(dividend, 1); 4008 __ Cmp(dividend, 1);
4007 __ Ccmp(divisor, -1, NoFlag, vs); 4009 __ Ccmp(divisor, -1, NoFlag, vs);
4008 DeoptimizeIf(eq, instr); 4010 DeoptimizeIf(eq, instr, "overflow");
4009 } 4011 }
4010 4012
4011 // Check for (0 / -x) that will produce negative zero. 4013 // Check for (0 / -x) that will produce negative zero.
4012 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 4014 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
4013 __ Cmp(divisor, 0); 4015 __ Cmp(divisor, 0);
4014 __ Ccmp(dividend, 0, ZFlag, mi); 4016 __ Ccmp(dividend, 0, ZFlag, mi);
4015 // "divisor" can't be null because the code would have already been 4017 // "divisor" can't be null because the code would have already been
4016 // deoptimized. The Z flag is set only if (divisor < 0) and (dividend == 0). 4018 // deoptimized. The Z flag is set only if (divisor < 0) and (dividend == 0).
4017 // In this case we need to deoptimize to produce a -0. 4019 // In this case we need to deoptimize to produce a -0.
4018 DeoptimizeIf(eq, instr); 4020 DeoptimizeIf(eq, instr, "minus zero");
4019 } 4021 }
4020 4022
4021 Label done; 4023 Label done;
4022 // If both operands have the same sign then we are done. 4024 // If both operands have the same sign then we are done.
4023 __ Eor(remainder, dividend, divisor); 4025 __ Eor(remainder, dividend, divisor);
4024 __ Tbz(remainder, kWSignBit, &done); 4026 __ Tbz(remainder, kWSignBit, &done);
4025 4027
4026 // Check if the result needs to be corrected. 4028 // Check if the result needs to be corrected.
4027 __ Msub(remainder, result, divisor, dividend); 4029 __ Msub(remainder, result, divisor, dividend);
4028 __ Cbz(remainder, &done); 4030 __ Cbz(remainder, &done);
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
4167 // result fits in 32 bits. 4169 // result fits in 32 bits.
4168 __ Cmp(result, Operand(result.W(), SXTW)); 4170 __ Cmp(result, Operand(result.W(), SXTW));
4169 __ Ccmp(result, 1, ZFlag, eq); 4171 __ Ccmp(result, 1, ZFlag, eq);
4170 __ B(hi, &done); 4172 __ B(hi, &done);
4171 4173
4172 // At this point, we have to handle possible inputs of NaN or numbers in the 4174 // At this point, we have to handle possible inputs of NaN or numbers in the
4173 // range [-0.5, 1.5[, or numbers larger than 32 bits. 4175 // range [-0.5, 1.5[, or numbers larger than 32 bits.
4174 4176
4175 // Deoptimize if the result > 1, as it must be larger than 32 bits. 4177 // Deoptimize if the result > 1, as it must be larger than 32 bits.
4176 __ Cmp(result, 1); 4178 __ Cmp(result, 1);
4177 DeoptimizeIf(hi, instr); 4179 DeoptimizeIf(hi, instr, "overflow");
4178 4180
4179 // Deoptimize for negative inputs, which at this point are only numbers in 4181 // Deoptimize for negative inputs, which at this point are only numbers in
4180 // the range [-0.5, -0.0] 4182 // the range [-0.5, -0.0]
4181 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 4183 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
4182 __ Fmov(result, input); 4184 __ Fmov(result, input);
4183 DeoptimizeIfNegative(result, instr); 4185 DeoptimizeIfNegative(result, instr, "minus zero");
4184 } 4186 }
4185 4187
4186 // Deoptimize if the input was NaN. 4188 // Deoptimize if the input was NaN.
4187 __ Fcmp(input, dot_five); 4189 __ Fcmp(input, dot_five);
4188 DeoptimizeIf(vs, instr); 4190 DeoptimizeIf(vs, instr, "NaN");
4189 4191
4190 // Now, the only unhandled inputs are in the range [0.0, 1.5[ (or [-0.5, 1.5[ 4192 // Now, the only unhandled inputs are in the range [0.0, 1.5[ (or [-0.5, 1.5[
4191 // if we didn't generate a -0.0 bailout). If input >= 0.5 then return 1, 4193 // if we didn't generate a -0.0 bailout). If input >= 0.5 then return 1,
4192 // else 0; we avoid dealing with 0.499...94 directly. 4194 // else 0; we avoid dealing with 0.499...94 directly.
4193 __ Cset(result, ge); 4195 __ Cset(result, ge);
4194 __ Bind(&done); 4196 __ Bind(&done);
4195 } 4197 }
4196 4198
4197 4199
4198 void LCodeGen::DoMathFround(LMathFround* instr) { 4200 void LCodeGen::DoMathFround(LMathFround* instr) {
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
4256 HMod* hmod = instr->hydrogen(); 4258 HMod* hmod = instr->hydrogen();
4257 int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1); 4259 int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1);
4258 Label dividend_is_not_negative, done; 4260 Label dividend_is_not_negative, done;
4259 if (hmod->CheckFlag(HValue::kLeftCanBeNegative)) { 4261 if (hmod->CheckFlag(HValue::kLeftCanBeNegative)) {
4260 __ Tbz(dividend, kWSignBit, &dividend_is_not_negative); 4262 __ Tbz(dividend, kWSignBit, &dividend_is_not_negative);
4261 // Note that this is correct even for kMinInt operands. 4263 // Note that this is correct even for kMinInt operands.
4262 __ Neg(dividend, dividend); 4264 __ Neg(dividend, dividend);
4263 __ And(dividend, dividend, mask); 4265 __ And(dividend, dividend, mask);
4264 __ Negs(dividend, dividend); 4266 __ Negs(dividend, dividend);
4265 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { 4267 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
4266 DeoptimizeIf(eq, instr); 4268 DeoptimizeIf(eq, instr, "minus zero");
4267 } 4269 }
4268 __ B(&done); 4270 __ B(&done);
4269 } 4271 }
4270 4272
4271 __ bind(&dividend_is_not_negative); 4273 __ bind(&dividend_is_not_negative);
4272 __ And(dividend, dividend, mask); 4274 __ And(dividend, dividend, mask);
4273 __ bind(&done); 4275 __ bind(&done);
4274 } 4276 }
4275 4277
4276 4278
4277 void LCodeGen::DoModByConstI(LModByConstI* instr) { 4279 void LCodeGen::DoModByConstI(LModByConstI* instr) {
4278 Register dividend = ToRegister32(instr->dividend()); 4280 Register dividend = ToRegister32(instr->dividend());
4279 int32_t divisor = instr->divisor(); 4281 int32_t divisor = instr->divisor();
4280 Register result = ToRegister32(instr->result()); 4282 Register result = ToRegister32(instr->result());
4281 Register temp = ToRegister32(instr->temp()); 4283 Register temp = ToRegister32(instr->temp());
4282 DCHECK(!AreAliased(dividend, result, temp)); 4284 DCHECK(!AreAliased(dividend, result, temp));
4283 4285
4284 if (divisor == 0) { 4286 if (divisor == 0) {
4285 Deoptimize(instr); 4287 Deoptimize(instr, "division by zero");
4286 return; 4288 return;
4287 } 4289 }
4288 4290
4289 __ TruncatingDiv(result, dividend, Abs(divisor)); 4291 __ TruncatingDiv(result, dividend, Abs(divisor));
4290 __ Sxtw(dividend.X(), dividend); 4292 __ Sxtw(dividend.X(), dividend);
4291 __ Mov(temp, Abs(divisor)); 4293 __ Mov(temp, Abs(divisor));
4292 __ Smsubl(result.X(), result, temp, dividend.X()); 4294 __ Smsubl(result.X(), result, temp, dividend.X());
4293 4295
4294 // Check for negative zero. 4296 // Check for negative zero.
4295 HMod* hmod = instr->hydrogen(); 4297 HMod* hmod = instr->hydrogen();
4296 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { 4298 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
4297 Label remainder_not_zero; 4299 Label remainder_not_zero;
4298 __ Cbnz(result, &remainder_not_zero); 4300 __ Cbnz(result, &remainder_not_zero);
4299 DeoptimizeIfNegative(dividend, instr); 4301 DeoptimizeIfNegative(dividend, instr, "minus zero");
4300 __ bind(&remainder_not_zero); 4302 __ bind(&remainder_not_zero);
4301 } 4303 }
4302 } 4304 }
4303 4305
4304 4306
4305 void LCodeGen::DoModI(LModI* instr) { 4307 void LCodeGen::DoModI(LModI* instr) {
4306 Register dividend = ToRegister32(instr->left()); 4308 Register dividend = ToRegister32(instr->left());
4307 Register divisor = ToRegister32(instr->right()); 4309 Register divisor = ToRegister32(instr->right());
4308 Register result = ToRegister32(instr->result()); 4310 Register result = ToRegister32(instr->result());
4309 4311
4310 Label done; 4312 Label done;
4311 // modulo = dividend - quotient * divisor 4313 // modulo = dividend - quotient * divisor
4312 __ Sdiv(result, dividend, divisor); 4314 __ Sdiv(result, dividend, divisor);
4313 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) { 4315 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
4314 DeoptimizeIfZero(divisor, instr); 4316 DeoptimizeIfZero(divisor, instr, "division by zero");
4315 } 4317 }
4316 __ Msub(result, result, divisor, dividend); 4318 __ Msub(result, result, divisor, dividend);
4317 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 4319 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
4318 __ Cbnz(result, &done); 4320 __ Cbnz(result, &done);
4319 DeoptimizeIfNegative(dividend, instr); 4321 DeoptimizeIfNegative(dividend, instr, "minus zero");
4320 } 4322 }
4321 __ Bind(&done); 4323 __ Bind(&done);
4322 } 4324 }
4323 4325
4324 4326
4325 void LCodeGen::DoMulConstIS(LMulConstIS* instr) { 4327 void LCodeGen::DoMulConstIS(LMulConstIS* instr) {
4326 DCHECK(instr->hydrogen()->representation().IsSmiOrInteger32()); 4328 DCHECK(instr->hydrogen()->representation().IsSmiOrInteger32());
4327 bool is_smi = instr->hydrogen()->representation().IsSmi(); 4329 bool is_smi = instr->hydrogen()->representation().IsSmi();
4328 Register result = 4330 Register result =
4329 is_smi ? ToRegister(instr->result()) : ToRegister32(instr->result()); 4331 is_smi ? ToRegister(instr->result()) : ToRegister32(instr->result());
4330 Register left = 4332 Register left =
4331 is_smi ? ToRegister(instr->left()) : ToRegister32(instr->left()) ; 4333 is_smi ? ToRegister(instr->left()) : ToRegister32(instr->left()) ;
4332 int32_t right = ToInteger32(instr->right()); 4334 int32_t right = ToInteger32(instr->right());
4333 DCHECK((right > -kMaxInt) || (right < kMaxInt)); 4335 DCHECK((right > -kMaxInt) || (right < kMaxInt));
4334 4336
4335 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); 4337 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
4336 bool bailout_on_minus_zero = 4338 bool bailout_on_minus_zero =
4337 instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero); 4339 instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero);
4338 4340
4339 if (bailout_on_minus_zero) { 4341 if (bailout_on_minus_zero) {
4340 if (right < 0) { 4342 if (right < 0) {
4341 // The result is -0 if right is negative and left is zero. 4343 // The result is -0 if right is negative and left is zero.
4342 DeoptimizeIfZero(left, instr); 4344 DeoptimizeIfZero(left, instr, "minus zero");
4343 } else if (right == 0) { 4345 } else if (right == 0) {
4344 // The result is -0 if the right is zero and the left is negative. 4346 // The result is -0 if the right is zero and the left is negative.
4345 DeoptimizeIfNegative(left, instr); 4347 DeoptimizeIfNegative(left, instr, "minus zero");
4346 } 4348 }
4347 } 4349 }
4348 4350
4349 switch (right) { 4351 switch (right) {
4350 // Cases which can detect overflow. 4352 // Cases which can detect overflow.
4351 case -1: 4353 case -1:
4352 if (can_overflow) { 4354 if (can_overflow) {
4353 // Only 0x80000000 can overflow here. 4355 // Only 0x80000000 can overflow here.
4354 __ Negs(result, left); 4356 __ Negs(result, left);
4355 DeoptimizeIf(vs, instr); 4357 DeoptimizeIf(vs, instr, "overflow");
4356 } else { 4358 } else {
4357 __ Neg(result, left); 4359 __ Neg(result, left);
4358 } 4360 }
4359 break; 4361 break;
4360 case 0: 4362 case 0:
4361 // This case can never overflow. 4363 // This case can never overflow.
4362 __ Mov(result, 0); 4364 __ Mov(result, 0);
4363 break; 4365 break;
4364 case 1: 4366 case 1:
4365 // This case can never overflow. 4367 // This case can never overflow.
4366 __ Mov(result, left, kDiscardForSameWReg); 4368 __ Mov(result, left, kDiscardForSameWReg);
4367 break; 4369 break;
4368 case 2: 4370 case 2:
4369 if (can_overflow) { 4371 if (can_overflow) {
4370 __ Adds(result, left, left); 4372 __ Adds(result, left, left);
4371 DeoptimizeIf(vs, instr); 4373 DeoptimizeIf(vs, instr, "overflow");
4372 } else { 4374 } else {
4373 __ Add(result, left, left); 4375 __ Add(result, left, left);
4374 } 4376 }
4375 break; 4377 break;
4376 4378
4377 default: 4379 default:
4378 // Multiplication by constant powers of two (and some related values) 4380 // Multiplication by constant powers of two (and some related values)
4379 // can be done efficiently with shifted operands. 4381 // can be done efficiently with shifted operands.
4380 int32_t right_abs = Abs(right); 4382 int32_t right_abs = Abs(right);
4381 4383
4382 if (base::bits::IsPowerOfTwo32(right_abs)) { 4384 if (base::bits::IsPowerOfTwo32(right_abs)) {
4383 int right_log2 = WhichPowerOf2(right_abs); 4385 int right_log2 = WhichPowerOf2(right_abs);
4384 4386
4385 if (can_overflow) { 4387 if (can_overflow) {
4386 Register scratch = result; 4388 Register scratch = result;
4387 DCHECK(!AreAliased(scratch, left)); 4389 DCHECK(!AreAliased(scratch, left));
4388 __ Cls(scratch, left); 4390 __ Cls(scratch, left);
4389 __ Cmp(scratch, right_log2); 4391 __ Cmp(scratch, right_log2);
4390 DeoptimizeIf(lt, instr); 4392 DeoptimizeIf(lt, instr, "overflow");
4391 } 4393 }
4392 4394
4393 if (right >= 0) { 4395 if (right >= 0) {
4394 // result = left << log2(right) 4396 // result = left << log2(right)
4395 __ Lsl(result, left, right_log2); 4397 __ Lsl(result, left, right_log2);
4396 } else { 4398 } else {
4397 // result = -left << log2(-right) 4399 // result = -left << log2(-right)
4398 if (can_overflow) { 4400 if (can_overflow) {
4399 __ Negs(result, Operand(left, LSL, right_log2)); 4401 __ Negs(result, Operand(left, LSL, right_log2));
4400 DeoptimizeIf(vs, instr); 4402 DeoptimizeIf(vs, instr, "overflow");
4401 } else { 4403 } else {
4402 __ Neg(result, Operand(left, LSL, right_log2)); 4404 __ Neg(result, Operand(left, LSL, right_log2));
4403 } 4405 }
4404 } 4406 }
4405 return; 4407 return;
4406 } 4408 }
4407 4409
4408 4410
4409 // For the following cases, we could perform a conservative overflow check 4411 // For the following cases, we could perform a conservative overflow check
4410 // with CLS as above. However the few cycles saved are likely not worth 4412 // with CLS as above. However the few cycles saved are likely not worth
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
4448 instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero); 4450 instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero);
4449 4451
4450 if (bailout_on_minus_zero && !left.Is(right)) { 4452 if (bailout_on_minus_zero && !left.Is(right)) {
4451 // If one operand is zero and the other is negative, the result is -0. 4453 // If one operand is zero and the other is negative, the result is -0.
4452 // - Set Z (eq) if either left or right, or both, are 0. 4454 // - Set Z (eq) if either left or right, or both, are 0.
4453 __ Cmp(left, 0); 4455 __ Cmp(left, 0);
4454 __ Ccmp(right, 0, ZFlag, ne); 4456 __ Ccmp(right, 0, ZFlag, ne);
4455 // - If so (eq), set N (mi) if left + right is negative. 4457 // - If so (eq), set N (mi) if left + right is negative.
4456 // - Otherwise, clear N. 4458 // - Otherwise, clear N.
4457 __ Ccmn(left, right, NoFlag, eq); 4459 __ Ccmn(left, right, NoFlag, eq);
4458 DeoptimizeIf(mi, instr); 4460 DeoptimizeIf(mi, instr, "minus zero");
4459 } 4461 }
4460 4462
4461 if (can_overflow) { 4463 if (can_overflow) {
4462 __ Smull(result.X(), left, right); 4464 __ Smull(result.X(), left, right);
4463 __ Cmp(result.X(), Operand(result, SXTW)); 4465 __ Cmp(result.X(), Operand(result, SXTW));
4464 DeoptimizeIf(ne, instr); 4466 DeoptimizeIf(ne, instr, "overflow");
4465 } else { 4467 } else {
4466 __ Mul(result, left, right); 4468 __ Mul(result, left, right);
4467 } 4469 }
4468 } 4470 }
4469 4471
4470 4472
4471 void LCodeGen::DoMulS(LMulS* instr) { 4473 void LCodeGen::DoMulS(LMulS* instr) {
4472 Register result = ToRegister(instr->result()); 4474 Register result = ToRegister(instr->result());
4473 Register left = ToRegister(instr->left()); 4475 Register left = ToRegister(instr->left());
4474 Register right = ToRegister(instr->right()); 4476 Register right = ToRegister(instr->right());
4475 4477
4476 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); 4478 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
4477 bool bailout_on_minus_zero = 4479 bool bailout_on_minus_zero =
4478 instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero); 4480 instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero);
4479 4481
4480 if (bailout_on_minus_zero && !left.Is(right)) { 4482 if (bailout_on_minus_zero && !left.Is(right)) {
4481 // If one operand is zero and the other is negative, the result is -0. 4483 // If one operand is zero and the other is negative, the result is -0.
4482 // - Set Z (eq) if either left or right, or both, are 0. 4484 // - Set Z (eq) if either left or right, or both, are 0.
4483 __ Cmp(left, 0); 4485 __ Cmp(left, 0);
4484 __ Ccmp(right, 0, ZFlag, ne); 4486 __ Ccmp(right, 0, ZFlag, ne);
4485 // - If so (eq), set N (mi) if left + right is negative. 4487 // - If so (eq), set N (mi) if left + right is negative.
4486 // - Otherwise, clear N. 4488 // - Otherwise, clear N.
4487 __ Ccmn(left, right, NoFlag, eq); 4489 __ Ccmn(left, right, NoFlag, eq);
4488 DeoptimizeIf(mi, instr); 4490 DeoptimizeIf(mi, instr, "minus zero");
4489 } 4491 }
4490 4492
4491 STATIC_ASSERT((kSmiShift == 32) && (kSmiTag == 0)); 4493 STATIC_ASSERT((kSmiShift == 32) && (kSmiTag == 0));
4492 if (can_overflow) { 4494 if (can_overflow) {
4493 __ Smulh(result, left, right); 4495 __ Smulh(result, left, right);
4494 __ Cmp(result, Operand(result.W(), SXTW)); 4496 __ Cmp(result, Operand(result.W(), SXTW));
4495 __ SmiTag(result); 4497 __ SmiTag(result);
4496 DeoptimizeIf(ne, instr); 4498 DeoptimizeIf(ne, instr, "overflow");
4497 } else { 4499 } else {
4498 if (AreAliased(result, left, right)) { 4500 if (AreAliased(result, left, right)) {
4499 // All three registers are the same: half untag the input and then 4501 // All three registers are the same: half untag the input and then
4500 // multiply, giving a tagged result. 4502 // multiply, giving a tagged result.
4501 STATIC_ASSERT((kSmiShift % 2) == 0); 4503 STATIC_ASSERT((kSmiShift % 2) == 0);
4502 __ Asr(result, left, kSmiShift / 2); 4504 __ Asr(result, left, kSmiShift / 2);
4503 __ Mul(result, result, result); 4505 __ Mul(result, result, result);
4504 } else if (result.Is(left) && !left.Is(right)) { 4506 } else if (result.Is(left) && !left.Is(right)) {
4505 // Registers result and left alias, right is distinct: untag left into 4507 // Registers result and left alias, right is distinct: untag left into
4506 // result, and then multiply by right, giving a tagged result. 4508 // result, and then multiply by right, giving a tagged result.
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after
4662 // Heap number map check. 4664 // Heap number map check.
4663 if (can_convert_undefined_to_nan) { 4665 if (can_convert_undefined_to_nan) {
4664 __ JumpIfNotHeapNumber(input, &convert_undefined); 4666 __ JumpIfNotHeapNumber(input, &convert_undefined);
4665 } else { 4667 } else {
4666 DeoptimizeIfNotHeapNumber(input, instr); 4668 DeoptimizeIfNotHeapNumber(input, instr);
4667 } 4669 }
4668 4670
4669 // Load heap number. 4671 // Load heap number.
4670 __ Ldr(result, FieldMemOperand(input, HeapNumber::kValueOffset)); 4672 __ Ldr(result, FieldMemOperand(input, HeapNumber::kValueOffset));
4671 if (instr->hydrogen()->deoptimize_on_minus_zero()) { 4673 if (instr->hydrogen()->deoptimize_on_minus_zero()) {
4672 DeoptimizeIfMinusZero(result, instr); 4674 DeoptimizeIfMinusZero(result, instr, "minus zero");
4673 } 4675 }
4674 __ B(&done); 4676 __ B(&done);
4675 4677
4676 if (can_convert_undefined_to_nan) { 4678 if (can_convert_undefined_to_nan) {
4677 __ Bind(&convert_undefined); 4679 __ Bind(&convert_undefined);
4678 DeoptimizeIfNotRoot(input, Heap::kUndefinedValueRootIndex, instr); 4680 DeoptimizeIfNotRoot(input, Heap::kUndefinedValueRootIndex, instr,
4681 "not a heap number/undefined");
4679 4682
4680 __ LoadRoot(scratch, Heap::kNanValueRootIndex); 4683 __ LoadRoot(scratch, Heap::kNanValueRootIndex);
4681 __ Ldr(result, FieldMemOperand(scratch, HeapNumber::kValueOffset)); 4684 __ Ldr(result, FieldMemOperand(scratch, HeapNumber::kValueOffset));
4682 __ B(&done); 4685 __ B(&done);
4683 } 4686 }
4684 4687
4685 } else { 4688 } else {
4686 DCHECK(mode == NUMBER_CANDIDATE_IS_SMI); 4689 DCHECK(mode == NUMBER_CANDIDATE_IS_SMI);
4687 // Fall through to load_smi. 4690 // Fall through to load_smi.
4688 } 4691 }
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after
4861 } 4864 }
4862 } 4865 }
4863 4866
4864 4867
4865 void LCodeGen::DoSmiTag(LSmiTag* instr) { 4868 void LCodeGen::DoSmiTag(LSmiTag* instr) {
4866 HChange* hchange = instr->hydrogen(); 4869 HChange* hchange = instr->hydrogen();
4867 Register input = ToRegister(instr->value()); 4870 Register input = ToRegister(instr->value());
4868 Register output = ToRegister(instr->result()); 4871 Register output = ToRegister(instr->result());
4869 if (hchange->CheckFlag(HValue::kCanOverflow) && 4872 if (hchange->CheckFlag(HValue::kCanOverflow) &&
4870 hchange->value()->CheckFlag(HValue::kUint32)) { 4873 hchange->value()->CheckFlag(HValue::kUint32)) {
4871 DeoptimizeIfNegative(input.W(), instr); 4874 DeoptimizeIfNegative(input.W(), instr, "overflow");
4872 } 4875 }
4873 __ SmiTag(output, input); 4876 __ SmiTag(output, input);
4874 } 4877 }
4875 4878
4876 4879
4877 void LCodeGen::DoSmiUntag(LSmiUntag* instr) { 4880 void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
4878 Register input = ToRegister(instr->value()); 4881 Register input = ToRegister(instr->value());
4879 Register result = ToRegister(instr->result()); 4882 Register result = ToRegister(instr->result());
4880 Label done, untag; 4883 Label done, untag;
4881 4884
4882 if (instr->needs_check()) { 4885 if (instr->needs_check()) {
4883 DeoptimizeIfNotSmi(input, instr); 4886 DeoptimizeIfNotSmi(input, instr, "not a Smi");
4884 } 4887 }
4885 4888
4886 __ Bind(&untag); 4889 __ Bind(&untag);
4887 __ SmiUntag(result, input); 4890 __ SmiUntag(result, input);
4888 __ Bind(&done); 4891 __ Bind(&done);
4889 } 4892 }
4890 4893
4891 4894
4892 void LCodeGen::DoShiftI(LShiftI* instr) { 4895 void LCodeGen::DoShiftI(LShiftI* instr) {
4893 LOperand* right_op = instr->right(); 4896 LOperand* right_op = instr->right();
4894 Register left = ToRegister32(instr->left()); 4897 Register left = ToRegister32(instr->left());
4895 Register result = ToRegister32(instr->result()); 4898 Register result = ToRegister32(instr->result());
4896 4899
4897 if (right_op->IsRegister()) { 4900 if (right_op->IsRegister()) {
4898 Register right = ToRegister32(instr->right()); 4901 Register right = ToRegister32(instr->right());
4899 switch (instr->op()) { 4902 switch (instr->op()) {
4900 case Token::ROR: __ Ror(result, left, right); break; 4903 case Token::ROR: __ Ror(result, left, right); break;
4901 case Token::SAR: __ Asr(result, left, right); break; 4904 case Token::SAR: __ Asr(result, left, right); break;
4902 case Token::SHL: __ Lsl(result, left, right); break; 4905 case Token::SHL: __ Lsl(result, left, right); break;
4903 case Token::SHR: 4906 case Token::SHR:
4904 __ Lsr(result, left, right); 4907 __ Lsr(result, left, right);
4905 if (instr->can_deopt()) { 4908 if (instr->can_deopt()) {
4906 // If `left >>> right` >= 0x80000000, the result is not representable 4909 // If `left >>> right` >= 0x80000000, the result is not representable
4907 // in a signed 32-bit smi. 4910 // in a signed 32-bit smi.
4908 DeoptimizeIfNegative(result, instr); 4911 DeoptimizeIfNegative(result, instr, "negative value");
4909 } 4912 }
4910 break; 4913 break;
4911 default: UNREACHABLE(); 4914 default: UNREACHABLE();
4912 } 4915 }
4913 } else { 4916 } else {
4914 DCHECK(right_op->IsConstantOperand()); 4917 DCHECK(right_op->IsConstantOperand());
4915 int shift_count = JSShiftAmountFromLConstant(right_op); 4918 int shift_count = JSShiftAmountFromLConstant(right_op);
4916 if (shift_count == 0) { 4919 if (shift_count == 0) {
4917 if ((instr->op() == Token::SHR) && instr->can_deopt()) { 4920 if ((instr->op() == Token::SHR) && instr->can_deopt()) {
4918 DeoptimizeIfNegative(left, instr); 4921 DeoptimizeIfNegative(left, instr, "negative value");
4919 } 4922 }
4920 __ Mov(result, left, kDiscardForSameWReg); 4923 __ Mov(result, left, kDiscardForSameWReg);
4921 } else { 4924 } else {
4922 switch (instr->op()) { 4925 switch (instr->op()) {
4923 case Token::ROR: __ Ror(result, left, shift_count); break; 4926 case Token::ROR: __ Ror(result, left, shift_count); break;
4924 case Token::SAR: __ Asr(result, left, shift_count); break; 4927 case Token::SAR: __ Asr(result, left, shift_count); break;
4925 case Token::SHL: __ Lsl(result, left, shift_count); break; 4928 case Token::SHL: __ Lsl(result, left, shift_count); break;
4926 case Token::SHR: __ Lsr(result, left, shift_count); break; 4929 case Token::SHR: __ Lsr(result, left, shift_count); break;
4927 default: UNREACHABLE(); 4930 default: UNREACHABLE();
4928 } 4931 }
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
4961 break; 4964 break;
4962 case Token::SHL: 4965 case Token::SHL:
4963 __ Lsl(result, left, result); 4966 __ Lsl(result, left, result);
4964 break; 4967 break;
4965 case Token::SHR: 4968 case Token::SHR:
4966 __ Lsr(result, left, result); 4969 __ Lsr(result, left, result);
4967 __ Bic(result, result, kSmiShiftMask); 4970 __ Bic(result, result, kSmiShiftMask);
4968 if (instr->can_deopt()) { 4971 if (instr->can_deopt()) {
4969 // If `left >>> right` >= 0x80000000, the result is not representable 4972 // If `left >>> right` >= 0x80000000, the result is not representable
4970 // in a signed 32-bit smi. 4973 // in a signed 32-bit smi.
4971 DeoptimizeIfNegative(result, instr); 4974 DeoptimizeIfNegative(result, instr, "negative value");
4972 } 4975 }
4973 break; 4976 break;
4974 default: UNREACHABLE(); 4977 default: UNREACHABLE();
4975 } 4978 }
4976 } else { 4979 } else {
4977 DCHECK(right_op->IsConstantOperand()); 4980 DCHECK(right_op->IsConstantOperand());
4978 int shift_count = JSShiftAmountFromLConstant(right_op); 4981 int shift_count = JSShiftAmountFromLConstant(right_op);
4979 if (shift_count == 0) { 4982 if (shift_count == 0) {
4980 if ((instr->op() == Token::SHR) && instr->can_deopt()) { 4983 if ((instr->op() == Token::SHR) && instr->can_deopt()) {
4981 DeoptimizeIfNegative(left, instr); 4984 DeoptimizeIfNegative(left, instr, "negative value");
4982 } 4985 }
4983 __ Mov(result, left); 4986 __ Mov(result, left);
4984 } else { 4987 } else {
4985 switch (instr->op()) { 4988 switch (instr->op()) {
4986 case Token::ROR: 4989 case Token::ROR:
4987 __ SmiUntag(result, left); 4990 __ SmiUntag(result, left);
4988 __ Ror(result.W(), result.W(), shift_count); 4991 __ Ror(result.W(), result.W(), shift_count);
4989 __ SmiTag(result); 4992 __ SmiTag(result);
4990 break; 4993 break;
4991 case Token::SAR: 4994 case Token::SAR:
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
5100 Register context = ToRegister(instr->context()); 5103 Register context = ToRegister(instr->context());
5101 Register value = ToRegister(instr->value()); 5104 Register value = ToRegister(instr->value());
5102 Register scratch = ToRegister(instr->temp()); 5105 Register scratch = ToRegister(instr->temp());
5103 MemOperand target = ContextMemOperand(context, instr->slot_index()); 5106 MemOperand target = ContextMemOperand(context, instr->slot_index());
5104 5107
5105 Label skip_assignment; 5108 Label skip_assignment;
5106 5109
5107 if (instr->hydrogen()->RequiresHoleCheck()) { 5110 if (instr->hydrogen()->RequiresHoleCheck()) {
5108 __ Ldr(scratch, target); 5111 __ Ldr(scratch, target);
5109 if (instr->hydrogen()->DeoptimizesOnHole()) { 5112 if (instr->hydrogen()->DeoptimizesOnHole()) {
5110 DeoptimizeIfRoot(scratch, Heap::kTheHoleValueRootIndex, instr); 5113 DeoptimizeIfRoot(scratch, Heap::kTheHoleValueRootIndex, instr, "hole");
5111 } else { 5114 } else {
5112 __ JumpIfNotRoot(scratch, Heap::kTheHoleValueRootIndex, &skip_assignment); 5115 __ JumpIfNotRoot(scratch, Heap::kTheHoleValueRootIndex, &skip_assignment);
5113 } 5116 }
5114 } 5117 }
5115 5118
5116 __ Str(value, target); 5119 __ Str(value, target);
5117 if (instr->hydrogen()->NeedsWriteBarrier()) { 5120 if (instr->hydrogen()->NeedsWriteBarrier()) {
5118 SmiCheck check_needed = 5121 SmiCheck check_needed =
5119 instr->hydrogen()->value()->type().IsHeapObject() 5122 instr->hydrogen()->value()->type().IsHeapObject()
5120 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; 5123 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
(...skipping 17 matching lines...) Expand all
5138 // Load the cell. 5141 // Load the cell.
5139 __ Mov(cell, Operand(instr->hydrogen()->cell().handle())); 5142 __ Mov(cell, Operand(instr->hydrogen()->cell().handle()));
5140 5143
5141 // If the cell we are storing to contains the hole it could have 5144 // If the cell we are storing to contains the hole it could have
5142 // been deleted from the property dictionary. In that case, we need 5145 // been deleted from the property dictionary. In that case, we need
5143 // to update the property details in the property dictionary to mark 5146 // to update the property details in the property dictionary to mark
5144 // it as no longer deleted. We deoptimize in that case. 5147 // it as no longer deleted. We deoptimize in that case.
5145 if (instr->hydrogen()->RequiresHoleCheck()) { 5148 if (instr->hydrogen()->RequiresHoleCheck()) {
5146 Register payload = ToRegister(instr->temp2()); 5149 Register payload = ToRegister(instr->temp2());
5147 __ Ldr(payload, FieldMemOperand(cell, Cell::kValueOffset)); 5150 __ Ldr(payload, FieldMemOperand(cell, Cell::kValueOffset));
5148 DeoptimizeIfRoot(payload, Heap::kTheHoleValueRootIndex, instr); 5151 DeoptimizeIfRoot(payload, Heap::kTheHoleValueRootIndex, instr, "hole");
5149 } 5152 }
5150 5153
5151 // Store the value. 5154 // Store the value.
5152 __ Str(value, FieldMemOperand(cell, Cell::kValueOffset)); 5155 __ Str(value, FieldMemOperand(cell, Cell::kValueOffset));
5153 // Cells are always rescanned, so no write barrier here. 5156 // Cells are always rescanned, so no write barrier here.
5154 } 5157 }
5155 5158
5156 5159
5157 void LCodeGen::DoStoreKeyedExternal(LStoreKeyedExternal* instr) { 5160 void LCodeGen::DoStoreKeyedExternal(LStoreKeyedExternal* instr) {
5158 Register ext_ptr = ToRegister(instr->elements()); 5161 Register ext_ptr = ToRegister(instr->elements());
(...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after
5555 5558
5556 5559
5557 void LCodeGen::DoSubI(LSubI* instr) { 5560 void LCodeGen::DoSubI(LSubI* instr) {
5558 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); 5561 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
5559 Register result = ToRegister32(instr->result()); 5562 Register result = ToRegister32(instr->result());
5560 Register left = ToRegister32(instr->left()); 5563 Register left = ToRegister32(instr->left());
5561 Operand right = ToShiftedRightOperand32(instr->right(), instr); 5564 Operand right = ToShiftedRightOperand32(instr->right(), instr);
5562 5565
5563 if (can_overflow) { 5566 if (can_overflow) {
5564 __ Subs(result, left, right); 5567 __ Subs(result, left, right);
5565 DeoptimizeIf(vs, instr); 5568 DeoptimizeIf(vs, instr, "overflow");
5566 } else { 5569 } else {
5567 __ Sub(result, left, right); 5570 __ Sub(result, left, right);
5568 } 5571 }
5569 } 5572 }
5570 5573
5571 5574
5572 void LCodeGen::DoSubS(LSubS* instr) { 5575 void LCodeGen::DoSubS(LSubS* instr) {
5573 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); 5576 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
5574 Register result = ToRegister(instr->result()); 5577 Register result = ToRegister(instr->result());
5575 Register left = ToRegister(instr->left()); 5578 Register left = ToRegister(instr->left());
5576 Operand right = ToOperand(instr->right()); 5579 Operand right = ToOperand(instr->right());
5577 if (can_overflow) { 5580 if (can_overflow) {
5578 __ Subs(result, left, right); 5581 __ Subs(result, left, right);
5579 DeoptimizeIf(vs, instr); 5582 DeoptimizeIf(vs, instr, "overflow");
5580 } else { 5583 } else {
5581 __ Sub(result, left, right); 5584 __ Sub(result, left, right);
5582 } 5585 }
5583 } 5586 }
5584 5587
5585 5588
5586 void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr, 5589 void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr,
5587 LOperand* value, 5590 LOperand* value,
5588 LOperand* temp1, 5591 LOperand* temp1,
5589 LOperand* temp2) { 5592 LOperand* temp2) {
(...skipping 19 matching lines...) Expand all
5609 Register true_root = output; 5612 Register true_root = output;
5610 Register false_root = scratch1; 5613 Register false_root = scratch1;
5611 __ LoadTrueFalseRoots(true_root, false_root); 5614 __ LoadTrueFalseRoots(true_root, false_root);
5612 __ Cmp(input, true_root); 5615 __ Cmp(input, true_root);
5613 __ Cset(output, eq); 5616 __ Cset(output, eq);
5614 __ Ccmp(input, false_root, ZFlag, ne); 5617 __ Ccmp(input, false_root, ZFlag, ne);
5615 __ B(eq, &done); 5618 __ B(eq, &done);
5616 5619
5617 // Output contains zero, undefined is converted to zero for truncating 5620 // Output contains zero, undefined is converted to zero for truncating
5618 // conversions. 5621 // conversions.
5619 DeoptimizeIfNotRoot(input, Heap::kUndefinedValueRootIndex, instr); 5622 DeoptimizeIfNotRoot(input, Heap::kUndefinedValueRootIndex, instr,
5623 "not a heap number/undefined/true/false");
5620 } else { 5624 } else {
5621 Register output = ToRegister32(instr->result()); 5625 Register output = ToRegister32(instr->result());
5622 DoubleRegister dbl_scratch2 = ToDoubleRegister(temp2); 5626 DoubleRegister dbl_scratch2 = ToDoubleRegister(temp2);
5623 5627
5624 DeoptimizeIfNotHeapNumber(input, instr); 5628 DeoptimizeIfNotHeapNumber(input, instr);
5625 5629
5626 // A heap number: load value and convert to int32 using non-truncating 5630 // A heap number: load value and convert to int32 using non-truncating
5627 // function. If the result is out of range, branch to deoptimize. 5631 // function. If the result is out of range, branch to deoptimize.
5628 __ Ldr(dbl_scratch1, FieldMemOperand(input, HeapNumber::kValueOffset)); 5632 __ Ldr(dbl_scratch1, FieldMemOperand(input, HeapNumber::kValueOffset));
5629 __ TryRepresentDoubleAsInt32(output, dbl_scratch1, dbl_scratch2); 5633 __ TryRepresentDoubleAsInt32(output, dbl_scratch1, dbl_scratch2);
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
5767 } 5771 }
5768 5772
5769 5773
5770 void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) { 5774 void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) {
5771 Register object = ToRegister(instr->object()); 5775 Register object = ToRegister(instr->object());
5772 Register temp1 = ToRegister(instr->temp1()); 5776 Register temp1 = ToRegister(instr->temp1());
5773 Register temp2 = ToRegister(instr->temp2()); 5777 Register temp2 = ToRegister(instr->temp2());
5774 5778
5775 Label no_memento_found; 5779 Label no_memento_found;
5776 __ TestJSArrayForAllocationMemento(object, temp1, temp2, &no_memento_found); 5780 __ TestJSArrayForAllocationMemento(object, temp1, temp2, &no_memento_found);
5777 DeoptimizeIf(eq, instr); 5781 DeoptimizeIf(eq, instr, "memento found");
5778 __ Bind(&no_memento_found); 5782 __ Bind(&no_memento_found);
5779 } 5783 }
5780 5784
5781 5785
5782 void LCodeGen::DoTruncateDoubleToIntOrSmi(LTruncateDoubleToIntOrSmi* instr) { 5786 void LCodeGen::DoTruncateDoubleToIntOrSmi(LTruncateDoubleToIntOrSmi* instr) {
5783 DoubleRegister input = ToDoubleRegister(instr->value()); 5787 DoubleRegister input = ToDoubleRegister(instr->value());
5784 Register result = ToRegister(instr->result()); 5788 Register result = ToRegister(instr->result());
5785 __ TruncateDoubleToI(result, input); 5789 __ TruncateDoubleToI(result, input);
5786 if (instr->tag_result()) { 5790 if (instr->tag_result()) {
5787 __ SmiTag(result, result); 5791 __ SmiTag(result, result);
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
5892 __ Ucvtf(ToDoubleRegister(instr->result()), ToRegister32(instr->value())); 5896 __ Ucvtf(ToDoubleRegister(instr->result()), ToRegister32(instr->value()));
5893 } 5897 }
5894 5898
5895 5899
5896 void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) { 5900 void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) {
5897 Register object = ToRegister(instr->value()); 5901 Register object = ToRegister(instr->value());
5898 Register map = ToRegister(instr->map()); 5902 Register map = ToRegister(instr->map());
5899 Register temp = ToRegister(instr->temp()); 5903 Register temp = ToRegister(instr->temp());
5900 __ Ldr(temp, FieldMemOperand(object, HeapObject::kMapOffset)); 5904 __ Ldr(temp, FieldMemOperand(object, HeapObject::kMapOffset));
5901 __ Cmp(map, temp); 5905 __ Cmp(map, temp);
5902 DeoptimizeIf(ne, instr); 5906 DeoptimizeIf(ne, instr, "wrong map");
5903 } 5907 }
5904 5908
5905 5909
5906 void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) { 5910 void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
5907 Register receiver = ToRegister(instr->receiver()); 5911 Register receiver = ToRegister(instr->receiver());
5908 Register function = ToRegister(instr->function()); 5912 Register function = ToRegister(instr->function());
5909 Register result = ToRegister(instr->result()); 5913 Register result = ToRegister(instr->result());
5910 5914
5911 // If the receiver is null or undefined, we have to pass the global object as 5915 // If the receiver is null or undefined, we have to pass the global object as
5912 // a receiver to normal functions. Values have to be passed unchanged to 5916 // a receiver to normal functions. Values have to be passed unchanged to
(...skipping 13 matching lines...) Expand all
5926 5930
5927 // Do not transform the receiver to object for builtins. 5931 // Do not transform the receiver to object for builtins.
5928 __ Tbnz(result, SharedFunctionInfo::kNative, &copy_receiver); 5932 __ Tbnz(result, SharedFunctionInfo::kNative, &copy_receiver);
5929 } 5933 }
5930 5934
5931 // Normal function. Replace undefined or null with global receiver. 5935 // Normal function. Replace undefined or null with global receiver.
5932 __ JumpIfRoot(receiver, Heap::kNullValueRootIndex, &global_object); 5936 __ JumpIfRoot(receiver, Heap::kNullValueRootIndex, &global_object);
5933 __ JumpIfRoot(receiver, Heap::kUndefinedValueRootIndex, &global_object); 5937 __ JumpIfRoot(receiver, Heap::kUndefinedValueRootIndex, &global_object);
5934 5938
5935 // Deoptimize if the receiver is not a JS object. 5939 // Deoptimize if the receiver is not a JS object.
5936 DeoptimizeIfSmi(receiver, instr); 5940 DeoptimizeIfSmi(receiver, instr, "Smi");
5937 __ CompareObjectType(receiver, result, result, FIRST_SPEC_OBJECT_TYPE); 5941 __ CompareObjectType(receiver, result, result, FIRST_SPEC_OBJECT_TYPE);
5938 __ B(ge, &copy_receiver); 5942 __ B(ge, &copy_receiver);
5939 Deoptimize(instr); 5943 Deoptimize(instr, "not a JavaScript object");
5940 5944
5941 __ Bind(&global_object); 5945 __ Bind(&global_object);
5942 __ Ldr(result, FieldMemOperand(function, JSFunction::kContextOffset)); 5946 __ Ldr(result, FieldMemOperand(function, JSFunction::kContextOffset));
5943 __ Ldr(result, ContextMemOperand(result, Context::GLOBAL_OBJECT_INDEX)); 5947 __ Ldr(result, ContextMemOperand(result, Context::GLOBAL_OBJECT_INDEX));
5944 __ Ldr(result, FieldMemOperand(result, GlobalObject::kGlobalProxyOffset)); 5948 __ Ldr(result, FieldMemOperand(result, GlobalObject::kGlobalProxyOffset));
5945 __ B(&done); 5949 __ B(&done);
5946 5950
5947 __ Bind(&copy_receiver); 5951 __ Bind(&copy_receiver);
5948 __ Mov(result, receiver); 5952 __ Mov(result, receiver);
5949 __ Bind(&done); 5953 __ Bind(&done);
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
6035 Handle<ScopeInfo> scope_info = instr->scope_info(); 6039 Handle<ScopeInfo> scope_info = instr->scope_info();
6036 __ Push(scope_info); 6040 __ Push(scope_info);
6037 __ Push(ToRegister(instr->function())); 6041 __ Push(ToRegister(instr->function()));
6038 CallRuntime(Runtime::kPushBlockContext, 2, instr); 6042 CallRuntime(Runtime::kPushBlockContext, 2, instr);
6039 RecordSafepoint(Safepoint::kNoLazyDeopt); 6043 RecordSafepoint(Safepoint::kNoLazyDeopt);
6040 } 6044 }
6041 6045
6042 6046
6043 6047
6044 } } // namespace v8::internal 6048 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/arm64/lithium-codegen-arm64.h ('k') | src/mips/lithium-codegen-mips.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698