| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 208 | 208 |
| 209 virtual void EmitInverted(Label* label) const { | 209 virtual void EmitInverted(Label* label) const { |
| 210 __ JumpIfNotHeapNumber(value_, label); | 210 __ JumpIfNotHeapNumber(value_, label); |
| 211 } | 211 } |
| 212 | 212 |
| 213 private: | 213 private: |
| 214 const Register& value_; | 214 const Register& value_; |
| 215 }; | 215 }; |
| 216 | 216 |
| 217 | 217 |
| 218 // Test the input and branch if it is the specified root value. |
| 219 class BranchIfRoot : public BranchGenerator { |
| 220 public: |
| 221 BranchIfRoot(LCodeGen* codegen, const Register& value, |
| 222 Heap::RootListIndex index) |
| 223 : BranchGenerator(codegen), value_(value), index_(index) { } |
| 224 |
| 225 virtual void Emit(Label* label) const { |
| 226 __ JumpIfRoot(value_, index_, label); |
| 227 } |
| 228 |
| 229 virtual void EmitInverted(Label* label) const { |
| 230 __ JumpIfNotRoot(value_, index_, label); |
| 231 } |
| 232 |
| 233 private: |
| 234 const Register& value_; |
| 235 const Heap::RootListIndex index_; |
| 236 }; |
| 237 |
| 238 |
| 218 void LCodeGen::WriteTranslation(LEnvironment* environment, | 239 void LCodeGen::WriteTranslation(LEnvironment* environment, |
| 219 Translation* translation) { | 240 Translation* translation) { |
| 220 if (environment == NULL) return; | 241 if (environment == NULL) return; |
| 221 | 242 |
| 222 // The translation includes one command per value in the environment. | 243 // The translation includes one command per value in the environment. |
| 223 int translation_size = environment->translation_size(); | 244 int translation_size = environment->translation_size(); |
| 224 // The output frame height does not include the parameters. | 245 // The output frame height does not include the parameters. |
| 225 int height = translation_size - environment->parameter_count(); | 246 int height = translation_size - environment->parameter_count(); |
| 226 | 247 |
| 227 WriteTranslation(environment->outer(), translation); | 248 WriteTranslation(environment->outer(), translation); |
| (...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 562 | 583 |
| 563 void LCodeGen::RecordSafepoint(Safepoint::DeoptMode deopt_mode) { | 584 void LCodeGen::RecordSafepoint(Safepoint::DeoptMode deopt_mode) { |
| 564 LPointerMap empty_pointers(RelocInfo::kNoPosition, zone()); | 585 LPointerMap empty_pointers(RelocInfo::kNoPosition, zone()); |
| 565 RecordSafepoint(&empty_pointers, deopt_mode); | 586 RecordSafepoint(&empty_pointers, deopt_mode); |
| 566 } | 587 } |
| 567 | 588 |
| 568 | 589 |
| 569 void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers, | 590 void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers, |
| 570 int arguments, | 591 int arguments, |
| 571 Safepoint::DeoptMode deopt_mode) { | 592 Safepoint::DeoptMode deopt_mode) { |
| 572 RecordSafepoint( | 593 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, deopt_mode); |
| 573 pointers, Safepoint::kWithRegisters, arguments, deopt_mode); | |
| 574 } | 594 } |
| 575 | 595 |
| 576 | 596 |
| 597 void LCodeGen::RecordSafepointWithRegistersAndDoubles( |
| 598 LPointerMap* pointers, int arguments, Safepoint::DeoptMode deopt_mode) { |
| 599 RecordSafepoint( |
| 600 pointers, Safepoint::kWithRegistersAndDoubles, arguments, deopt_mode); |
| 601 } |
| 602 |
| 603 |
| 577 bool LCodeGen::GenerateCode() { | 604 bool LCodeGen::GenerateCode() { |
| 578 LPhase phase("Z_Code generation", chunk()); | 605 LPhase phase("Z_Code generation", chunk()); |
| 579 ASSERT(is_unused()); | 606 ASSERT(is_unused()); |
| 580 status_ = GENERATING; | 607 status_ = GENERATING; |
| 581 | 608 |
| 582 // Open a frame scope to indicate that there is a frame on the stack. The | 609 // Open a frame scope to indicate that there is a frame on the stack. The |
| 583 // NONE indicates that the scope shouldn't actually generate code to set up | 610 // NONE indicates that the scope shouldn't actually generate code to set up |
| 584 // the frame (that is done in GeneratePrologue). | 611 // the frame (that is done in GeneratePrologue). |
| 585 FrameScope frame_scope(masm_, StackFrame::NONE); | 612 FrameScope frame_scope(masm_, StackFrame::NONE); |
| 586 | 613 |
| (...skipping 699 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1286 | 1313 |
| 1287 | 1314 |
| 1288 template<class InstrType> | 1315 template<class InstrType> |
| 1289 void LCodeGen::EmitBranchIfHeapNumber(InstrType instr, | 1316 void LCodeGen::EmitBranchIfHeapNumber(InstrType instr, |
| 1290 const Register& value) { | 1317 const Register& value) { |
| 1291 BranchIfHeapNumber branch(this, value); | 1318 BranchIfHeapNumber branch(this, value); |
| 1292 EmitBranchGeneric(instr, branch); | 1319 EmitBranchGeneric(instr, branch); |
| 1293 } | 1320 } |
| 1294 | 1321 |
| 1295 | 1322 |
| 1323 template<class InstrType> |
| 1324 void LCodeGen::EmitBranchIfRoot(InstrType instr, |
| 1325 const Register& value, |
| 1326 Heap::RootListIndex index) { |
| 1327 BranchIfRoot branch(this, value, index); |
| 1328 EmitBranchGeneric(instr, branch); |
| 1329 } |
| 1330 |
| 1331 |
| 1296 void LCodeGen::DoGap(LGap* gap) { | 1332 void LCodeGen::DoGap(LGap* gap) { |
| 1297 for (int i = LGap::FIRST_INNER_POSITION; | 1333 for (int i = LGap::FIRST_INNER_POSITION; |
| 1298 i <= LGap::LAST_INNER_POSITION; | 1334 i <= LGap::LAST_INNER_POSITION; |
| 1299 i++) { | 1335 i++) { |
| 1300 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i); | 1336 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i); |
| 1301 LParallelMove* move = gap->GetParallelMove(inner_pos); | 1337 LParallelMove* move = gap->GetParallelMove(inner_pos); |
| 1302 if (move != NULL) { | 1338 if (move != NULL) { |
| 1303 resolver_.Resolve(move); | 1339 resolver_.Resolve(move); |
| 1304 } | 1340 } |
| 1305 } | 1341 } |
| (...skipping 913 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2219 // The class name we are testing against is internalized since it's a literal. | 2255 // The class name we are testing against is internalized since it's a literal. |
| 2220 // The name in the constructor is internalized because of the way the context | 2256 // The name in the constructor is internalized because of the way the context |
| 2221 // is booted. This routine isn't expected to work for random API-created | 2257 // is booted. This routine isn't expected to work for random API-created |
| 2222 // classes and it doesn't have to because you can't access it with natives | 2258 // classes and it doesn't have to because you can't access it with natives |
| 2223 // syntax. Since both sides are internalized it is sufficient to use an | 2259 // syntax. Since both sides are internalized it is sufficient to use an |
| 2224 // identity comparison. | 2260 // identity comparison. |
| 2225 EmitCompareAndBranch(instr, eq, scratch1, Operand(class_name)); | 2261 EmitCompareAndBranch(instr, eq, scratch1, Operand(class_name)); |
| 2226 } | 2262 } |
| 2227 | 2263 |
| 2228 | 2264 |
| 2265 void LCodeGen::DoCmpHoleAndBranchD(LCmpHoleAndBranchD* instr) { |
| 2266 ASSERT(instr->hydrogen()->representation().IsDouble()); |
| 2267 FPRegister object = ToDoubleRegister(instr->object()); |
| 2268 Register temp = ToRegister(instr->temp()); |
| 2269 |
| 2270 // If we don't have a NaN, we don't have the hole, so branch now to avoid the |
| 2271 // (relatively expensive) hole-NaN check. |
| 2272 __ Fcmp(object, object); |
| 2273 __ B(vc, instr->FalseLabel(chunk_)); |
| 2274 |
| 2275 // We have a NaN, but is it the hole? |
| 2276 __ Fmov(temp, object); |
| 2277 EmitCompareAndBranch(instr, eq, temp, kHoleNanInt64); |
| 2278 } |
| 2279 |
| 2280 |
| 2281 void LCodeGen::DoCmpHoleAndBranchT(LCmpHoleAndBranchT* instr) { |
| 2282 ASSERT(instr->hydrogen()->representation().IsTagged()); |
| 2283 Register object = ToRegister(instr->object()); |
| 2284 |
| 2285 EmitBranchIfRoot(instr, object, Heap::kTheHoleValueRootIndex); |
| 2286 } |
| 2287 |
| 2288 |
| 2229 void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { | 2289 void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { |
| 2230 Register value = ToRegister(instr->value()); | 2290 Register value = ToRegister(instr->value()); |
| 2231 Register map = ToRegister(instr->temp()); | 2291 Register map = ToRegister(instr->temp()); |
| 2232 | 2292 |
| 2233 __ Ldr(map, FieldMemOperand(value, HeapObject::kMapOffset)); | 2293 __ Ldr(map, FieldMemOperand(value, HeapObject::kMapOffset)); |
| 2234 EmitCompareAndBranch(instr, eq, map, Operand(instr->map())); | 2294 EmitCompareAndBranch(instr, eq, map, Operand(instr->map())); |
| 2235 } | 2295 } |
| 2236 | 2296 |
| 2237 | 2297 |
| 2238 void LCodeGen::DoCompareNumericAndBranch(LCompareNumericAndBranch* instr) { | 2298 void LCodeGen::DoCompareNumericAndBranch(LCompareNumericAndBranch* instr) { |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2375 } | 2435 } |
| 2376 } | 2436 } |
| 2377 | 2437 |
| 2378 | 2438 |
| 2379 void LCodeGen::DoCheckFunction(LCheckFunction* instr) { | 2439 void LCodeGen::DoCheckFunction(LCheckFunction* instr) { |
| 2380 Register reg = ToRegister(instr->value()); | 2440 Register reg = ToRegister(instr->value()); |
| 2381 Handle<JSFunction> target = instr->hydrogen()->target(); | 2441 Handle<JSFunction> target = instr->hydrogen()->target(); |
| 2382 AllowDeferredHandleDereference smi_check; | 2442 AllowDeferredHandleDereference smi_check; |
| 2383 if (isolate()->heap()->InNewSpace(*target)) { | 2443 if (isolate()->heap()->InNewSpace(*target)) { |
| 2384 Register temp = ToRegister(instr->temp()); | 2444 Register temp = ToRegister(instr->temp()); |
| 2385 Handle<Cell> cell = isolate()->factory()->NewPropertyCell(target); | 2445 Handle<Cell> cell = isolate()->factory()->NewCell(target); |
| 2386 __ Mov(temp, Operand(Handle<Object>(cell))); | 2446 __ Mov(temp, Operand(Handle<Object>(cell))); |
| 2387 __ Ldr(temp, FieldMemOperand(temp, Cell::kValueOffset)); | 2447 __ Ldr(temp, FieldMemOperand(temp, Cell::kValueOffset)); |
| 2388 __ Cmp(reg, temp); | 2448 __ Cmp(reg, temp); |
| 2389 } else { | 2449 } else { |
| 2390 __ Cmp(reg, Operand(target)); | 2450 __ Cmp(reg, Operand(target)); |
| 2391 } | 2451 } |
| 2392 DeoptimizeIf(ne, instr->environment()); | 2452 DeoptimizeIf(ne, instr->environment()); |
| 2393 } | 2453 } |
| 2394 | 2454 |
| 2395 | 2455 |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2448 | 2508 |
| 2449 void LCodeGen::DoDeoptimize(LDeoptimize* instr) { | 2509 void LCodeGen::DoDeoptimize(LDeoptimize* instr) { |
| 2450 Deoptimizer::BailoutType type = instr->hydrogen()->type(); | 2510 Deoptimizer::BailoutType type = instr->hydrogen()->type(); |
| 2451 // TODO(danno): Stubs expect all deopts to be lazy for historical reasons (the | 2511 // TODO(danno): Stubs expect all deopts to be lazy for historical reasons (the |
| 2452 // needed return address), even though the implementation of LAZY and EAGER is | 2512 // needed return address), even though the implementation of LAZY and EAGER is |
| 2453 // now identical. When LAZY is eventually completely folded into EAGER, remove | 2513 // now identical. When LAZY is eventually completely folded into EAGER, remove |
| 2454 // the special case below. | 2514 // the special case below. |
| 2455 if (info()->IsStub() && (type == Deoptimizer::EAGER)) { | 2515 if (info()->IsStub() && (type == Deoptimizer::EAGER)) { |
| 2456 type = Deoptimizer::LAZY; | 2516 type = Deoptimizer::LAZY; |
| 2457 } | 2517 } |
| 2518 |
| 2519 Comment(";;; deoptimize: %s", instr->hydrogen()->reason()); |
| 2458 Deoptimize(instr->environment(), type); | 2520 Deoptimize(instr->environment(), type); |
| 2459 } | 2521 } |
| 2460 | 2522 |
| 2461 | 2523 |
| 2462 void LCodeGen::DoDivI(LDivI* instr) { | 2524 void LCodeGen::DoDivI(LDivI* instr) { |
| 2463 Register dividend = ToRegister32(instr->left()); | 2525 Register dividend = ToRegister32(instr->left()); |
| 2464 Register result = ToRegister32(instr->result()); | 2526 Register result = ToRegister32(instr->result()); |
| 2465 | 2527 |
| 2466 bool has_power_of_2_divisor = instr->hydrogen()->HasPowerOf2Divisor(); | 2528 bool has_power_of_2_divisor = instr->hydrogen()->HasPowerOf2Divisor(); |
| 2467 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); | 2529 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); |
| (...skipping 1008 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3476 if (access.IsInobject()) { | 3538 if (access.IsInobject()) { |
| 3477 __ Ldr(result, FieldMemOperand(object, offset)); | 3539 __ Ldr(result, FieldMemOperand(object, offset)); |
| 3478 } else { | 3540 } else { |
| 3479 __ Ldr(result, FieldMemOperand(object, JSObject::kPropertiesOffset)); | 3541 __ Ldr(result, FieldMemOperand(object, JSObject::kPropertiesOffset)); |
| 3480 __ Ldr(result, FieldMemOperand(result, offset)); | 3542 __ Ldr(result, FieldMemOperand(result, offset)); |
| 3481 } | 3543 } |
| 3482 } | 3544 } |
| 3483 } | 3545 } |
| 3484 | 3546 |
| 3485 | 3547 |
| 3486 void LCodeGen::EmitLoadFieldOrConstantFunction(Register result, | |
| 3487 Register object, | |
| 3488 Handle<Map> type, | |
| 3489 Handle<String> name, | |
| 3490 LEnvironment* env) { | |
| 3491 LookupResult lookup(isolate()); | |
| 3492 type->LookupDescriptor(NULL, *name, &lookup); | |
| 3493 ASSERT(lookup.IsFound() || lookup.IsCacheable()); | |
| 3494 | |
| 3495 if (lookup.IsField()) { | |
| 3496 int index = lookup.GetLocalFieldIndexFromMap(*type); | |
| 3497 int offset = index * kPointerSize; | |
| 3498 if (index < 0) { | |
| 3499 // Negative property indices are in-object properties, indexed from the | |
| 3500 // end of the fixed part of the object. | |
| 3501 __ Ldr(result, FieldMemOperand(object, offset + type->instance_size())); | |
| 3502 } else { | |
| 3503 // Non-negative property indices are in the properties array. | |
| 3504 __ Ldr(result, FieldMemOperand(object, JSObject::kPropertiesOffset)); | |
| 3505 __ Ldr(result, FieldMemOperand(result, offset + FixedArray::kHeaderSize)); | |
| 3506 } | |
| 3507 } else if (lookup.IsConstant()) { | |
| 3508 Handle<Object> constant(lookup.GetConstantFromMap(*type), isolate()); | |
| 3509 __ LoadObject(result, constant); | |
| 3510 } else { | |
| 3511 // Negative lookup. Check prototypes. | |
| 3512 Handle<HeapObject> current(HeapObject::cast((*type)->prototype())); | |
| 3513 Heap* heap = type->GetHeap(); | |
| 3514 while (*current != heap->null_value()) { | |
| 3515 __ LoadHeapObject(result, current); | |
| 3516 __ CompareMap(result, result, Handle<Map>(current->map())); | |
| 3517 DeoptimizeIf(ne, env); | |
| 3518 current = | |
| 3519 Handle<HeapObject>(HeapObject::cast(current->map()->prototype())); | |
| 3520 } | |
| 3521 __ LoadRoot(result, Heap::kUndefinedValueRootIndex); | |
| 3522 } | |
| 3523 } | |
| 3524 | |
| 3525 | |
| 3526 void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) { | |
| 3527 Register object = ToRegister(instr->object()); | |
| 3528 Register result = ToRegister(instr->result()); | |
| 3529 // The result register is loaded with its value when the object's map has been | |
| 3530 // found. At this point we don't need to hold the map in object_map anymore, | |
| 3531 // so both values can share the same register. | |
| 3532 // However when we need to go through the generic code path, the instruction | |
| 3533 // is MarkedAsCall and both object and result registers will be allocated to | |
| 3534 // x0. Object should not be clobbered until the call to LoadIC. We choose a | |
| 3535 // different arbitrary register for object_map in this case. | |
| 3536 Register object_map = instr->IsMarkedAsCall() | |
| 3537 ? x10 | |
| 3538 : result; | |
| 3539 | |
| 3540 int map_count = instr->hydrogen()->types()->length(); | |
| 3541 bool need_generic = instr->hydrogen()->need_generic(); | |
| 3542 | |
| 3543 if ((map_count == 0) && !need_generic) { | |
| 3544 Deoptimize(instr->environment()); | |
| 3545 return; | |
| 3546 } | |
| 3547 | |
| 3548 Handle<String> name = instr->hydrogen()->name(); | |
| 3549 Label done; | |
| 3550 __ Ldr(object_map, FieldMemOperand(object, HeapObject::kMapOffset)); | |
| 3551 for (int i = 0; i < map_count; i++) { | |
| 3552 bool last = (i == (map_count - 1)); | |
| 3553 Handle<Map> map = instr->hydrogen()->types()->at(i); | |
| 3554 Label check_passed; | |
| 3555 __ CompareMap(object_map, map, &check_passed); | |
| 3556 if (last && !need_generic) { | |
| 3557 DeoptimizeIf(ne, instr->environment()); | |
| 3558 __ Bind(&check_passed); | |
| 3559 EmitLoadFieldOrConstantFunction(result, object, map, name, | |
| 3560 instr->environment()); | |
| 3561 } else { | |
| 3562 Label next; | |
| 3563 __ B(ne, &next); | |
| 3564 __ Bind(&check_passed); | |
| 3565 EmitLoadFieldOrConstantFunction(result, object, map, name, | |
| 3566 instr->environment()); | |
| 3567 __ B(&done); | |
| 3568 __ Bind(&next); | |
| 3569 } | |
| 3570 } | |
| 3571 if (need_generic) { | |
| 3572 ASSERT(instr->IsMarkedAsCall()); | |
| 3573 // LoadIC expects x2 to hold the name, and x0 to hold the receiver. | |
| 3574 ASSERT(object.Is(x0)); | |
| 3575 __ Mov(x2, Operand(name)); | |
| 3576 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | |
| 3577 CallCode(ic, RelocInfo::CODE_TARGET, instr); | |
| 3578 } | |
| 3579 __ Bind(&done); | |
| 3580 } | |
| 3581 | |
| 3582 | |
| 3583 void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { | 3548 void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { |
| 3584 // LoadIC expects x2 to hold the name, and x0 to hold the receiver. | 3549 // LoadIC expects x2 to hold the name, and x0 to hold the receiver. |
| 3585 ASSERT(ToRegister(instr->object()).is(x0)); | 3550 ASSERT(ToRegister(instr->object()).is(x0)); |
| 3586 __ Mov(x2, Operand(instr->name())); | 3551 __ Mov(x2, Operand(instr->name())); |
| 3587 | 3552 |
| 3588 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | 3553 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); |
| 3589 CallCode(ic, RelocInfo::CODE_TARGET, instr); | 3554 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 3590 | 3555 |
| 3591 ASSERT(ToRegister(instr->result()).is(x0)); | 3556 ASSERT(ToRegister(instr->result()).is(x0)); |
| 3592 } | 3557 } |
| (...skipping 738 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4331 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); } | 4296 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); } |
| 4332 virtual LInstruction* instr() { return instr_; } | 4297 virtual LInstruction* instr() { return instr_; } |
| 4333 private: | 4298 private: |
| 4334 LNumberTagD* instr_; | 4299 LNumberTagD* instr_; |
| 4335 }; | 4300 }; |
| 4336 | 4301 |
| 4337 DoubleRegister input = ToDoubleRegister(instr->value()); | 4302 DoubleRegister input = ToDoubleRegister(instr->value()); |
| 4338 Register result = ToRegister(instr->result()); | 4303 Register result = ToRegister(instr->result()); |
| 4339 Register temp1 = ToRegister(instr->temp1()); | 4304 Register temp1 = ToRegister(instr->temp1()); |
| 4340 Register temp2 = ToRegister(instr->temp2()); | 4305 Register temp2 = ToRegister(instr->temp2()); |
| 4341 Label done; | |
| 4342 | |
| 4343 bool convert_hole = false; | |
| 4344 HValue* change_input = instr->hydrogen()->value(); | |
| 4345 if (change_input->IsLoadKeyed()) { | |
| 4346 HLoadKeyed* load = HLoadKeyed::cast(change_input); | |
| 4347 convert_hole = load->UsesMustHandleHole(); | |
| 4348 } | |
| 4349 | |
| 4350 if (convert_hole) { | |
| 4351 Label no_special_nan_handling, canonicalize; | |
| 4352 // TODO(jbramley): This special case does not exist in bleeding_edge. | |
| 4353 // * Non-NaN inputs are handled as usual. | |
| 4354 // * If the input is the hole, the output is the hole. | |
| 4355 // * If the input is any other NaN, the output is the canonical NaN. | |
| 4356 __ Fcmp(input, 0.0); | |
| 4357 __ B(vc, &no_special_nan_handling); | |
| 4358 __ Fmov(temp1, input); | |
| 4359 __ Cmp(temp1, kHoleNanInt64); | |
| 4360 __ B(ne, &canonicalize); | |
| 4361 __ Mov(result, Operand(factory()->the_hole_value())); | |
| 4362 __ B(&done); | |
| 4363 __ Bind(&canonicalize); | |
| 4364 // TODO(jbramley): Overwriting the input is probably a mistake, but this | |
| 4365 // code is removed in bleeding_edge anyway so it won't be here for long. | |
| 4366 TODO_UNIMPLEMENTED("DoNumberTagD: Fix NaN canonicalization logic."); | |
| 4367 __ Fmov(input, FixedDoubleArray::canonical_not_the_hole_nan_as_double()); | |
| 4368 __ Bind(&no_special_nan_handling); | |
| 4369 } | |
| 4370 | 4306 |
| 4371 DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr); | 4307 DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr); |
| 4372 if (FLAG_inline_new) { | 4308 if (FLAG_inline_new) { |
| 4373 __ AllocateHeapNumber(result, deferred->entry(), temp1, temp2); | 4309 __ AllocateHeapNumber(result, deferred->entry(), temp1, temp2); |
| 4374 } else { | 4310 } else { |
| 4375 __ B(deferred->entry()); | 4311 __ B(deferred->entry()); |
| 4376 } | 4312 } |
| 4377 | 4313 |
| 4378 __ Bind(deferred->exit()); | 4314 __ Bind(deferred->exit()); |
| 4379 __ Str(input, FieldMemOperand(result, HeapNumber::kValueOffset)); | 4315 __ Str(input, FieldMemOperand(result, HeapNumber::kValueOffset)); |
| 4380 __ Bind(&done); | |
| 4381 } | 4316 } |
| 4382 | 4317 |
| 4383 | 4318 |
| 4384 void LCodeGen::DoDeferredNumberTagU(LInstruction* instr, | 4319 void LCodeGen::DoDeferredNumberTagU(LInstruction* instr, |
| 4385 LOperand* value, | 4320 LOperand* value, |
| 4386 LOperand* temp1, | 4321 LOperand* temp1, |
| 4387 LOperand* temp2) { | 4322 LOperand* temp2) { |
| 4388 Label slow, convert_and_store; | 4323 Label slow, convert_and_store; |
| 4389 Register src = ToRegister32(value); | 4324 Register src = ToRegister32(value); |
| 4390 Register dst = ToRegister(instr->result()); | 4325 Register dst = ToRegister(instr->result()); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4453 __ B(hi, deferred->entry()); | 4388 __ B(hi, deferred->entry()); |
| 4454 __ SmiTag(result, value); | 4389 __ SmiTag(result, value); |
| 4455 __ Bind(deferred->exit()); | 4390 __ Bind(deferred->exit()); |
| 4456 } | 4391 } |
| 4457 | 4392 |
| 4458 | 4393 |
| 4459 void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { | 4394 void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { |
| 4460 Register input = ToRegister(instr->value()); | 4395 Register input = ToRegister(instr->value()); |
| 4461 Register scratch = ToRegister(instr->temp()); | 4396 Register scratch = ToRegister(instr->temp()); |
| 4462 DoubleRegister result = ToDoubleRegister(instr->result()); | 4397 DoubleRegister result = ToDoubleRegister(instr->result()); |
| 4463 bool allow_undefined_as_nan = instr->hydrogen()->allow_undefined_as_nan(); | 4398 bool can_convert_undefined_to_nan = |
| 4399 instr->hydrogen()->can_convert_undefined_to_nan(); |
| 4464 | 4400 |
| 4465 Label done, load_smi; | 4401 Label done, load_smi; |
| 4466 | 4402 |
| 4467 // Work out what untag mode we're working with. | 4403 // Work out what untag mode we're working with. |
| 4468 NumberUntagDMode mode = NUMBER_CANDIDATE_IS_ANY_TAGGED; | |
| 4469 HValue* value = instr->hydrogen()->value(); | 4404 HValue* value = instr->hydrogen()->value(); |
| 4470 if (value->type().IsSmi()) { | 4405 NumberUntagDMode mode = value->representation().IsSmi() |
| 4471 mode = NUMBER_CANDIDATE_IS_SMI; | 4406 ? NUMBER_CANDIDATE_IS_SMI : NUMBER_CANDIDATE_IS_ANY_TAGGED; |
| 4472 } else if (value->IsLoadKeyed()) { | |
| 4473 HLoadKeyed* load = HLoadKeyed::cast(value); | |
| 4474 if (load->UsesMustHandleHole()) { | |
| 4475 if (load->hole_mode() == ALLOW_RETURN_HOLE) { | |
| 4476 mode = NUMBER_CANDIDATE_IS_ANY_TAGGED_CONVERT_HOLE; | |
| 4477 } | |
| 4478 } | |
| 4479 } | |
| 4480 | 4407 |
| 4481 STATIC_ASSERT(NUMBER_CANDIDATE_IS_ANY_TAGGED_CONVERT_HOLE > | 4408 if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) { |
| 4482 NUMBER_CANDIDATE_IS_ANY_TAGGED); | |
| 4483 if (mode >= NUMBER_CANDIDATE_IS_ANY_TAGGED) { | |
| 4484 __ JumpIfSmi(input, &load_smi); | 4409 __ JumpIfSmi(input, &load_smi); |
| 4485 | 4410 |
| 4486 Label convert_undefined, deopt; | 4411 Label convert_undefined, deopt; |
| 4487 | 4412 |
| 4488 // Heap number map check. | 4413 // Heap number map check. |
| 4489 Label* not_heap_number = allow_undefined_as_nan ? &convert_undefined | 4414 Label* not_heap_number = can_convert_undefined_to_nan ? &convert_undefined |
| 4490 : &deopt; | 4415 : &deopt; |
| 4491 __ Ldr(scratch, FieldMemOperand(input, HeapObject::kMapOffset)); | 4416 __ Ldr(scratch, FieldMemOperand(input, HeapObject::kMapOffset)); |
| 4492 __ JumpIfNotRoot(scratch, Heap::kHeapNumberMapRootIndex, not_heap_number); | 4417 __ JumpIfNotRoot(scratch, Heap::kHeapNumberMapRootIndex, not_heap_number); |
| 4493 | 4418 |
| 4494 // Load heap number. | 4419 // Load heap number. |
| 4495 __ Ldr(result, FieldMemOperand(input, HeapNumber::kValueOffset)); | 4420 __ Ldr(result, FieldMemOperand(input, HeapNumber::kValueOffset)); |
| 4496 if (instr->hydrogen()->deoptimize_on_minus_zero()) { | 4421 if (instr->hydrogen()->deoptimize_on_minus_zero()) { |
| 4497 __ JumpIfMinusZero(result, &deopt); | 4422 __ JumpIfMinusZero(result, &deopt); |
| 4498 } | 4423 } |
| 4499 __ B(&done); | 4424 __ B(&done); |
| 4500 | 4425 |
| 4501 if (allow_undefined_as_nan) { | 4426 if (can_convert_undefined_to_nan) { |
| 4502 Label load_nan; | 4427 __ Bind(&convert_undefined); |
| 4428 __ JumpIfNotRoot(input, Heap::kUndefinedValueRootIndex, &deopt); |
| 4503 | 4429 |
| 4504 __ Bind(&convert_undefined); | |
| 4505 // Convert undefined (and hole) to NaN. | |
| 4506 if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED_CONVERT_HOLE) { | |
| 4507 __ JumpIfRoot(input, Heap::kUndefinedValueRootIndex, &load_nan); | |
| 4508 __ JumpIfNotRoot(input, Heap::kTheHoleValueRootIndex, &deopt); | |
| 4509 } else { | |
| 4510 ASSERT(mode == NUMBER_CANDIDATE_IS_ANY_TAGGED); | |
| 4511 __ JumpIfNotRoot(input, Heap::kUndefinedValueRootIndex, &deopt); | |
| 4512 } | |
| 4513 | |
| 4514 __ Bind(&load_nan); | |
| 4515 __ LoadRoot(scratch, Heap::kNanValueRootIndex); | 4430 __ LoadRoot(scratch, Heap::kNanValueRootIndex); |
| 4516 __ Ldr(result, FieldMemOperand(scratch, HeapNumber::kValueOffset)); | 4431 __ Ldr(result, FieldMemOperand(scratch, HeapNumber::kValueOffset)); |
| 4517 __ B(&done); | 4432 __ B(&done); |
| 4518 } | 4433 } |
| 4519 | 4434 |
| 4520 __ Bind(&deopt); | 4435 __ Bind(&deopt); |
| 4521 Deoptimize(instr->environment()); | 4436 Deoptimize(instr->environment()); |
| 4522 } else { | 4437 } else { |
| 4523 ASSERT(mode == NUMBER_CANDIDATE_IS_SMI); | 4438 ASSERT(mode == NUMBER_CANDIDATE_IS_SMI); |
| 4524 // Fall through to load_smi. | 4439 // Fall through to load_smi. |
| (...skipping 895 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5420 __ CheckMap(object, temp1, from_map, ¬_applicable, DONT_DO_SMI_CHECK); | 5335 __ CheckMap(object, temp1, from_map, ¬_applicable, DONT_DO_SMI_CHECK); |
| 5421 | 5336 |
| 5422 if (IsSimpleMapChangeTransition(from_kind, to_kind)) { | 5337 if (IsSimpleMapChangeTransition(from_kind, to_kind)) { |
| 5423 Register new_map = ToRegister(instr->temp2()); | 5338 Register new_map = ToRegister(instr->temp2()); |
| 5424 __ Mov(new_map, Operand(to_map)); | 5339 __ Mov(new_map, Operand(to_map)); |
| 5425 __ Str(new_map, FieldMemOperand(object, HeapObject::kMapOffset)); | 5340 __ Str(new_map, FieldMemOperand(object, HeapObject::kMapOffset)); |
| 5426 // Write barrier. | 5341 // Write barrier. |
| 5427 __ RecordWriteField(object, HeapObject::kMapOffset, new_map, temp1, | 5342 __ RecordWriteField(object, HeapObject::kMapOffset, new_map, temp1, |
| 5428 GetLinkRegisterState(), kDontSaveFPRegs); | 5343 GetLinkRegisterState(), kDontSaveFPRegs); |
| 5429 } else { | 5344 } else { |
| 5430 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); | 5345 PushSafepointRegistersScope scope( |
| 5346 this, Safepoint::kWithRegistersAndDoubles); |
| 5431 __ Mov(x0, object); | 5347 __ Mov(x0, object); |
| 5432 __ Mov(x1, Operand(to_map)); | 5348 __ Mov(x1, Operand(to_map)); |
| 5433 TransitionElementsKindStub stub(from_kind, to_kind); | 5349 TransitionElementsKindStub stub(from_kind, to_kind); |
| 5434 __ CallStub(&stub); | 5350 __ CallStub(&stub); |
| 5435 RecordSafepointWithRegisters( | 5351 RecordSafepointWithRegistersAndDoubles( |
| 5436 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt); | 5352 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt); |
| 5437 } | 5353 } |
| 5438 __ Bind(¬_applicable); | 5354 __ Bind(¬_applicable); |
| 5439 } | 5355 } |
| 5440 | 5356 |
| 5441 | 5357 |
| 5442 void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) { | 5358 void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) { |
| 5443 Register object = ToRegister(instr->object()); | 5359 Register object = ToRegister(instr->object()); |
| 5444 Register temp1 = ToRegister(instr->temp1()); | 5360 Register temp1 = ToRegister(instr->temp1()); |
| 5445 Register temp2 = ToRegister(instr->temp2()); | 5361 Register temp2 = ToRegister(instr->temp2()); |
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5662 __ Bind(&out_of_object); | 5578 __ Bind(&out_of_object); |
| 5663 __ Ldr(result, FieldMemOperand(object, JSObject::kPropertiesOffset)); | 5579 __ Ldr(result, FieldMemOperand(object, JSObject::kPropertiesOffset)); |
| 5664 // Index is equal to negated out of object property index plus 1. | 5580 // Index is equal to negated out of object property index plus 1. |
| 5665 __ Sub(result, result, Operand::UntagSmiAndScale(index, kPointerSizeLog2)); | 5581 __ Sub(result, result, Operand::UntagSmiAndScale(index, kPointerSizeLog2)); |
| 5666 __ Ldr(result, FieldMemOperand(result, | 5582 __ Ldr(result, FieldMemOperand(result, |
| 5667 FixedArray::kHeaderSize - kPointerSize)); | 5583 FixedArray::kHeaderSize - kPointerSize)); |
| 5668 __ Bind(&done); | 5584 __ Bind(&done); |
| 5669 } | 5585 } |
| 5670 | 5586 |
| 5671 } } // namespace v8::internal | 5587 } } // namespace v8::internal |
| OLD | NEW |