| 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 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 70 public: | 70 public: |
| 71 BranchOnCondition(LCodeGen* codegen, Condition cond) | 71 BranchOnCondition(LCodeGen* codegen, Condition cond) |
| 72 : BranchGenerator(codegen), | 72 : BranchGenerator(codegen), |
| 73 cond_(cond) { } | 73 cond_(cond) { } |
| 74 | 74 |
| 75 virtual void Emit(Label* label) const { | 75 virtual void Emit(Label* label) const { |
| 76 __ B(cond_, label); | 76 __ B(cond_, label); |
| 77 } | 77 } |
| 78 | 78 |
| 79 virtual void EmitInverted(Label* label) const { | 79 virtual void EmitInverted(Label* label) const { |
| 80 __ B(InvertCondition(cond_), label); | 80 if (cond_ != al) { |
| 81 __ B(InvertCondition(cond_), label); |
| 82 } |
| 81 } | 83 } |
| 82 | 84 |
| 83 private: | 85 private: |
| 84 Condition cond_; | 86 Condition cond_; |
| 85 }; | 87 }; |
| 86 | 88 |
| 87 | 89 |
| 88 // Emit code to compare lhs and rhs and branch if the condition holds. | 90 // Emit code to compare lhs and rhs and branch if the condition holds. |
| 89 // This uses MacroAssembler's CompareAndBranch function so it will handle | 91 // This uses MacroAssembler's CompareAndBranch function so it will handle |
| 90 // converting the comparison to Cbz/Cbnz if the right-hand side is 0. | 92 // converting the comparison to Cbz/Cbnz if the right-hand side is 0. |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 160 } | 162 } |
| 161 } | 163 } |
| 162 | 164 |
| 163 private: | 165 private: |
| 164 Condition cond_; | 166 Condition cond_; |
| 165 const Register& value_; | 167 const Register& value_; |
| 166 uint64_t mask_; | 168 uint64_t mask_; |
| 167 }; | 169 }; |
| 168 | 170 |
| 169 | 171 |
| 172 // Test the input and branch if it is non-zero and not a NaN. |
| 173 class BranchIfNonZeroNumber : public BranchGenerator { |
| 174 public: |
| 175 BranchIfNonZeroNumber(LCodeGen* codegen, const FPRegister& value, |
| 176 const FPRegister& scratch) |
| 177 : BranchGenerator(codegen), value_(value), scratch_(scratch) { } |
| 178 |
| 179 virtual void Emit(Label* label) const { |
| 180 __ Fabs(scratch_, value_); |
| 181 // Compare with 0.0. Because scratch_ is positive, the result can be one of |
| 182 // nZCv (equal), nzCv (greater) or nzCV (unordered). |
| 183 __ Fcmp(scratch_, 0.0); |
| 184 __ B(gt, label); |
| 185 } |
| 186 |
| 187 virtual void EmitInverted(Label* label) const { |
| 188 __ Fabs(scratch_, value_); |
| 189 __ Fcmp(scratch_, 0.0); |
| 190 __ B(le, label); |
| 191 } |
| 192 |
| 193 private: |
| 194 const FPRegister& value_; |
| 195 const FPRegister& scratch_; |
| 196 }; |
| 197 |
| 198 |
| 170 void LCodeGen::WriteTranslation(LEnvironment* environment, | 199 void LCodeGen::WriteTranslation(LEnvironment* environment, |
| 171 Translation* translation) { | 200 Translation* translation) { |
| 172 if (environment == NULL) return; | 201 if (environment == NULL) return; |
| 173 | 202 |
| 174 // The translation includes one command per value in the environment. | 203 // The translation includes one command per value in the environment. |
| 175 int translation_size = environment->translation_size(); | 204 int translation_size = environment->translation_size(); |
| 176 // The output frame height does not include the parameters. | 205 // The output frame height does not include the parameters. |
| 177 int height = translation_size - environment->parameter_count(); | 206 int height = translation_size - environment->parameter_count(); |
| 178 | 207 |
| 179 WriteTranslation(environment->outer(), translation); | 208 WriteTranslation(environment->outer(), translation); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 205 break; | 234 break; |
| 206 case ARGUMENTS_ADAPTOR: | 235 case ARGUMENTS_ADAPTOR: |
| 207 translation->BeginArgumentsAdaptorFrame(closure_id, translation_size); | 236 translation->BeginArgumentsAdaptorFrame(closure_id, translation_size); |
| 208 break; | 237 break; |
| 209 default: | 238 default: |
| 210 UNREACHABLE(); | 239 UNREACHABLE(); |
| 211 } | 240 } |
| 212 | 241 |
| 213 for (int i = 0; i < translation_size; ++i) { | 242 for (int i = 0; i < translation_size; ++i) { |
| 214 LOperand* value = environment->values()->at(i); | 243 LOperand* value = environment->values()->at(i); |
| 215 // spilled_registers_ and spilled_double_registers_ are either | |
| 216 // both NULL or both set. | |
| 217 if ((environment->spilled_registers() != NULL) && (value != NULL)) { | |
| 218 if (value->IsRegister() && | |
| 219 (environment->spilled_registers()[value->index()] != NULL)) { | |
| 220 translation->MarkDuplicate(); | |
| 221 AddToTranslation(translation, | |
| 222 environment->spilled_registers()[value->index()], | |
| 223 environment->HasTaggedValueAt(i), | |
| 224 environment->HasUint32ValueAt(i)); | |
| 225 } else if ( | |
| 226 value->IsDoubleRegister() && | |
| 227 (environment->spilled_double_registers()[value->index()] != NULL)) { | |
| 228 translation->MarkDuplicate(); | |
| 229 AddToTranslation( | |
| 230 translation, | |
| 231 environment->spilled_double_registers()[value->index()], | |
| 232 false, | |
| 233 false); | |
| 234 } | |
| 235 } | |
| 236 | 244 |
| 237 // TODO(mstarzinger): Introduce marker operands to indicate that this value | 245 // TODO(mstarzinger): Introduce marker operands to indicate that this value |
| 238 // is not present and must be reconstructed from the deoptimizer. Currently | 246 // is not present and must be reconstructed from the deoptimizer. Currently |
| 239 // this is only used for the arguments object. | 247 // this is only used for the arguments object. |
| 240 if (value == NULL) { | 248 if (value == NULL) { |
| 241 int arguments_count = environment->values()->length() - translation_size; | 249 int arguments_count = environment->values()->length() - translation_size; |
| 242 translation->BeginArgumentsObject(arguments_count); | 250 translation->BeginArgumentsObject(arguments_count); |
| 243 for (int i = 0; i < arguments_count; ++i) { | 251 for (int i = 0; i < arguments_count; ++i) { |
| 244 LOperand* value = environment->values()->at(translation_size + i); | 252 LOperand* value = environment->values()->at(translation_size + i); |
| 245 ASSERT(environment->spilled_registers() == NULL || | |
| 246 !value->IsRegister() || | |
| 247 environment->spilled_registers()[value->index()] == NULL); | |
| 248 ASSERT(environment->spilled_registers() == NULL || | |
| 249 !value->IsDoubleRegister() || | |
| 250 environment->spilled_double_registers()[value->index()] == NULL); | |
| 251 AddToTranslation(translation, | 253 AddToTranslation(translation, |
| 252 value, | 254 value, |
| 253 environment->HasTaggedValueAt(translation_size + i), | 255 environment->HasTaggedValueAt(translation_size + i), |
| 254 environment->HasUint32ValueAt(translation_size + i)); | 256 environment->HasUint32ValueAt(translation_size + i)); |
| 255 } | 257 } |
| 256 continue; | 258 continue; |
| 257 } | 259 } |
| 258 | 260 |
| 259 AddToTranslation(translation, | 261 AddToTranslation(translation, |
| 260 value, | 262 value, |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 374 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); | 376 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); |
| 375 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 377 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 376 } | 378 } |
| 377 | 379 |
| 378 | 380 |
| 379 void LCodeGen::DoCallNew(LCallNew* instr) { | 381 void LCodeGen::DoCallNew(LCallNew* instr) { |
| 380 ASSERT(instr->IsMarkedAsCall()); | 382 ASSERT(instr->IsMarkedAsCall()); |
| 381 ASSERT(ToRegister(instr->constructor()).is(x1)); | 383 ASSERT(ToRegister(instr->constructor()).is(x1)); |
| 382 | 384 |
| 383 __ Mov(x0, instr->arity()); | 385 __ Mov(x0, instr->arity()); |
| 384 if (FLAG_optimize_constructed_arrays) { | 386 // No cell in x2 for construct type feedback in optimized code. |
| 385 // No cell in x2 for construct type feedback in optimized code. | 387 Handle<Object> undefined_value(isolate()->factory()->undefined_value()); |
| 386 Handle<Object> undefined_value(isolate()->heap()->undefined_value(), | 388 __ Mov(x2, Operand(undefined_value)); |
| 387 isolate()); | |
| 388 __ Mov(x2, Operand(undefined_value)); | |
| 389 } | |
| 390 | 389 |
| 391 CallConstructStub stub(NO_CALL_FUNCTION_FLAGS); | 390 CallConstructStub stub(NO_CALL_FUNCTION_FLAGS); |
| 392 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); | 391 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); |
| 393 | 392 |
| 394 ASSERT(ToRegister(instr->result()).is(x0)); | 393 ASSERT(ToRegister(instr->result()).is(x0)); |
| 395 } | 394 } |
| 396 | 395 |
| 397 | 396 |
| 398 void LCodeGen::DoCallNewArray(LCallNewArray* instr) { | 397 void LCodeGen::DoCallNewArray(LCallNewArray* instr) { |
| 399 ASSERT(instr->IsMarkedAsCall()); | 398 ASSERT(instr->IsMarkedAsCall()); |
| 400 ASSERT(ToRegister(instr->constructor()).is(x1)); | 399 ASSERT(ToRegister(instr->constructor()).is(x1)); |
| 401 ASSERT(FLAG_optimize_constructed_arrays); | |
| 402 | 400 |
| 403 __ Mov(x0, Operand(instr->arity())); | 401 __ Mov(x0, Operand(instr->arity())); |
| 404 __ Mov(x2, Operand(instr->hydrogen()->property_cell())); | 402 __ Mov(x2, Operand(instr->hydrogen()->property_cell())); |
| 405 | 403 |
| 406 ElementsKind kind = instr->hydrogen()->elements_kind(); | 404 ElementsKind kind = instr->hydrogen()->elements_kind(); |
| 407 bool disable_allocation_sites = | 405 bool disable_allocation_sites = |
| 408 (AllocationSiteInfo::GetMode(kind) == TRACK_ALLOCATION_SITE); | 406 (AllocationSiteInfo::GetMode(kind) == TRACK_ALLOCATION_SITE); |
| 409 | 407 |
| 410 if (instr->arity() == 0) { | 408 if (instr->arity() == 0) { |
| 411 ArrayNoArgumentConstructorStub stub(kind, disable_allocation_sites); | 409 ArrayNoArgumentConstructorStub stub(kind, disable_allocation_sites); |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 518 | 516 |
| 519 void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers, | 517 void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers, |
| 520 int arguments, | 518 int arguments, |
| 521 Safepoint::DeoptMode deopt_mode) { | 519 Safepoint::DeoptMode deopt_mode) { |
| 522 RecordSafepoint( | 520 RecordSafepoint( |
| 523 pointers, Safepoint::kWithRegisters, arguments, deopt_mode); | 521 pointers, Safepoint::kWithRegisters, arguments, deopt_mode); |
| 524 } | 522 } |
| 525 | 523 |
| 526 | 524 |
| 527 bool LCodeGen::GenerateCode() { | 525 bool LCodeGen::GenerateCode() { |
| 528 HPhase phase("Z_Code generation", chunk()); | 526 LPhase phase("Z_Code generation", chunk()); |
| 529 ASSERT(is_unused()); | 527 ASSERT(is_unused()); |
| 530 status_ = GENERATING; | 528 status_ = GENERATING; |
| 531 | 529 |
| 532 // Open a frame scope to indicate that there is a frame on the stack. The | 530 // Open a frame scope to indicate that there is a frame on the stack. The |
| 533 // NONE indicates that the scope shouldn't actually generate code to set up | 531 // NONE indicates that the scope shouldn't actually generate code to set up |
| 534 // the frame (that is done in GeneratePrologue). | 532 // the frame (that is done in GeneratePrologue). |
| 535 FrameScope frame_scope(masm_, StackFrame::NONE); | 533 FrameScope frame_scope(masm_, StackFrame::NONE); |
| 536 | 534 |
| 537 return GeneratePrologue() && | 535 return GeneratePrologue() && |
| 538 GenerateBody() && | 536 GenerateBody() && |
| (...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 757 | 755 |
| 758 | 756 |
| 759 void LCodeGen::FinishCode(Handle<Code> code) { | 757 void LCodeGen::FinishCode(Handle<Code> code) { |
| 760 ASSERT(is_done()); | 758 ASSERT(is_done()); |
| 761 code->set_stack_slots(GetStackSlotCount()); | 759 code->set_stack_slots(GetStackSlotCount()); |
| 762 code->set_safepoint_table_offset(safepoints_.GetCodeOffset()); | 760 code->set_safepoint_table_offset(safepoints_.GetCodeOffset()); |
| 763 if (FLAG_weak_embedded_maps_in_optimized_code) { | 761 if (FLAG_weak_embedded_maps_in_optimized_code) { |
| 764 RegisterDependentCodeForEmbeddedMaps(code); | 762 RegisterDependentCodeForEmbeddedMaps(code); |
| 765 } | 763 } |
| 766 PopulateDeoptimizationData(code); | 764 PopulateDeoptimizationData(code); |
| 767 info()->CommitDependentMaps(code); | 765 info()->CommitDependencies(code); |
| 768 } | 766 } |
| 769 | 767 |
| 770 | 768 |
| 771 void LCodeGen::Abort(const char* reason) { | 769 void LCodeGen::Abort(const char* reason) { |
| 772 info()->set_bailout_reason(reason); | 770 info()->set_bailout_reason(reason); |
| 773 status_ = ABORTED; | 771 status_ = ABORTED; |
| 774 } | 772 } |
| 775 | 773 |
| 776 | 774 |
| 777 void LCodeGen::Comment(const char* format, ...) { | 775 void LCodeGen::Comment(const char* format, ...) { |
| (...skipping 417 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1195 template<class InstrType> | 1193 template<class InstrType> |
| 1196 void LCodeGen::EmitTestAndBranch(InstrType instr, | 1194 void LCodeGen::EmitTestAndBranch(InstrType instr, |
| 1197 Condition condition, | 1195 Condition condition, |
| 1198 const Register& value, | 1196 const Register& value, |
| 1199 uint64_t mask) { | 1197 uint64_t mask) { |
| 1200 TestAndBranch branch(this, condition, value, mask); | 1198 TestAndBranch branch(this, condition, value, mask); |
| 1201 EmitBranchGeneric(instr, branch); | 1199 EmitBranchGeneric(instr, branch); |
| 1202 } | 1200 } |
| 1203 | 1201 |
| 1204 | 1202 |
| 1203 template<class InstrType> |
| 1204 void LCodeGen::EmitBranchIfNonZeroNumber(InstrType instr, |
| 1205 const FPRegister& value, |
| 1206 const FPRegister& scratch) { |
| 1207 BranchIfNonZeroNumber branch(this, value, scratch); |
| 1208 EmitBranchGeneric(instr, branch); |
| 1209 } |
| 1210 |
| 1211 |
| 1205 void LCodeGen::DoGap(LGap* gap) { | 1212 void LCodeGen::DoGap(LGap* gap) { |
| 1206 for (int i = LGap::FIRST_INNER_POSITION; | 1213 for (int i = LGap::FIRST_INNER_POSITION; |
| 1207 i <= LGap::LAST_INNER_POSITION; | 1214 i <= LGap::LAST_INNER_POSITION; |
| 1208 i++) { | 1215 i++) { |
| 1209 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i); | 1216 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i); |
| 1210 LParallelMove* move = gap->GetParallelMove(inner_pos); | 1217 LParallelMove* move = gap->GetParallelMove(inner_pos); |
| 1211 if (move != NULL) { | 1218 if (move != NULL) { |
| 1212 resolver_.Resolve(move); | 1219 resolver_.Resolve(move); |
| 1213 } | 1220 } |
| 1214 } | 1221 } |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1322 CallRuntimeFromDeferred(Runtime::kAllocateInOldPointerSpace, 1, instr); | 1329 CallRuntimeFromDeferred(Runtime::kAllocateInOldPointerSpace, 1, instr); |
| 1323 } else if (instr->hydrogen()->CanAllocateInOldDataSpace()) { | 1330 } else if (instr->hydrogen()->CanAllocateInOldDataSpace()) { |
| 1324 CallRuntimeFromDeferred(Runtime::kAllocateInOldDataSpace, 1, instr); | 1331 CallRuntimeFromDeferred(Runtime::kAllocateInOldDataSpace, 1, instr); |
| 1325 } else { | 1332 } else { |
| 1326 CallRuntimeFromDeferred(Runtime::kAllocateInNewSpace, 1, instr); | 1333 CallRuntimeFromDeferred(Runtime::kAllocateInNewSpace, 1, instr); |
| 1327 } | 1334 } |
| 1328 __ StoreToSafepointRegisterSlot(x0, result); | 1335 __ StoreToSafepointRegisterSlot(x0, result); |
| 1329 } | 1336 } |
| 1330 | 1337 |
| 1331 | 1338 |
| 1339 void LCodeGen::DoAllocateObject(LAllocateObject* instr) { |
| 1340 class DeferredAllocateObject: public LDeferredCode { |
| 1341 public: |
| 1342 DeferredAllocateObject(LCodeGen* codegen, LAllocateObject* instr) |
| 1343 : LDeferredCode(codegen), instr_(instr) { } |
| 1344 virtual void Generate() { codegen()->DoDeferredAllocateObject(instr_); } |
| 1345 virtual LInstruction* instr() { return instr_; } |
| 1346 private: |
| 1347 LAllocateObject* instr_; |
| 1348 }; |
| 1349 |
| 1350 DeferredAllocateObject* deferred = |
| 1351 new(zone()) DeferredAllocateObject(this, instr); |
| 1352 |
| 1353 Register result = ToRegister(instr->result()); |
| 1354 Register scratch1 = ToRegister(instr->temp1()); |
| 1355 Register scratch2 = ToRegister(instr->temp2()); |
| 1356 Handle<JSFunction> constructor = instr->hydrogen()->constructor(); |
| 1357 Handle<Map> initial_map = instr->hydrogen()->constructor_initial_map(); |
| 1358 int instance_size = initial_map->instance_size(); |
| 1359 |
| 1360 ASSERT(initial_map->pre_allocated_property_fields() + |
| 1361 initial_map->unused_property_fields() - |
| 1362 initial_map->inobject_properties() == 0); |
| 1363 |
| 1364 __ Allocate(instance_size, result, scratch1, scratch2, deferred->entry(), |
| 1365 TAG_OBJECT); |
| 1366 |
| 1367 __ Bind(deferred->exit()); |
| 1368 if (FLAG_debug_code) { |
| 1369 Label is_in_new_space; |
| 1370 __ JumpIfInNewSpace(result, &is_in_new_space); |
| 1371 __ Abort("Allocated object is not in new-space"); |
| 1372 __ Bind(&is_in_new_space); |
| 1373 } |
| 1374 |
| 1375 // Load the initial map. |
| 1376 Register map = scratch1; |
| 1377 __ LoadHeapObject(map, constructor); |
| 1378 __ Ldr(map, FieldMemOperand(map, JSFunction::kPrototypeOrInitialMapOffset)); |
| 1379 |
| 1380 // Initialize map and field of the newly allocated object. |
| 1381 ASSERT(initial_map->instance_type() == JS_OBJECT_TYPE); |
| 1382 __ Str(map, FieldMemOperand(result, JSObject::kMapOffset)); |
| 1383 |
| 1384 Register empty_array = scratch1; |
| 1385 __ LoadRoot(empty_array, Heap::kEmptyFixedArrayRootIndex); |
| 1386 __ Str(empty_array, FieldMemOperand(result, JSObject::kElementsOffset)); |
| 1387 __ Str(empty_array, FieldMemOperand(result, JSObject::kPropertiesOffset)); |
| 1388 |
| 1389 if (initial_map->inobject_properties() != 0) { |
| 1390 Register undef = scratch1; |
| 1391 __ LoadRoot(undef, Heap::kUndefinedValueRootIndex); |
| 1392 for (int i = 0; i < initial_map->inobject_properties(); i++) { |
| 1393 int property_offset = JSObject::kHeaderSize + i * kPointerSize; |
| 1394 __ Str(undef, FieldMemOperand(result, property_offset)); |
| 1395 } |
| 1396 } |
| 1397 } |
| 1398 |
| 1399 |
| 1400 void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) { |
| 1401 Register result = ToRegister(instr->result()); |
| 1402 Handle<Map> initial_map = instr->hydrogen()->constructor_initial_map(); |
| 1403 int instance_size = initial_map->instance_size(); |
| 1404 |
| 1405 |
| 1406 // TODO(3095996): Get rid of this. For now, we need to make the |
| 1407 // result register contain a valid pointer because it is already |
| 1408 // contained in the register pointer map. |
| 1409 __ Mov(result, 0); |
| 1410 |
| 1411 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); |
| 1412 __ Mov(x0, Operand(Smi::FromInt(instance_size))); |
| 1413 __ Push(x0); |
| 1414 CallRuntimeFromDeferred(Runtime::kAllocateInNewSpace, 1, instr); |
| 1415 __ StoreToSafepointRegisterSlot(x0, result); |
| 1416 } |
| 1417 |
| 1418 |
| 1332 void LCodeGen::DoApplyArguments(LApplyArguments* instr) { | 1419 void LCodeGen::DoApplyArguments(LApplyArguments* instr) { |
| 1333 Register receiver = ToRegister(instr->receiver()); | 1420 Register receiver = ToRegister(instr->receiver()); |
| 1334 Register function = ToRegister(instr->function()); | 1421 Register function = ToRegister(instr->function()); |
| 1335 Register length = ToRegister(instr->length()); | 1422 Register length = ToRegister(instr->length()); |
| 1336 Register elements = ToRegister(instr->elements()); | 1423 Register elements = ToRegister(instr->elements()); |
| 1337 Register scratch = x5; | 1424 Register scratch = x5; |
| 1338 ASSERT(receiver.Is(x0)); // Used for parameter count. | 1425 ASSERT(receiver.Is(x0)); // Used for parameter count. |
| 1339 ASSERT(function.Is(x1)); // Required by InvokeFunction. | 1426 ASSERT(function.Is(x1)); // Required by InvokeFunction. |
| 1340 ASSERT(ToRegister(instr->result()).Is(x0)); | 1427 ASSERT(ToRegister(instr->result()).Is(x0)); |
| 1341 ASSERT(instr->IsMarkedAsCall()); | 1428 ASSERT(instr->IsMarkedAsCall()); |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1529 | 1616 |
| 1530 if (r.IsInteger32()) { | 1617 if (r.IsInteger32()) { |
| 1531 ASSERT(!info()->IsStub()); | 1618 ASSERT(!info()->IsStub()); |
| 1532 EmitCompareAndBranch(instr, ne, ToRegister32(instr->value()), 0); | 1619 EmitCompareAndBranch(instr, ne, ToRegister32(instr->value()), 0); |
| 1533 } else if (r.IsSmi()) { | 1620 } else if (r.IsSmi()) { |
| 1534 ASSERT(!info()->IsStub()); | 1621 ASSERT(!info()->IsStub()); |
| 1535 STATIC_ASSERT(kSmiTag == 0); | 1622 STATIC_ASSERT(kSmiTag == 0); |
| 1536 EmitCompareAndBranch(instr, ne, ToRegister(instr->value()), 0); | 1623 EmitCompareAndBranch(instr, ne, ToRegister(instr->value()), 0); |
| 1537 } else if (r.IsDouble()) { | 1624 } else if (r.IsDouble()) { |
| 1538 DoubleRegister value = ToDoubleRegister(instr->value()); | 1625 DoubleRegister value = ToDoubleRegister(instr->value()); |
| 1539 __ Fcmp(value, 0.0); | 1626 // Test the double value. Zero and NaN are false. |
| 1540 // If we got a NaN jump to the false branch. | 1627 EmitBranchIfNonZeroNumber(instr, value, double_scratch()); |
| 1541 __ B(vs, false_label); | |
| 1542 EmitBranch(instr, ne); | |
| 1543 } else { | 1628 } else { |
| 1544 ASSERT(r.IsTagged()); | 1629 ASSERT(r.IsTagged()); |
| 1545 Register value = ToRegister(instr->value()); | 1630 Register value = ToRegister(instr->value()); |
| 1546 HType type = instr->hydrogen()->value()->type(); | 1631 HType type = instr->hydrogen()->value()->type(); |
| 1547 | 1632 |
| 1548 if (type.IsBoolean()) { | 1633 if (type.IsBoolean()) { |
| 1549 ASSERT(!info()->IsStub()); | 1634 ASSERT(!info()->IsStub()); |
| 1550 __ CompareRoot(value, Heap::kTrueValueRootIndex); | 1635 __ CompareRoot(value, Heap::kTrueValueRootIndex); |
| 1551 EmitBranch(instr, eq); | 1636 EmitBranch(instr, eq); |
| 1552 } else if (type.IsSmi()) { | 1637 } else if (type.IsSmi()) { |
| 1553 ASSERT(!info()->IsStub()); | 1638 ASSERT(!info()->IsStub()); |
| 1554 EmitCompareAndBranch(instr, ne, value, Operand(Smi::FromInt(0))); | 1639 EmitCompareAndBranch(instr, ne, value, Operand(Smi::FromInt(0))); |
| 1640 } else if (type.IsJSArray()) { |
| 1641 ASSERT(!info()->IsStub()); |
| 1642 EmitBranch(instr, al); |
| 1643 } else if (type.IsHeapNumber()) { |
| 1644 ASSERT(!info()->IsStub()); |
| 1645 __ Ldr(double_scratch(), FieldMemOperand(value, |
| 1646 HeapNumber::kValueOffset)); |
| 1647 // Test the double value. Zero and NaN are false. |
| 1648 EmitBranchIfNonZeroNumber(instr, double_scratch(), double_scratch()); |
| 1649 } else if (type.IsString()) { |
| 1650 ASSERT(!info()->IsStub()); |
| 1651 Register temp = ToRegister(instr->temp1()); |
| 1652 __ Ldr(temp, FieldMemOperand(value, String::kLengthOffset)); |
| 1653 EmitCompareAndBranch(instr, ne, temp, 0); |
| 1555 } else { | 1654 } else { |
| 1556 ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types(); | 1655 ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types(); |
| 1557 // Avoid deopts in the case where we've never executed this path before. | 1656 // Avoid deopts in the case where we've never executed this path before. |
| 1558 if (expected.IsEmpty()) expected = ToBooleanStub::all_types(); | 1657 if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic(); |
| 1559 | 1658 |
| 1560 if (expected.Contains(ToBooleanStub::UNDEFINED)) { | 1659 if (expected.Contains(ToBooleanStub::UNDEFINED)) { |
| 1561 // undefined -> false. | 1660 // undefined -> false. |
| 1562 __ JumpIfRoot( | 1661 __ JumpIfRoot( |
| 1563 value, Heap::kUndefinedValueRootIndex, false_label); | 1662 value, Heap::kUndefinedValueRootIndex, false_label); |
| 1564 } | 1663 } |
| 1565 | 1664 |
| 1566 if (expected.Contains(ToBooleanStub::BOOLEAN)) { | 1665 if (expected.Contains(ToBooleanStub::BOOLEAN)) { |
| 1567 // Boolean -> its value. | 1666 // Boolean -> its value. |
| 1568 __ JumpIfRoot( | 1667 __ JumpIfRoot( |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1635 __ Ldr(double_scratch(), | 1734 __ Ldr(double_scratch(), |
| 1636 FieldMemOperand(value, HeapNumber::kValueOffset)); | 1735 FieldMemOperand(value, HeapNumber::kValueOffset)); |
| 1637 __ Fcmp(double_scratch(), 0.0); | 1736 __ Fcmp(double_scratch(), 0.0); |
| 1638 // If we got a NaN (overflow bit is set), jump to the false branch. | 1737 // If we got a NaN (overflow bit is set), jump to the false branch. |
| 1639 __ B(vs, false_label); | 1738 __ B(vs, false_label); |
| 1640 __ B(eq, false_label); | 1739 __ B(eq, false_label); |
| 1641 __ B(true_label); | 1740 __ B(true_label); |
| 1642 __ Bind(¬_heap_number); | 1741 __ Bind(¬_heap_number); |
| 1643 } | 1742 } |
| 1644 | 1743 |
| 1645 // We've seen something for the first time -> deopt. | 1744 if (!expected.IsGeneric()) { |
| 1646 Deoptimize(instr->environment()); | 1745 // We've seen something for the first time -> deopt. |
| 1746 // This can only happen if we are not generic already. |
| 1747 Deoptimize(instr->environment()); |
| 1748 } |
| 1647 } | 1749 } |
| 1648 } | 1750 } |
| 1649 } | 1751 } |
| 1650 | 1752 |
| 1651 | 1753 |
| 1652 void LCodeGen::CallKnownFunction(Handle<JSFunction> function, | 1754 void LCodeGen::CallKnownFunction(Handle<JSFunction> function, |
| 1653 int formal_parameter_count, | 1755 int formal_parameter_count, |
| 1654 int arity, | 1756 int arity, |
| 1655 LInstruction* instr, | 1757 LInstruction* instr, |
| 1656 CallKind call_kind, | 1758 CallKind call_kind, |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1835 } | 1937 } |
| 1836 | 1938 |
| 1837 // If we didn't match a map, deoptimize. | 1939 // If we didn't match a map, deoptimize. |
| 1838 Deoptimize(instr->environment()); | 1940 Deoptimize(instr->environment()); |
| 1839 | 1941 |
| 1840 __ Bind(&success); | 1942 __ Bind(&success); |
| 1841 } | 1943 } |
| 1842 | 1944 |
| 1843 | 1945 |
| 1844 void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) { | 1946 void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) { |
| 1845 // TODO(all): Depending of how we chose to implement the deopt, if we could | 1947 if (!instr->hydrogen()->value()->IsHeapObject()) { |
| 1846 // guarantee that we have a deopt handler reachable by a tbz instruction, | 1948 // TODO(all): Depending of how we chose to implement the deopt, if we could |
| 1847 // we could use tbz here and produce less code to support this instruction. | 1949 // guarantee that we have a deopt handler reachable by a tbz instruction, |
| 1848 DeoptimizeIfSmi(ToRegister(instr->value()), instr->environment()); | 1950 // we could use tbz here and produce less code to support this instruction. |
| 1951 DeoptimizeIfSmi(ToRegister(instr->value()), instr->environment()); |
| 1952 } |
| 1849 } | 1953 } |
| 1850 | 1954 |
| 1851 | 1955 |
| 1852 void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { | 1956 void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { |
| 1853 ZoneList<Handle<JSObject> >* prototypes = instr->prototypes(); | 1957 ZoneList<Handle<JSObject> >* prototypes = instr->prototypes(); |
| 1854 ZoneList<Handle<Map> >* maps = instr->maps(); | 1958 ZoneList<Handle<Map> >* maps = instr->maps(); |
| 1855 ASSERT(prototypes->length() == maps->length()); | 1959 ASSERT(prototypes->length() == maps->length()); |
| 1856 | 1960 |
| 1857 if (!instr->hydrogen()->CanOmitPrototypeChecks()) { | 1961 if (!instr->hydrogen()->CanOmitPrototypeChecks()) { |
| 1858 // TODO(jbramley): The temp registers are only needed in this case. | 1962 // TODO(jbramley): The temp registers are only needed in this case. |
| (...skipping 734 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2593 for (int i = current_block_ + 1; i < graph()->blocks()->length(); ++i) { | 2697 for (int i = current_block_ + 1; i < graph()->blocks()->length(); ++i) { |
| 2594 if (!chunk_->GetLabel(i)->HasReplacement()) return i; | 2698 if (!chunk_->GetLabel(i)->HasReplacement()) return i; |
| 2595 } | 2699 } |
| 2596 return -1; | 2700 return -1; |
| 2597 } | 2701 } |
| 2598 | 2702 |
| 2599 | 2703 |
| 2600 void LCodeGen::EmitGoto(int block) { | 2704 void LCodeGen::EmitGoto(int block) { |
| 2601 // Do not emit jump if we are emitting a goto to the next block. | 2705 // Do not emit jump if we are emitting a goto to the next block. |
| 2602 if (!IsNextEmittedBlock(block)) { | 2706 if (!IsNextEmittedBlock(block)) { |
| 2603 __ B(chunk_->GetAssemblyLabel(chunk_->LookupDestination(block))); | 2707 __ B(chunk_->GetAssemblyLabel(LookupDestination(block))); |
| 2604 } | 2708 } |
| 2605 } | 2709 } |
| 2606 | 2710 |
| 2607 | 2711 |
| 2608 void LCodeGen::DoGoto(LGoto* instr) { | 2712 void LCodeGen::DoGoto(LGoto* instr) { |
| 2609 EmitGoto(instr->block_id()); | 2713 EmitGoto(instr->block_id()); |
| 2610 } | 2714 } |
| 2611 | 2715 |
| 2612 | 2716 |
| 2613 // HHasInstanceTypeAndBranch instruction is built with an interval of type | 2717 // HHasInstanceTypeAndBranch instruction is built with an interval of type |
| (...skipping 27 matching lines...) Expand all Loading... |
| 2641 if (from == FIRST_TYPE) return ls; | 2745 if (from == FIRST_TYPE) return ls; |
| 2642 UNREACHABLE(); | 2746 UNREACHABLE(); |
| 2643 return eq; | 2747 return eq; |
| 2644 } | 2748 } |
| 2645 | 2749 |
| 2646 | 2750 |
| 2647 void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { | 2751 void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { |
| 2648 Register input = ToRegister(instr->value()); | 2752 Register input = ToRegister(instr->value()); |
| 2649 Register scratch = ToRegister(instr->temp()); | 2753 Register scratch = ToRegister(instr->temp()); |
| 2650 | 2754 |
| 2651 // TODO(all): When we'll have rebased, we can avoid the smi check if the | 2755 if (!instr->hydrogen()->value()->IsHeapObject()) { |
| 2652 // input is known to be a HeapObject. | 2756 __ JumpIfSmi(input, instr->FalseLabel(chunk_)); |
| 2653 __ JumpIfSmi(input, instr->FalseLabel(chunk_)); | 2757 } |
| 2654 __ CompareObjectType(input, scratch, scratch, TestType(instr->hydrogen())); | 2758 __ CompareObjectType(input, scratch, scratch, TestType(instr->hydrogen())); |
| 2655 EmitBranch(instr, BranchCondition(instr->hydrogen())); | 2759 EmitBranch(instr, BranchCondition(instr->hydrogen())); |
| 2656 } | 2760 } |
| 2657 | 2761 |
| 2658 | 2762 |
| 2659 void LCodeGen::DoIn(LIn* instr) { | 2763 void LCodeGen::DoIn(LIn* instr) { |
| 2660 Register obj = ToRegister(instr->object()); | 2764 Register obj = ToRegister(instr->object()); |
| 2661 Register key = ToRegister(instr->key()); | 2765 Register key = ToRegister(instr->key()); |
| 2662 __ Push(key, obj); | 2766 __ Push(key, obj); |
| 2663 ASSERT(instr->HasPointerMap()); | 2767 ASSERT(instr->HasPointerMap()); |
| (...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2879 __ IsInstanceJSObjectType(map, scratch, NULL); | 2983 __ IsInstanceJSObjectType(map, scratch, NULL); |
| 2880 // Flags have been updated by IsInstanceJSObjectType. We can now test the | 2984 // Flags have been updated by IsInstanceJSObjectType. We can now test the |
| 2881 // flags for "le" condition to check if the object's type is a valid | 2985 // flags for "le" condition to check if the object's type is a valid |
| 2882 // JS object type. | 2986 // JS object type. |
| 2883 EmitBranch(instr, le); | 2987 EmitBranch(instr, le); |
| 2884 } | 2988 } |
| 2885 | 2989 |
| 2886 | 2990 |
| 2887 Condition LCodeGen::EmitIsString(Register input, | 2991 Condition LCodeGen::EmitIsString(Register input, |
| 2888 Register temp1, | 2992 Register temp1, |
| 2889 Label* is_not_string) { | 2993 Label* is_not_string, |
| 2890 __ JumpIfSmi(input, is_not_string); | 2994 SmiCheck check_needed = INLINE_SMI_CHECK) { |
| 2995 if (check_needed == INLINE_SMI_CHECK) { |
| 2996 __ JumpIfSmi(input, is_not_string); |
| 2997 } |
| 2891 __ CompareObjectType(input, temp1, temp1, FIRST_NONSTRING_TYPE); | 2998 __ CompareObjectType(input, temp1, temp1, FIRST_NONSTRING_TYPE); |
| 2892 | 2999 |
| 2893 return lt; | 3000 return lt; |
| 2894 } | 3001 } |
| 2895 | 3002 |
| 2896 | 3003 |
| 2897 void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) { | 3004 void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) { |
| 2898 Register val = ToRegister(instr->value()); | 3005 Register val = ToRegister(instr->value()); |
| 2899 Register scratch = ToRegister(instr->temp()); | 3006 Register scratch = ToRegister(instr->temp()); |
| 2900 | 3007 |
| 2901 Condition true_cond = EmitIsString(val, scratch, instr->FalseLabel(chunk_)); | 3008 SmiCheck check_needed = |
| 3009 instr->hydrogen()->value()->IsHeapObject() |
| 3010 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; |
| 3011 Condition true_cond = |
| 3012 EmitIsString(val, scratch, instr->FalseLabel(chunk_), check_needed); |
| 2902 | 3013 |
| 2903 EmitBranch(instr, true_cond); | 3014 EmitBranch(instr, true_cond); |
| 2904 } | 3015 } |
| 2905 | 3016 |
| 2906 | 3017 |
| 2907 void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { | 3018 void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { |
| 2908 Register value = ToRegister(instr->value()); | 3019 Register value = ToRegister(instr->value()); |
| 2909 STATIC_ASSERT(kSmiTag == 0); | 3020 STATIC_ASSERT(kSmiTag == 0); |
| 2910 EmitTestAndBranch(instr, eq, value, kSmiTagMask); | 3021 EmitTestAndBranch(instr, eq, value, kSmiTagMask); |
| 2911 } | 3022 } |
| 2912 | 3023 |
| 2913 | 3024 |
| 2914 void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) { | 3025 void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) { |
| 2915 Register input = ToRegister(instr->value()); | 3026 Register input = ToRegister(instr->value()); |
| 2916 Register temp = ToRegister(instr->temp()); | 3027 Register temp = ToRegister(instr->temp()); |
| 2917 | 3028 |
| 2918 __ JumpIfSmi(input, instr->FalseLabel(chunk_)); | 3029 if (!instr->hydrogen()->value()->IsHeapObject()) { |
| 3030 __ JumpIfSmi(input, instr->FalseLabel(chunk_)); |
| 3031 } |
| 2919 __ Ldr(temp, FieldMemOperand(input, HeapObject::kMapOffset)); | 3032 __ Ldr(temp, FieldMemOperand(input, HeapObject::kMapOffset)); |
| 2920 __ Ldrb(temp, FieldMemOperand(temp, Map::kBitFieldOffset)); | 3033 __ Ldrb(temp, FieldMemOperand(temp, Map::kBitFieldOffset)); |
| 2921 | 3034 |
| 2922 // TODO(jbramley): Find a way to use Tbz here. | 3035 EmitTestAndBranch(instr, ne, temp, 1 << Map::kIsUndetectable); |
| 2923 __ Tst(temp, 1 << Map::kIsUndetectable); | |
| 2924 EmitBranch(instr, ne); | |
| 2925 } | 3036 } |
| 2926 | 3037 |
| 2927 | 3038 |
| 2928 static const char* LabelType(LLabel* label) { | 3039 static const char* LabelType(LLabel* label) { |
| 2929 if (label->is_loop_header()) return " (loop header)"; | 3040 if (label->is_loop_header()) return " (loop header)"; |
| 2930 if (label->is_osr_entry()) return " (OSR entry)"; | 3041 if (label->is_osr_entry()) return " (OSR entry)"; |
| 2931 return ""; | 3042 return ""; |
| 2932 } | 3043 } |
| 2933 | 3044 |
| 2934 | 3045 |
| (...skipping 1535 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4470 if (instr->hydrogen()->DeoptimizesOnHole()) { | 4581 if (instr->hydrogen()->DeoptimizesOnHole()) { |
| 4471 DeoptimizeIfRoot(scratch, Heap::kTheHoleValueRootIndex, | 4582 DeoptimizeIfRoot(scratch, Heap::kTheHoleValueRootIndex, |
| 4472 instr->environment()); | 4583 instr->environment()); |
| 4473 } else { | 4584 } else { |
| 4474 __ JumpIfNotRoot(scratch, Heap::kTheHoleValueRootIndex, &skip_assignment); | 4585 __ JumpIfNotRoot(scratch, Heap::kTheHoleValueRootIndex, &skip_assignment); |
| 4475 } | 4586 } |
| 4476 } | 4587 } |
| 4477 | 4588 |
| 4478 __ Str(value, target); | 4589 __ Str(value, target); |
| 4479 if (instr->hydrogen()->NeedsWriteBarrier()) { | 4590 if (instr->hydrogen()->NeedsWriteBarrier()) { |
| 4480 HType type = instr->hydrogen()->value()->type(); | |
| 4481 SmiCheck check_needed = | 4591 SmiCheck check_needed = |
| 4482 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; | 4592 instr->hydrogen()->value()->IsHeapObject() |
| 4593 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; |
| 4483 __ RecordWriteContextSlot(context, | 4594 __ RecordWriteContextSlot(context, |
| 4484 target.offset(), | 4595 target.offset(), |
| 4485 value, | 4596 value, |
| 4486 scratch, | 4597 scratch, |
| 4487 GetLinkRegisterState(), | 4598 GetLinkRegisterState(), |
| 4488 kSaveFPRegs, | 4599 kSaveFPRegs, |
| 4489 EMIT_REMEMBERED_SET, | 4600 EMIT_REMEMBERED_SET, |
| 4490 check_needed); | 4601 check_needed); |
| 4491 } | 4602 } |
| 4492 __ Bind(&skip_assignment); | 4603 __ Bind(&skip_assignment); |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4642 } else { | 4753 } else { |
| 4643 key = ToRegister(instr->key()); | 4754 key = ToRegister(instr->key()); |
| 4644 bool key_is_tagged = instr->hydrogen()->key()->representation().IsSmi(); | 4755 bool key_is_tagged = instr->hydrogen()->key()->representation().IsSmi(); |
| 4645 CalcKeyedArrayBaseRegister(store_base, elements, key, key_is_tagged, | 4756 CalcKeyedArrayBaseRegister(store_base, elements, key, key_is_tagged, |
| 4646 instr->hydrogen()->elements_kind()); | 4757 instr->hydrogen()->elements_kind()); |
| 4647 offset = FixedArray::OffsetOfElementAt(instr->additional_index()); | 4758 offset = FixedArray::OffsetOfElementAt(instr->additional_index()); |
| 4648 } | 4759 } |
| 4649 __ Str(value, FieldMemOperand(store_base, offset)); | 4760 __ Str(value, FieldMemOperand(store_base, offset)); |
| 4650 | 4761 |
| 4651 if (instr->hydrogen()->NeedsWriteBarrier()) { | 4762 if (instr->hydrogen()->NeedsWriteBarrier()) { |
| 4652 HType type = instr->hydrogen()->value()->type(); | 4763 SmiCheck check_needed = |
| 4653 SmiCheck check_needed = type.IsHeapObject() | 4764 instr->hydrogen()->value()->IsHeapObject() |
| 4654 ? OMIT_SMI_CHECK | 4765 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; |
| 4655 : INLINE_SMI_CHECK; | |
| 4656 // Compute address of modified element and store it into key register. | 4766 // Compute address of modified element and store it into key register. |
| 4657 __ Add(key, store_base, offset - kHeapObjectTag); | 4767 __ Add(key, store_base, offset - kHeapObjectTag); |
| 4658 __ RecordWrite(elements, key, value, GetLinkRegisterState(), kSaveFPRegs, | 4768 __ RecordWrite(elements, key, value, GetLinkRegisterState(), kSaveFPRegs, |
| 4659 EMIT_REMEMBERED_SET, check_needed); | 4769 EMIT_REMEMBERED_SET, check_needed); |
| 4660 } | 4770 } |
| 4661 } | 4771 } |
| 4662 | 4772 |
| 4663 | 4773 |
| 4664 void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { | 4774 void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { |
| 4665 ASSERT(ToRegister(instr->object()).Is(x2)); | 4775 ASSERT(ToRegister(instr->object()).Is(x2)); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4713 temp1, | 4823 temp1, |
| 4714 GetLinkRegisterState(), | 4824 GetLinkRegisterState(), |
| 4715 kSaveFPRegs, | 4825 kSaveFPRegs, |
| 4716 OMIT_REMEMBERED_SET, | 4826 OMIT_REMEMBERED_SET, |
| 4717 OMIT_SMI_CHECK); | 4827 OMIT_SMI_CHECK); |
| 4718 } | 4828 } |
| 4719 } | 4829 } |
| 4720 | 4830 |
| 4721 // Do the store. | 4831 // Do the store. |
| 4722 Register value = ToRegister(instr->value()); | 4832 Register value = ToRegister(instr->value()); |
| 4723 HType type = instr->hydrogen()->value()->type(); | |
| 4724 SmiCheck check_needed = | 4833 SmiCheck check_needed = |
| 4725 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; | 4834 instr->hydrogen()->value()->IsHeapObject() |
| 4835 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; |
| 4726 if (access.IsInobject()) { | 4836 if (access.IsInobject()) { |
| 4727 __ Str(value, FieldMemOperand(object, offset)); | 4837 __ Str(value, FieldMemOperand(object, offset)); |
| 4728 if (instr->hydrogen()->NeedsWriteBarrier()) { | 4838 if (instr->hydrogen()->NeedsWriteBarrier()) { |
| 4729 // Update the write barrier for the object for in-object properties. | 4839 // Update the write barrier for the object for in-object properties. |
| 4730 __ RecordWriteField(object, | 4840 __ RecordWriteField(object, |
| 4731 offset, | 4841 offset, |
| 4732 value, // Clobbered. | 4842 value, // Clobbered. |
| 4733 temp0, // Clobbered. | 4843 temp0, // Clobbered. |
| 4734 GetLinkRegisterState(), | 4844 GetLinkRegisterState(), |
| 4735 kSaveFPRegs, | 4845 kSaveFPRegs, |
| (...skipping 496 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5232 | 5342 |
| 5233 | 5343 |
| 5234 void LCodeGen::DoValueOf(LValueOf* instr) { | 5344 void LCodeGen::DoValueOf(LValueOf* instr) { |
| 5235 Register input = ToRegister(instr->value()); | 5345 Register input = ToRegister(instr->value()); |
| 5236 Register result = ToRegister(instr->result()); | 5346 Register result = ToRegister(instr->result()); |
| 5237 Register scratch = ToRegister(instr->temp()); | 5347 Register scratch = ToRegister(instr->temp()); |
| 5238 Label done; | 5348 Label done; |
| 5239 | 5349 |
| 5240 ASSERT(input.Is(result)); | 5350 ASSERT(input.Is(result)); |
| 5241 | 5351 |
| 5242 // If the object is a smi return it. | 5352 if (!instr->hydrogen()->value()->IsHeapObject()) { |
| 5243 __ JumpIfSmi(input, &done); | 5353 // If the object is a smi return it. |
| 5354 __ JumpIfSmi(input, &done); |
| 5355 } |
| 5244 | 5356 |
| 5245 // If the object is not a value type, return the object, otherwise | 5357 // If the object is not a value type, return the object, otherwise |
| 5246 // return the value. | 5358 // return the value. |
| 5247 __ JumpIfNotObjectType(input, scratch, scratch, JS_VALUE_TYPE, &done); | 5359 __ JumpIfNotObjectType(input, scratch, scratch, JS_VALUE_TYPE, &done); |
| 5248 __ Ldr(result, FieldMemOperand(input, JSValue::kValueOffset)); | 5360 __ Ldr(result, FieldMemOperand(input, JSValue::kValueOffset)); |
| 5249 | 5361 |
| 5250 __ Bind(&done); | 5362 __ Bind(&done); |
| 5251 } | 5363 } |
| 5252 | 5364 |
| 5253 | 5365 |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5329 __ Bind(&out_of_object); | 5441 __ Bind(&out_of_object); |
| 5330 __ Ldr(result, FieldMemOperand(object, JSObject::kPropertiesOffset)); | 5442 __ Ldr(result, FieldMemOperand(object, JSObject::kPropertiesOffset)); |
| 5331 // Index is equal to negated out of object property index plus 1. | 5443 // Index is equal to negated out of object property index plus 1. |
| 5332 __ Sub(result, result, Operand::UntagSmiAndScale(index, kPointerSizeLog2)); | 5444 __ Sub(result, result, Operand::UntagSmiAndScale(index, kPointerSizeLog2)); |
| 5333 __ Ldr(result, FieldMemOperand(result, | 5445 __ Ldr(result, FieldMemOperand(result, |
| 5334 FixedArray::kHeaderSize - kPointerSize)); | 5446 FixedArray::kHeaderSize - kPointerSize)); |
| 5335 __ Bind(&done); | 5447 __ Bind(&done); |
| 5336 } | 5448 } |
| 5337 | 5449 |
| 5338 } } // namespace v8::internal | 5450 } } // namespace v8::internal |
| OLD | NEW |