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 489 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
500 | 500 |
501 MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) { | 501 MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) { |
502 switch (slot->type()) { | 502 switch (slot->type()) { |
503 case Slot::PARAMETER: | 503 case Slot::PARAMETER: |
504 case Slot::LOCAL: | 504 case Slot::LOCAL: |
505 return Operand(rbp, SlotOffset(slot)); | 505 return Operand(rbp, SlotOffset(slot)); |
506 case Slot::CONTEXT: { | 506 case Slot::CONTEXT: { |
507 int context_chain_length = | 507 int context_chain_length = |
508 scope()->ContextChainLength(slot->var()->scope()); | 508 scope()->ContextChainLength(slot->var()->scope()); |
509 __ LoadContext(scratch, context_chain_length); | 509 __ LoadContext(scratch, context_chain_length); |
510 return CodeGenerator::ContextOperand(scratch, slot->index()); | 510 return ContextOperand(scratch, slot->index()); |
511 } | 511 } |
512 case Slot::LOOKUP: | 512 case Slot::LOOKUP: |
513 UNREACHABLE(); | 513 UNREACHABLE(); |
514 } | 514 } |
515 UNREACHABLE(); | 515 UNREACHABLE(); |
516 return Operand(rax, 0); | 516 return Operand(rax, 0); |
517 } | 517 } |
518 | 518 |
519 | 519 |
520 void FullCodeGenerator::Move(Register destination, Slot* source) { | 520 void FullCodeGenerator::Move(Register destination, Slot* source) { |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
561 break; | 561 break; |
562 | 562 |
563 case Slot::CONTEXT: | 563 case Slot::CONTEXT: |
564 // We bypass the general EmitSlotSearch because we know more about | 564 // We bypass the general EmitSlotSearch because we know more about |
565 // this specific context. | 565 // this specific context. |
566 | 566 |
567 // The variable in the decl always resides in the current context. | 567 // The variable in the decl always resides in the current context. |
568 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); | 568 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); |
569 if (FLAG_debug_code) { | 569 if (FLAG_debug_code) { |
570 // Check if we have the correct context pointer. | 570 // Check if we have the correct context pointer. |
571 __ movq(rbx, | 571 __ movq(rbx, ContextOperand(rsi, Context::FCONTEXT_INDEX)); |
572 CodeGenerator::ContextOperand(rsi, Context::FCONTEXT_INDEX)); | |
573 __ cmpq(rbx, rsi); | 572 __ cmpq(rbx, rsi); |
574 __ Check(equal, "Unexpected declaration in current context."); | 573 __ Check(equal, "Unexpected declaration in current context."); |
575 } | 574 } |
576 if (mode == Variable::CONST) { | 575 if (mode == Variable::CONST) { |
577 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); | 576 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); |
578 __ movq(CodeGenerator::ContextOperand(rsi, slot->index()), | 577 __ movq(ContextOperand(rsi, slot->index()), kScratchRegister); |
579 kScratchRegister); | |
580 // No write barrier since the hole value is in old space. | 578 // No write barrier since the hole value is in old space. |
581 } else if (function != NULL) { | 579 } else if (function != NULL) { |
582 VisitForValue(function, kAccumulator); | 580 VisitForValue(function, kAccumulator); |
583 __ movq(CodeGenerator::ContextOperand(rsi, slot->index()), | 581 __ movq(ContextOperand(rsi, slot->index()), result_register()); |
584 result_register()); | |
585 int offset = Context::SlotOffset(slot->index()); | 582 int offset = Context::SlotOffset(slot->index()); |
586 __ movq(rbx, rsi); | 583 __ movq(rbx, rsi); |
587 __ RecordWrite(rbx, offset, result_register(), rcx); | 584 __ RecordWrite(rbx, offset, result_register(), rcx); |
588 } | 585 } |
589 break; | 586 break; |
590 | 587 |
591 case Slot::LOOKUP: { | 588 case Slot::LOOKUP: { |
592 __ push(rsi); | 589 __ push(rsi); |
593 __ Push(variable->name()); | 590 __ Push(variable->name()); |
594 // Declaration nodes are always introduced in one of two modes. | 591 // Declaration nodes are always introduced in one of two modes. |
(...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
874 Apply(context_, rax); | 871 Apply(context_, rax); |
875 } | 872 } |
876 | 873 |
877 | 874 |
878 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { | 875 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { |
879 Comment cmnt(masm_, "[ VariableProxy"); | 876 Comment cmnt(masm_, "[ VariableProxy"); |
880 EmitVariableLoad(expr->var(), context_); | 877 EmitVariableLoad(expr->var(), context_); |
881 } | 878 } |
882 | 879 |
883 | 880 |
| 881 void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions( |
| 882 Slot* slot, |
| 883 TypeofState typeof_state, |
| 884 Label* slow) { |
| 885 Register context = rsi; |
| 886 Register temp = rdx; |
| 887 |
| 888 Scope* s = scope(); |
| 889 while (s != NULL) { |
| 890 if (s->num_heap_slots() > 0) { |
| 891 if (s->calls_eval()) { |
| 892 // Check that extension is NULL. |
| 893 __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX), |
| 894 Immediate(0)); |
| 895 __ j(not_equal, slow); |
| 896 } |
| 897 // Load next context in chain. |
| 898 __ movq(temp, ContextOperand(context, Context::CLOSURE_INDEX)); |
| 899 __ movq(temp, FieldOperand(temp, JSFunction::kContextOffset)); |
| 900 // Walk the rest of the chain using a single register without |
| 901 // clobbering rsi. |
| 902 context = temp; |
| 903 } |
| 904 // If no outer scope calls eval, we do not need to check more |
| 905 // context extensions. If we have reached an eval scope, we check |
| 906 // all extensions from this point. |
| 907 if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break; |
| 908 s = s->outer_scope(); |
| 909 } |
| 910 |
| 911 if (s != NULL && s->is_eval_scope()) { |
| 912 // Loop up the context chain. There is no frame effect so it is |
| 913 // safe to use raw labels here. |
| 914 Label next, fast; |
| 915 if (!context.is(temp)) { |
| 916 __ movq(temp, context); |
| 917 } |
| 918 // Load map for comparison into register, outside loop. |
| 919 __ LoadRoot(kScratchRegister, Heap::kGlobalContextMapRootIndex); |
| 920 __ bind(&next); |
| 921 // Terminate at global context. |
| 922 __ cmpq(kScratchRegister, FieldOperand(temp, HeapObject::kMapOffset)); |
| 923 __ j(equal, &fast); |
| 924 // Check that extension is NULL. |
| 925 __ cmpq(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0)); |
| 926 __ j(not_equal, slow); |
| 927 // Load next context in chain. |
| 928 __ movq(temp, ContextOperand(temp, Context::CLOSURE_INDEX)); |
| 929 __ movq(temp, FieldOperand(temp, JSFunction::kContextOffset)); |
| 930 __ jmp(&next); |
| 931 __ bind(&fast); |
| 932 } |
| 933 |
| 934 // All extension objects were empty and it is safe to use a global |
| 935 // load IC call. |
| 936 __ movq(rax, CodeGenerator::GlobalObject()); |
| 937 __ Move(rcx, slot->var()->name()); |
| 938 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
| 939 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) |
| 940 ? RelocInfo::CODE_TARGET |
| 941 : RelocInfo::CODE_TARGET_CONTEXT; |
| 942 __ call(ic, mode); |
| 943 } |
| 944 |
| 945 |
884 void FullCodeGenerator::EmitVariableLoad(Variable* var, | 946 void FullCodeGenerator::EmitVariableLoad(Variable* var, |
885 Expression::Context context) { | 947 Expression::Context context) { |
886 // Four cases: non-this global variables, lookup slots, all other | 948 // Four cases: non-this global variables, lookup slots, all other |
887 // types of slots, and parameters that rewrite to explicit property | 949 // types of slots, and parameters that rewrite to explicit property |
888 // accesses on the arguments object. | 950 // accesses on the arguments object. |
889 Slot* slot = var->slot(); | 951 Slot* slot = var->slot(); |
890 Property* property = var->AsProperty(); | 952 Property* property = var->AsProperty(); |
891 | 953 |
892 if (var->is_global() && !var->is_this()) { | 954 if (var->is_global() && !var->is_this()) { |
893 Comment cmnt(masm_, "Global variable"); | 955 Comment cmnt(masm_, "Global variable"); |
894 // Use inline caching. Variable name is passed in rcx and the global | 956 // Use inline caching. Variable name is passed in rcx and the global |
895 // object on the stack. | 957 // object on the stack. |
896 __ Move(rcx, var->name()); | 958 __ Move(rcx, var->name()); |
897 __ movq(rax, CodeGenerator::GlobalObject()); | 959 __ movq(rax, CodeGenerator::GlobalObject()); |
898 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 960 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
899 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 961 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
900 // A test rax instruction following the call is used by the IC to | 962 // A test rax instruction following the call is used by the IC to |
901 // indicate that the inobject property case was inlined. Ensure there | 963 // indicate that the inobject property case was inlined. Ensure there |
902 // is no test rax instruction here. | 964 // is no test rax instruction here. |
903 __ nop(); | 965 __ nop(); |
904 Apply(context, rax); | 966 Apply(context, rax); |
905 | 967 |
906 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { | 968 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { |
| 969 Label done, slow; |
| 970 |
| 971 // Generate fast-case code for variables that might be shadowed by |
| 972 // eval-introduced variables. Eval is used a lot without |
| 973 // introducing variables. In those cases, we do not want to |
| 974 // perform a runtime call for all variables in the scope |
| 975 // containing the eval. |
| 976 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { |
| 977 EmitLoadGlobalSlotCheckExtensions(slot, NOT_INSIDE_TYPEOF, &slow); |
| 978 Apply(context, rax); |
| 979 __ jmp(&done); |
| 980 } |
| 981 |
| 982 __ bind(&slow); |
907 Comment cmnt(masm_, "Lookup slot"); | 983 Comment cmnt(masm_, "Lookup slot"); |
908 __ push(rsi); // Context. | 984 __ push(rsi); // Context. |
909 __ Push(var->name()); | 985 __ Push(var->name()); |
910 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 986 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
911 Apply(context, rax); | 987 Apply(context, rax); |
| 988 __ bind(&done); |
912 | 989 |
913 } else if (slot != NULL) { | 990 } else if (slot != NULL) { |
914 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) | 991 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) |
915 ? "Context slot" | 992 ? "Context slot" |
916 : "Stack slot"); | 993 : "Stack slot"); |
917 if (var->mode() == Variable::CONST) { | 994 if (var->mode() == Variable::CONST) { |
918 // Constants may be the hole value if they have not been initialized. | 995 // Constants may be the hole value if they have not been initialized. |
919 // Unhole them. | 996 // Unhole them. |
920 Label done; | 997 Label done; |
921 MemOperand slot_operand = EmitSlotSearch(slot, rax); | 998 MemOperand slot_operand = EmitSlotSearch(slot, rax); |
(...skipping 1593 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2515 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); | 2592 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); |
2516 Apply(context_, rax); | 2593 Apply(context_, rax); |
2517 return; | 2594 return; |
2518 } | 2595 } |
2519 | 2596 |
2520 VisitForValue(args->at(1), kAccumulator); | 2597 VisitForValue(args->at(1), kAccumulator); |
2521 | 2598 |
2522 Register key = rax; | 2599 Register key = rax; |
2523 Register cache = rbx; | 2600 Register cache = rbx; |
2524 Register tmp = rcx; | 2601 Register tmp = rcx; |
2525 __ movq(cache, CodeGenerator::ContextOperand(rsi, Context::GLOBAL_INDEX)); | 2602 __ movq(cache, ContextOperand(rsi, Context::GLOBAL_INDEX)); |
2526 __ movq(cache, | 2603 __ movq(cache, |
2527 FieldOperand(cache, GlobalObject::kGlobalContextOffset)); | 2604 FieldOperand(cache, GlobalObject::kGlobalContextOffset)); |
2528 __ movq(cache, | 2605 __ movq(cache, |
2529 CodeGenerator::ContextOperand( | 2606 ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX)); |
2530 cache, Context::JSFUNCTION_RESULT_CACHES_INDEX)); | |
2531 __ movq(cache, | 2607 __ movq(cache, |
2532 FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id))); | 2608 FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id))); |
2533 | 2609 |
2534 Label done, not_found; | 2610 Label done, not_found; |
2535 // tmp now holds finger offset as a smi. | 2611 // tmp now holds finger offset as a smi. |
2536 ASSERT(kSmiTag == 0 && kSmiTagSize == 1); | 2612 ASSERT(kSmiTag == 0 && kSmiTagSize == 1); |
2537 __ movq(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset)); | 2613 __ movq(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset)); |
2538 SmiIndex index = | 2614 SmiIndex index = |
2539 __ SmiToIndex(kScratchRegister, tmp, kPointerSizeLog2); | 2615 __ SmiToIndex(kScratchRegister, tmp, kPointerSizeLog2); |
2540 __ cmpq(key, FieldOperand(cache, | 2616 __ cmpq(key, FieldOperand(cache, |
(...skipping 695 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3236 Register FullCodeGenerator::context_register() { return rsi; } | 3312 Register FullCodeGenerator::context_register() { return rsi; } |
3237 | 3313 |
3238 | 3314 |
3239 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { | 3315 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { |
3240 ASSERT(IsAligned(frame_offset, kPointerSize)); | 3316 ASSERT(IsAligned(frame_offset, kPointerSize)); |
3241 __ movq(Operand(rbp, frame_offset), value); | 3317 __ movq(Operand(rbp, frame_offset), value); |
3242 } | 3318 } |
3243 | 3319 |
3244 | 3320 |
3245 void FullCodeGenerator::LoadContextField(Register dst, int context_index) { | 3321 void FullCodeGenerator::LoadContextField(Register dst, int context_index) { |
3246 __ movq(dst, CodeGenerator::ContextOperand(rsi, context_index)); | 3322 __ movq(dst, ContextOperand(rsi, context_index)); |
3247 } | 3323 } |
3248 | 3324 |
3249 | 3325 |
3250 // ---------------------------------------------------------------------------- | 3326 // ---------------------------------------------------------------------------- |
3251 // Non-local control flow support. | 3327 // Non-local control flow support. |
3252 | 3328 |
3253 | 3329 |
3254 void FullCodeGenerator::EnterFinallyBlock() { | 3330 void FullCodeGenerator::EnterFinallyBlock() { |
3255 ASSERT(!result_register().is(rdx)); | 3331 ASSERT(!result_register().is(rdx)); |
3256 ASSERT(!result_register().is(rcx)); | 3332 ASSERT(!result_register().is(rcx)); |
(...skipping 23 matching lines...) Expand all Loading... |
3280 __ ret(0); | 3356 __ ret(0); |
3281 } | 3357 } |
3282 | 3358 |
3283 | 3359 |
3284 #undef __ | 3360 #undef __ |
3285 | 3361 |
3286 | 3362 |
3287 } } // namespace v8::internal | 3363 } } // namespace v8::internal |
3288 | 3364 |
3289 #endif // V8_TARGET_ARCH_X64 | 3365 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |