OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 496 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
507 | 507 |
508 MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) { | 508 MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) { |
509 switch (slot->type()) { | 509 switch (slot->type()) { |
510 case Slot::PARAMETER: | 510 case Slot::PARAMETER: |
511 case Slot::LOCAL: | 511 case Slot::LOCAL: |
512 return Operand(ebp, SlotOffset(slot)); | 512 return Operand(ebp, SlotOffset(slot)); |
513 case Slot::CONTEXT: { | 513 case Slot::CONTEXT: { |
514 int context_chain_length = | 514 int context_chain_length = |
515 scope()->ContextChainLength(slot->var()->scope()); | 515 scope()->ContextChainLength(slot->var()->scope()); |
516 __ LoadContext(scratch, context_chain_length); | 516 __ LoadContext(scratch, context_chain_length); |
517 return CodeGenerator::ContextOperand(scratch, slot->index()); | 517 return ContextOperand(scratch, slot->index()); |
518 } | 518 } |
519 case Slot::LOOKUP: | 519 case Slot::LOOKUP: |
520 UNREACHABLE(); | 520 UNREACHABLE(); |
521 } | 521 } |
522 UNREACHABLE(); | 522 UNREACHABLE(); |
523 return Operand(eax, 0); | 523 return Operand(eax, 0); |
524 } | 524 } |
525 | 525 |
526 | 526 |
527 void FullCodeGenerator::Move(Register destination, Slot* source) { | 527 void FullCodeGenerator::Move(Register destination, Slot* source) { |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
567 break; | 567 break; |
568 | 568 |
569 case Slot::CONTEXT: | 569 case Slot::CONTEXT: |
570 // We bypass the general EmitSlotSearch because we know more about | 570 // We bypass the general EmitSlotSearch because we know more about |
571 // this specific context. | 571 // this specific context. |
572 | 572 |
573 // The variable in the decl always resides in the current context. | 573 // The variable in the decl always resides in the current context. |
574 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); | 574 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); |
575 if (FLAG_debug_code) { | 575 if (FLAG_debug_code) { |
576 // Check if we have the correct context pointer. | 576 // Check if we have the correct context pointer. |
577 __ mov(ebx, | 577 __ mov(ebx, ContextOperand(esi, Context::FCONTEXT_INDEX)); |
578 CodeGenerator::ContextOperand(esi, Context::FCONTEXT_INDEX)); | |
579 __ cmp(ebx, Operand(esi)); | 578 __ cmp(ebx, Operand(esi)); |
580 __ Check(equal, "Unexpected declaration in current context."); | 579 __ Check(equal, "Unexpected declaration in current context."); |
581 } | 580 } |
582 if (mode == Variable::CONST) { | 581 if (mode == Variable::CONST) { |
583 __ mov(CodeGenerator::ContextOperand(esi, slot->index()), | 582 __ mov(ContextOperand(esi, slot->index()), |
584 Immediate(Factory::the_hole_value())); | 583 Immediate(Factory::the_hole_value())); |
585 // No write barrier since the hole value is in old space. | 584 // No write barrier since the hole value is in old space. |
586 } else if (function != NULL) { | 585 } else if (function != NULL) { |
587 VisitForValue(function, kAccumulator); | 586 VisitForValue(function, kAccumulator); |
588 __ mov(CodeGenerator::ContextOperand(esi, slot->index()), | 587 __ mov(ContextOperand(esi, slot->index()), result_register()); |
589 result_register()); | |
590 int offset = Context::SlotOffset(slot->index()); | 588 int offset = Context::SlotOffset(slot->index()); |
591 __ mov(ebx, esi); | 589 __ mov(ebx, esi); |
592 __ RecordWrite(ebx, offset, result_register(), ecx); | 590 __ RecordWrite(ebx, offset, result_register(), ecx); |
593 } | 591 } |
594 break; | 592 break; |
595 | 593 |
596 case Slot::LOOKUP: { | 594 case Slot::LOOKUP: { |
597 __ push(esi); | 595 __ push(esi); |
598 __ push(Immediate(variable->name())); | 596 __ push(Immediate(variable->name())); |
599 // Declaration nodes are always introduced in one of two modes. | 597 // Declaration nodes are always introduced in one of two modes. |
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
878 Apply(context_, eax); | 876 Apply(context_, eax); |
879 } | 877 } |
880 | 878 |
881 | 879 |
882 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { | 880 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { |
883 Comment cmnt(masm_, "[ VariableProxy"); | 881 Comment cmnt(masm_, "[ VariableProxy"); |
884 EmitVariableLoad(expr->var(), context_); | 882 EmitVariableLoad(expr->var(), context_); |
885 } | 883 } |
886 | 884 |
887 | 885 |
| 886 void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions( |
| 887 Slot* slot, |
| 888 TypeofState typeof_state, |
| 889 Label* slow) { |
| 890 Register context = esi; |
| 891 Register temp = edx; |
| 892 |
| 893 Scope* s = scope(); |
| 894 while (s != NULL) { |
| 895 if (s->num_heap_slots() > 0) { |
| 896 if (s->calls_eval()) { |
| 897 // Check that extension is NULL. |
| 898 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), |
| 899 Immediate(0)); |
| 900 __ j(not_equal, slow); |
| 901 } |
| 902 // Load next context in chain. |
| 903 __ mov(temp, ContextOperand(context, Context::CLOSURE_INDEX)); |
| 904 __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset)); |
| 905 // Walk the rest of the chain using a single register without |
| 906 // clobbering esi. |
| 907 context = temp; |
| 908 } |
| 909 // If no outer scope calls eval, we do not need to check more |
| 910 // context extensions. If we have reached an eval scope, we check |
| 911 // all extensions from this point. |
| 912 if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break; |
| 913 s = s->outer_scope(); |
| 914 } |
| 915 |
| 916 if (s != NULL && s->is_eval_scope()) { |
| 917 // Loop up the context chain. There is no frame effect so it is |
| 918 // safe to use raw labels here. |
| 919 Label next, fast; |
| 920 if (!context.is(temp)) { |
| 921 __ mov(temp, context); |
| 922 } |
| 923 __ bind(&next); |
| 924 // Terminate at global context. |
| 925 __ cmp(FieldOperand(temp, HeapObject::kMapOffset), |
| 926 Immediate(Factory::global_context_map())); |
| 927 __ j(equal, &fast); |
| 928 // Check that extension is NULL. |
| 929 __ cmp(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0)); |
| 930 __ j(not_equal, slow); |
| 931 // Load next context in chain. |
| 932 __ mov(temp, ContextOperand(temp, Context::CLOSURE_INDEX)); |
| 933 __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset)); |
| 934 __ jmp(&next); |
| 935 __ bind(&fast); |
| 936 } |
| 937 |
| 938 // All extension objects were empty and it is safe to use a global |
| 939 // load IC call. |
| 940 __ mov(eax, CodeGenerator::GlobalObject()); |
| 941 __ mov(ecx, slot->var()->name()); |
| 942 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
| 943 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) |
| 944 ? RelocInfo::CODE_TARGET |
| 945 : RelocInfo::CODE_TARGET_CONTEXT; |
| 946 __ call(ic, mode); |
| 947 } |
| 948 |
| 949 |
888 void FullCodeGenerator::EmitVariableLoad(Variable* var, | 950 void FullCodeGenerator::EmitVariableLoad(Variable* var, |
889 Expression::Context context) { | 951 Expression::Context context) { |
890 // Four cases: non-this global variables, lookup slots, all other | 952 // Four cases: non-this global variables, lookup slots, all other |
891 // types of slots, and parameters that rewrite to explicit property | 953 // types of slots, and parameters that rewrite to explicit property |
892 // accesses on the arguments object. | 954 // accesses on the arguments object. |
893 Slot* slot = var->slot(); | 955 Slot* slot = var->slot(); |
894 Property* property = var->AsProperty(); | 956 Property* property = var->AsProperty(); |
895 | 957 |
896 if (var->is_global() && !var->is_this()) { | 958 if (var->is_global() && !var->is_this()) { |
897 Comment cmnt(masm_, "Global variable"); | 959 Comment cmnt(masm_, "Global variable"); |
898 // Use inline caching. Variable name is passed in ecx and the global | 960 // Use inline caching. Variable name is passed in ecx and the global |
899 // object on the stack. | 961 // object on the stack. |
900 __ mov(eax, CodeGenerator::GlobalObject()); | 962 __ mov(eax, CodeGenerator::GlobalObject()); |
901 __ mov(ecx, var->name()); | 963 __ mov(ecx, var->name()); |
902 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 964 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
903 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 965 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
904 // By emitting a nop we make sure that we do not have a test eax | 966 // By emitting a nop we make sure that we do not have a test eax |
905 // instruction after the call it is treated specially by the LoadIC code | 967 // instruction after the call it is treated specially by the LoadIC code |
906 // Remember that the assembler may choose to do peephole optimization | 968 // Remember that the assembler may choose to do peephole optimization |
907 // (eg, push/pop elimination). | 969 // (eg, push/pop elimination). |
908 __ nop(); | 970 __ nop(); |
909 Apply(context, eax); | 971 Apply(context, eax); |
910 | 972 |
911 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { | 973 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { |
| 974 Label done, slow; |
| 975 |
| 976 // Generate fast-case code for variables that might be shadowed by |
| 977 // eval-introduced variables. Eval is used a lot without |
| 978 // introducing variables. In those cases, we do not want to |
| 979 // perform a runtime call for all variables in the scope |
| 980 // containing the eval. |
| 981 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { |
| 982 EmitLoadGlobalSlotCheckExtensions(slot, NOT_INSIDE_TYPEOF, &slow); |
| 983 Apply(context, eax); |
| 984 __ jmp(&done); |
| 985 } |
| 986 |
| 987 __ bind(&slow); |
912 Comment cmnt(masm_, "Lookup slot"); | 988 Comment cmnt(masm_, "Lookup slot"); |
913 __ push(esi); // Context. | 989 __ push(esi); // Context. |
914 __ push(Immediate(var->name())); | 990 __ push(Immediate(var->name())); |
915 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 991 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
916 Apply(context, eax); | 992 Apply(context, eax); |
| 993 __ bind(&done); |
917 | 994 |
918 } else if (slot != NULL) { | 995 } else if (slot != NULL) { |
919 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) | 996 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) |
920 ? "Context slot" | 997 ? "Context slot" |
921 : "Stack slot"); | 998 : "Stack slot"); |
922 if (var->mode() == Variable::CONST) { | 999 if (var->mode() == Variable::CONST) { |
923 // Constants may be the hole value if they have not been initialized. | 1000 // Constants may be the hole value if they have not been initialized. |
924 // Unhole them. | 1001 // Unhole them. |
925 Label done; | 1002 Label done; |
926 MemOperand slot_operand = EmitSlotSearch(slot, eax); | 1003 MemOperand slot_operand = EmitSlotSearch(slot, eax); |
(...skipping 1847 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2774 __ mov(eax, Factory::undefined_value()); | 2851 __ mov(eax, Factory::undefined_value()); |
2775 Apply(context_, eax); | 2852 Apply(context_, eax); |
2776 return; | 2853 return; |
2777 } | 2854 } |
2778 | 2855 |
2779 VisitForValue(args->at(1), kAccumulator); | 2856 VisitForValue(args->at(1), kAccumulator); |
2780 | 2857 |
2781 Register key = eax; | 2858 Register key = eax; |
2782 Register cache = ebx; | 2859 Register cache = ebx; |
2783 Register tmp = ecx; | 2860 Register tmp = ecx; |
2784 __ mov(cache, CodeGenerator::ContextOperand(esi, Context::GLOBAL_INDEX)); | 2861 __ mov(cache, ContextOperand(esi, Context::GLOBAL_INDEX)); |
2785 __ mov(cache, | 2862 __ mov(cache, |
2786 FieldOperand(cache, GlobalObject::kGlobalContextOffset)); | 2863 FieldOperand(cache, GlobalObject::kGlobalContextOffset)); |
2787 __ mov(cache, | 2864 __ mov(cache, ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX)); |
2788 CodeGenerator::ContextOperand( | |
2789 cache, Context::JSFUNCTION_RESULT_CACHES_INDEX)); | |
2790 __ mov(cache, | 2865 __ mov(cache, |
2791 FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id))); | 2866 FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id))); |
2792 | 2867 |
2793 Label done, not_found; | 2868 Label done, not_found; |
2794 // tmp now holds finger offset as a smi. | 2869 // tmp now holds finger offset as a smi. |
2795 ASSERT(kSmiTag == 0 && kSmiTagSize == 1); | 2870 ASSERT(kSmiTag == 0 && kSmiTagSize == 1); |
2796 __ mov(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset)); | 2871 __ mov(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset)); |
2797 __ cmp(key, CodeGenerator::FixedArrayElementOperand(cache, tmp)); | 2872 __ cmp(key, CodeGenerator::FixedArrayElementOperand(cache, tmp)); |
2798 __ j(not_equal, ¬_found); | 2873 __ j(not_equal, ¬_found); |
2799 | 2874 |
(...skipping 705 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3505 Register FullCodeGenerator::context_register() { return esi; } | 3580 Register FullCodeGenerator::context_register() { return esi; } |
3506 | 3581 |
3507 | 3582 |
3508 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { | 3583 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { |
3509 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset); | 3584 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset); |
3510 __ mov(Operand(ebp, frame_offset), value); | 3585 __ mov(Operand(ebp, frame_offset), value); |
3511 } | 3586 } |
3512 | 3587 |
3513 | 3588 |
3514 void FullCodeGenerator::LoadContextField(Register dst, int context_index) { | 3589 void FullCodeGenerator::LoadContextField(Register dst, int context_index) { |
3515 __ mov(dst, CodeGenerator::ContextOperand(esi, context_index)); | 3590 __ mov(dst, ContextOperand(esi, context_index)); |
3516 } | 3591 } |
3517 | 3592 |
3518 | 3593 |
3519 // ---------------------------------------------------------------------------- | 3594 // ---------------------------------------------------------------------------- |
3520 // Non-local control flow support. | 3595 // Non-local control flow support. |
3521 | 3596 |
3522 void FullCodeGenerator::EnterFinallyBlock() { | 3597 void FullCodeGenerator::EnterFinallyBlock() { |
3523 // Cook return address on top of stack (smi encoded Code* delta) | 3598 // Cook return address on top of stack (smi encoded Code* delta) |
3524 ASSERT(!result_register().is(edx)); | 3599 ASSERT(!result_register().is(edx)); |
3525 __ mov(edx, Operand(esp, 0)); | 3600 __ mov(edx, Operand(esp, 0)); |
(...skipping 19 matching lines...) Expand all Loading... |
3545 // And return. | 3620 // And return. |
3546 __ ret(0); | 3621 __ ret(0); |
3547 } | 3622 } |
3548 | 3623 |
3549 | 3624 |
3550 #undef __ | 3625 #undef __ |
3551 | 3626 |
3552 } } // namespace v8::internal | 3627 } } // namespace v8::internal |
3553 | 3628 |
3554 #endif // V8_TARGET_ARCH_IA32 | 3629 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |