| 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 |