| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 479 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 490 cgen->LoadReference(this); | 490 cgen->LoadReference(this); |
| 491 } | 491 } |
| 492 | 492 |
| 493 | 493 |
| 494 Reference::~Reference() { | 494 Reference::~Reference() { |
| 495 cgen_->UnloadReference(this); | 495 cgen_->UnloadReference(this); |
| 496 } | 496 } |
| 497 | 497 |
| 498 | 498 |
| 499 void CodeGenerator::LoadReference(Reference* ref) { | 499 void CodeGenerator::LoadReference(Reference* ref) { |
| 500 // References are loaded from both spilled and unspilled code. Set the |
| 501 // state to unspilled to allow that (and explicitly spill after |
| 502 // construction at the construction sites). |
| 503 bool was_in_spilled_code = in_spilled_code_; |
| 504 in_spilled_code_ = false; |
| 505 |
| 500 Comment cmnt(masm_, "[ LoadReference"); | 506 Comment cmnt(masm_, "[ LoadReference"); |
| 501 Expression* e = ref->expression(); | 507 Expression* e = ref->expression(); |
| 502 Property* property = e->AsProperty(); | 508 Property* property = e->AsProperty(); |
| 503 Variable* var = e->AsVariableProxy()->AsVariable(); | 509 Variable* var = e->AsVariableProxy()->AsVariable(); |
| 504 | 510 |
| 505 if (property != NULL) { | 511 if (property != NULL) { |
| 506 // The expression is either a property or a variable proxy that rewrites | 512 // The expression is either a property or a variable proxy that rewrites |
| 507 // to a property. | 513 // to a property. |
| 508 Load(property->obj()); | 514 Load(property->obj()); |
| 509 // We use a named reference if the key is a literal symbol, unless it is | 515 // We use a named reference if the key is a literal symbol, unless it is |
| (...skipping 19 matching lines...) Expand all Loading... |
| 529 ref->set_type(Reference::NAMED); | 535 ref->set_type(Reference::NAMED); |
| 530 } else { | 536 } else { |
| 531 ASSERT(var->slot() != NULL); | 537 ASSERT(var->slot() != NULL); |
| 532 ref->set_type(Reference::SLOT); | 538 ref->set_type(Reference::SLOT); |
| 533 } | 539 } |
| 534 } else { | 540 } else { |
| 535 // Anything else is a runtime error. | 541 // Anything else is a runtime error. |
| 536 Load(e); | 542 Load(e); |
| 537 frame_->CallRuntime(Runtime::kThrowReferenceError, 1); | 543 frame_->CallRuntime(Runtime::kThrowReferenceError, 1); |
| 538 } | 544 } |
| 545 |
| 546 in_spilled_code_ = was_in_spilled_code; |
| 539 } | 547 } |
| 540 | 548 |
| 541 | 549 |
| 542 void CodeGenerator::UnloadReference(Reference* ref) { | 550 void CodeGenerator::UnloadReference(Reference* ref) { |
| 543 // Pop a reference from the stack while preserving TOS. | 551 // Pop a reference from the stack while preserving TOS. |
| 544 Comment cmnt(masm_, "[ UnloadReference"); | 552 Comment cmnt(masm_, "[ UnloadReference"); |
| 545 int size = ref->size(); | 553 int size = ref->size(); |
| 546 if (size == 1) { | 554 if (size == 1) { |
| 547 VirtualFrame::SpilledScope spilled_scope(this); | 555 VirtualFrame::SpilledScope spilled_scope(this); |
| 548 frame_->EmitPop(eax); | 556 frame_->EmitPop(eax); |
| (...skipping 2784 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3333 | 3341 |
| 3334 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { | 3342 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { |
| 3335 ASSERT(args->length() == 1); | 3343 ASSERT(args->length() == 1); |
| 3336 LoadAndSpill(args->at(0)); | 3344 LoadAndSpill(args->at(0)); |
| 3337 frame_->EmitPop(eax); | 3345 frame_->EmitPop(eax); |
| 3338 __ test(eax, Immediate(kSmiTagMask)); | 3346 __ test(eax, Immediate(kSmiTagMask)); |
| 3339 cc_reg_ = zero; | 3347 cc_reg_ = zero; |
| 3340 } | 3348 } |
| 3341 | 3349 |
| 3342 | 3350 |
| 3351 void CodeGenerator::GenerateLog(ZoneList<Expression*>* args) { |
| 3352 // Conditionally generate a log call. |
| 3353 // Args: |
| 3354 // 0 (literal string): The type of logging (corresponds to the flags). |
| 3355 // This is used to determine whether or not to generate the log call. |
| 3356 // 1 (string): Format string. Access the string at argument index 2 |
| 3357 // with '%2s' (see Logger::LogRuntime for all the formats). |
| 3358 // 2 (array): Arguments to the format string. |
| 3359 ASSERT_EQ(args->length(), 3); |
| 3360 if (ShouldGenerateLog(args->at(0))) { |
| 3361 LoadAndSpill(args->at(1)); |
| 3362 LoadAndSpill(args->at(2)); |
| 3363 frame_->CallRuntime(Runtime::kLog, 2); |
| 3364 } |
| 3365 // Finally, we're expected to leave a value on the top of the stack. |
| 3366 frame_->EmitPush(Immediate(Factory::undefined_value())); |
| 3367 } |
| 3368 |
| 3369 |
| 3343 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { | 3370 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { |
| 3344 ASSERT(args->length() == 1); | 3371 ASSERT(args->length() == 1); |
| 3345 LoadAndSpill(args->at(0)); | 3372 LoadAndSpill(args->at(0)); |
| 3346 frame_->EmitPop(eax); | 3373 frame_->EmitPop(eax); |
| 3347 __ test(eax, Immediate(kSmiTagMask | 0x80000000)); | 3374 __ test(eax, Immediate(kSmiTagMask | 0x80000000)); |
| 3348 cc_reg_ = zero; | 3375 cc_reg_ = zero; |
| 3349 } | 3376 } |
| 3350 | 3377 |
| 3351 | 3378 |
| 3352 // This generates code that performs a charCodeAt() call or returns | 3379 // This generates code that performs a charCodeAt() call or returns |
| (...skipping 929 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4282 bool CodeGenerator::HasValidEntryRegisters() { | 4309 bool CodeGenerator::HasValidEntryRegisters() { |
| 4283 return (allocator()->count(eax) - frame()->register_count(eax) == 0) | 4310 return (allocator()->count(eax) - frame()->register_count(eax) == 0) |
| 4284 && (allocator()->count(ebx) - frame()->register_count(ebx) == 0) | 4311 && (allocator()->count(ebx) - frame()->register_count(ebx) == 0) |
| 4285 && (allocator()->count(ecx) - frame()->register_count(ecx) == 0) | 4312 && (allocator()->count(ecx) - frame()->register_count(ecx) == 0) |
| 4286 && (allocator()->count(edx) - frame()->register_count(edx) == 0) | 4313 && (allocator()->count(edx) - frame()->register_count(edx) == 0) |
| 4287 && (allocator()->count(edi) - frame()->register_count(edi) == 0); | 4314 && (allocator()->count(edi) - frame()->register_count(edi) == 0); |
| 4288 } | 4315 } |
| 4289 #endif | 4316 #endif |
| 4290 | 4317 |
| 4291 | 4318 |
| 4319 class DeferredReferenceGetKeyedValue: public DeferredCode { |
| 4320 public: |
| 4321 DeferredReferenceGetKeyedValue(CodeGenerator* generator, bool is_global) |
| 4322 : DeferredCode(generator), is_global_(is_global) { |
| 4323 set_comment("[ DeferredReferenceGetKeyedValue"); |
| 4324 } |
| 4325 |
| 4326 virtual void Generate() { |
| 4327 // The argument are actually passed in edx and on top of the frame. |
| 4328 enter()->Bind(); |
| 4329 VirtualFrame::SpilledScope spilled_scope(generator()); |
| 4330 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
| 4331 // Calculate the delta from the IC call instruction to the map |
| 4332 // check cmp instruction in the inlined version. This delta is |
| 4333 // stored in a test(eax, delta) instruction after the call so that |
| 4334 // we can find it in the IC initialization code and patch the cmp |
| 4335 // instruction. This means that we cannot allow test instructions |
| 4336 // after calls to KeyedLoadIC stubs in other places. |
| 4337 int delta_to_patch_site = __ SizeOfCodeGeneratedSince(patch_site()); |
| 4338 VirtualFrame* frame = generator()->frame(); |
| 4339 if (is_global_) { |
| 4340 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET_CONTEXT, 0); |
| 4341 } else { |
| 4342 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); |
| 4343 } |
| 4344 __ test(eax, Immediate(-delta_to_patch_site)); |
| 4345 __ IncrementCounter(&Counters::keyed_load_inline_miss, 1); |
| 4346 // The result is result is actually returned in eax. |
| 4347 exit()->Jump(); |
| 4348 } |
| 4349 |
| 4350 Label* patch_site() { return &patch_site_; } |
| 4351 |
| 4352 private: |
| 4353 Label patch_site_; |
| 4354 bool is_global_; |
| 4355 }; |
| 4356 |
| 4357 |
| 4292 #undef __ | 4358 #undef __ |
| 4293 #define __ masm-> | 4359 #define __ masm-> |
| 4294 | 4360 |
| 4295 Handle<String> Reference::GetName() { | 4361 Handle<String> Reference::GetName() { |
| 4296 ASSERT(type_ == NAMED); | 4362 ASSERT(type_ == NAMED); |
| 4297 Property* property = expression_->AsProperty(); | 4363 Property* property = expression_->AsProperty(); |
| 4298 if (property == NULL) { | 4364 if (property == NULL) { |
| 4299 // Global variable reference treated as a named property reference. | 4365 // Global variable reference treated as a named property reference. |
| 4300 VariableProxy* proxy = expression_->AsVariableProxy(); | 4366 VariableProxy* proxy = expression_->AsVariableProxy(); |
| 4301 ASSERT(proxy->AsVariable() != NULL); | 4367 ASSERT(proxy->AsVariable() != NULL); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 4318 switch (type_) { | 4384 switch (type_) { |
| 4319 case SLOT: { | 4385 case SLOT: { |
| 4320 Comment cmnt(masm, "[ Load from Slot"); | 4386 Comment cmnt(masm, "[ Load from Slot"); |
| 4321 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); | 4387 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); |
| 4322 ASSERT(slot != NULL); | 4388 ASSERT(slot != NULL); |
| 4323 cgen_->LoadFromSlot(slot, typeof_state); | 4389 cgen_->LoadFromSlot(slot, typeof_state); |
| 4324 break; | 4390 break; |
| 4325 } | 4391 } |
| 4326 | 4392 |
| 4327 case NAMED: { | 4393 case NAMED: { |
| 4328 // TODO(1241834): Make sure that this it is safe to ignore the | 4394 // TODO(1241834): Make sure that it is safe to ignore the |
| 4329 // distinction between expressions in a typeof and not in a typeof. If | 4395 // distinction between expressions in a typeof and not in a |
| 4330 // there is a chance that reference errors can be thrown below, we | 4396 // typeof. If there is a chance that reference errors can be |
| 4331 // must distinguish between the two kinds of loads (typeof expression | 4397 // thrown below, we must distinguish between the two kinds of |
| 4332 // loads must not throw a reference error). | 4398 // loads (typeof expression loads must not throw a reference |
| 4399 // error). |
| 4333 VirtualFrame::SpilledScope spilled_scope(cgen_); | 4400 VirtualFrame::SpilledScope spilled_scope(cgen_); |
| 4334 Comment cmnt(masm, "[ Load from named Property"); | 4401 Comment cmnt(masm, "[ Load from named Property"); |
| 4335 Handle<String> name(GetName()); | 4402 Handle<String> name(GetName()); |
| 4403 Variable* var = expression_->AsVariableProxy()->AsVariable(); |
| 4336 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 4404 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
| 4337 // Setup the name register. | 4405 // Setup the name register. |
| 4338 __ mov(ecx, name); | 4406 __ mov(ecx, name); |
| 4339 | |
| 4340 Variable* var = expression_->AsVariableProxy()->AsVariable(); | |
| 4341 if (var != NULL) { | 4407 if (var != NULL) { |
| 4342 ASSERT(var->is_global()); | 4408 ASSERT(var->is_global()); |
| 4343 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET_CONTEXT, 0); | 4409 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET_CONTEXT, 0); |
| 4344 } else { | 4410 } else { |
| 4345 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); | 4411 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); |
| 4346 } | 4412 } |
| 4347 frame->EmitPush(eax); // IC call leaves result in eax, push it out | 4413 frame->EmitPush(eax); // IC call leaves result in eax, push it out |
| 4348 break; | 4414 break; |
| 4349 } | 4415 } |
| 4350 | 4416 |
| 4351 case KEYED: { | 4417 case KEYED: { |
| 4352 // TODO(1241834): Make sure that this it is safe to ignore the | 4418 // TODO(1241834): Make sure that this it is safe to ignore the |
| 4353 // distinction between expressions in a typeof and not in a typeof. | 4419 // distinction between expressions in a typeof and not in a typeof. |
| 4354 VirtualFrame::SpilledScope spilled_scope(cgen_); | 4420 VirtualFrame::SpilledScope spilled_scope(cgen_); |
| 4355 Comment cmnt(masm, "[ Load from keyed Property"); | 4421 Comment cmnt(masm, "[ Load from keyed Property"); |
| 4356 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 4422 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
| 4357 | |
| 4358 Variable* var = expression_->AsVariableProxy()->AsVariable(); | 4423 Variable* var = expression_->AsVariableProxy()->AsVariable(); |
| 4359 if (var != NULL) { | 4424 bool is_global = var != NULL; |
| 4360 ASSERT(var->is_global()); | 4425 ASSERT(!is_global || var->is_global()); |
| 4361 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET_CONTEXT, 0); | 4426 // Inline array load code if inside of a loop. We do not know |
| 4427 // the receiver map yet, so we initially generate the code with |
| 4428 // a check against an invalid map. In the inline cache code, we |
| 4429 // patch the map check if appropriate. |
| 4430 if (cgen_->loop_nesting() > 0) { |
| 4431 Comment cmnt(masm, "[ Inlined array index load"); |
| 4432 DeferredReferenceGetKeyedValue* deferred = |
| 4433 new DeferredReferenceGetKeyedValue(cgen_, is_global); |
| 4434 // Load receiver and check that it is not a smi (only needed |
| 4435 // if this is not a load from the global context) and that it |
| 4436 // has the expected map. |
| 4437 __ mov(edx, Operand(esp, kPointerSize)); |
| 4438 if (!is_global) { |
| 4439 __ test(edx, Immediate(kSmiTagMask)); |
| 4440 deferred->enter()->Branch(zero, not_taken); |
| 4441 } |
| 4442 // Initially, use an invalid map. The map is patched in the IC |
| 4443 // initialization code. |
| 4444 __ bind(deferred->patch_site()); |
| 4445 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), |
| 4446 Immediate(Factory::null_value())); |
| 4447 deferred->enter()->Branch(not_equal, not_taken); |
| 4448 // Load key and check that it is a smi. |
| 4449 __ mov(eax, Operand(esp, 0)); |
| 4450 __ test(eax, Immediate(kSmiTagMask)); |
| 4451 deferred->enter()->Branch(not_zero, not_taken); |
| 4452 // Shift to get actual index value. |
| 4453 __ sar(eax, kSmiTagSize); |
| 4454 // Get the elements array from the receiver and check that it |
| 4455 // is not a dictionary. |
| 4456 __ mov(edx, FieldOperand(edx, JSObject::kElementsOffset)); |
| 4457 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), |
| 4458 Immediate(Factory::hash_table_map())); |
| 4459 deferred->enter()->Branch(equal, not_taken); |
| 4460 // Check that key is within bounds. |
| 4461 __ cmp(eax, FieldOperand(edx, Array::kLengthOffset)); |
| 4462 deferred->enter()->Branch(above_equal, not_taken); |
| 4463 // Load and check that the result is not the hole. |
| 4464 __ mov(eax, |
| 4465 Operand(edx, eax, times_4, Array::kHeaderSize - kHeapObjectTag)); |
| 4466 __ cmp(Operand(eax), Immediate(Factory::the_hole_value())); |
| 4467 deferred->enter()->Branch(equal, not_taken); |
| 4468 __ IncrementCounter(&Counters::keyed_load_inline, 1); |
| 4469 deferred->exit()->Bind(); |
| 4362 } else { | 4470 } else { |
| 4363 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); | 4471 Comment cmnt(masm, "[ Load from keyed Property"); |
| 4472 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
| 4473 if (is_global) { |
| 4474 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET_CONTEXT, 0); |
| 4475 } else { |
| 4476 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); |
| 4477 } |
| 4478 // Make sure that we do not have a test instruction after the |
| 4479 // call. A test instruction after the call is used to |
| 4480 // indicate that we have generated an inline version of the |
| 4481 // keyed load. The explicit nop instruction is here because |
| 4482 // the push that follows might be peep-hole optimized away. |
| 4483 __ nop(); |
| 4364 } | 4484 } |
| 4365 frame->EmitPush(eax); // IC call leaves result in eax, push it out | 4485 frame->EmitPush(eax); // IC call leaves result in eax, push it out |
| 4366 break; | 4486 break; |
| 4367 } | 4487 } |
| 4368 | 4488 |
| 4369 default: | 4489 default: |
| 4370 UNREACHABLE(); | 4490 UNREACHABLE(); |
| 4371 } | 4491 } |
| 4372 } | 4492 } |
| 4373 | 4493 |
| (...skipping 1450 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5824 | 5944 |
| 5825 // Slow-case: Go through the JavaScript implementation. | 5945 // Slow-case: Go through the JavaScript implementation. |
| 5826 __ bind(&slow); | 5946 __ bind(&slow); |
| 5827 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 5947 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 5828 } | 5948 } |
| 5829 | 5949 |
| 5830 | 5950 |
| 5831 #undef __ | 5951 #undef __ |
| 5832 | 5952 |
| 5833 } } // namespace v8::internal | 5953 } } // namespace v8::internal |
| OLD | NEW |