OLD | NEW |
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 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 475 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
486 | 486 |
487 MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) { | 487 MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) { |
488 switch (slot->type()) { | 488 switch (slot->type()) { |
489 case Slot::PARAMETER: | 489 case Slot::PARAMETER: |
490 case Slot::LOCAL: | 490 case Slot::LOCAL: |
491 return MemOperand(fp, SlotOffset(slot)); | 491 return MemOperand(fp, SlotOffset(slot)); |
492 case Slot::CONTEXT: { | 492 case Slot::CONTEXT: { |
493 int context_chain_length = | 493 int context_chain_length = |
494 scope()->ContextChainLength(slot->var()->scope()); | 494 scope()->ContextChainLength(slot->var()->scope()); |
495 __ LoadContext(scratch, context_chain_length); | 495 __ LoadContext(scratch, context_chain_length); |
496 return CodeGenerator::ContextOperand(scratch, slot->index()); | 496 return ContextOperand(scratch, slot->index()); |
497 } | 497 } |
498 case Slot::LOOKUP: | 498 case Slot::LOOKUP: |
499 UNREACHABLE(); | 499 UNREACHABLE(); |
500 } | 500 } |
501 UNREACHABLE(); | 501 UNREACHABLE(); |
502 return MemOperand(r0, 0); | 502 return MemOperand(r0, 0); |
503 } | 503 } |
504 | 504 |
505 | 505 |
506 void FullCodeGenerator::Move(Register destination, Slot* source) { | 506 void FullCodeGenerator::Move(Register destination, Slot* source) { |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
550 break; | 550 break; |
551 | 551 |
552 case Slot::CONTEXT: | 552 case Slot::CONTEXT: |
553 // We bypass the general EmitSlotSearch because we know more about | 553 // We bypass the general EmitSlotSearch because we know more about |
554 // this specific context. | 554 // this specific context. |
555 | 555 |
556 // The variable in the decl always resides in the current context. | 556 // The variable in the decl always resides in the current context. |
557 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); | 557 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); |
558 if (FLAG_debug_code) { | 558 if (FLAG_debug_code) { |
559 // Check if we have the correct context pointer. | 559 // Check if we have the correct context pointer. |
560 __ ldr(r1, | 560 __ ldr(r1, ContextOperand(cp, Context::FCONTEXT_INDEX)); |
561 CodeGenerator::ContextOperand(cp, Context::FCONTEXT_INDEX)); | |
562 __ cmp(r1, cp); | 561 __ cmp(r1, cp); |
563 __ Check(eq, "Unexpected declaration in current context."); | 562 __ Check(eq, "Unexpected declaration in current context."); |
564 } | 563 } |
565 if (mode == Variable::CONST) { | 564 if (mode == Variable::CONST) { |
566 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 565 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
567 __ str(ip, CodeGenerator::ContextOperand(cp, slot->index())); | 566 __ str(ip, ContextOperand(cp, slot->index())); |
568 // No write barrier since the_hole_value is in old space. | 567 // No write barrier since the_hole_value is in old space. |
569 } else if (function != NULL) { | 568 } else if (function != NULL) { |
570 VisitForValue(function, kAccumulator); | 569 VisitForValue(function, kAccumulator); |
571 __ str(result_register(), | 570 __ str(result_register(), ContextOperand(cp, slot->index())); |
572 CodeGenerator::ContextOperand(cp, slot->index())); | |
573 int offset = Context::SlotOffset(slot->index()); | 571 int offset = Context::SlotOffset(slot->index()); |
574 // We know that we have written a function, which is not a smi. | 572 // We know that we have written a function, which is not a smi. |
575 __ mov(r1, Operand(cp)); | 573 __ mov(r1, Operand(cp)); |
576 __ RecordWrite(r1, Operand(offset), r2, result_register()); | 574 __ RecordWrite(r1, Operand(offset), r2, result_register()); |
577 } | 575 } |
578 break; | 576 break; |
579 | 577 |
580 case Slot::LOOKUP: { | 578 case Slot::LOOKUP: { |
581 __ mov(r2, Operand(variable->name())); | 579 __ mov(r2, Operand(variable->name())); |
582 // Declaration nodes are always introduced in one of two modes. | 580 // Declaration nodes are always introduced in one of two modes. |
(...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
874 Apply(context_, r0); | 872 Apply(context_, r0); |
875 } | 873 } |
876 | 874 |
877 | 875 |
878 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { | 876 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { |
879 Comment cmnt(masm_, "[ VariableProxy"); | 877 Comment cmnt(masm_, "[ VariableProxy"); |
880 EmitVariableLoad(expr->var(), context_); | 878 EmitVariableLoad(expr->var(), context_); |
881 } | 879 } |
882 | 880 |
883 | 881 |
| 882 void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions( |
| 883 Slot* slot, |
| 884 TypeofState typeof_state, |
| 885 Label* slow) { |
| 886 Register current = cp; |
| 887 Register next = r1; |
| 888 Register temp = r2; |
| 889 |
| 890 Scope* s = scope(); |
| 891 while (s != NULL) { |
| 892 if (s->num_heap_slots() > 0) { |
| 893 if (s->calls_eval()) { |
| 894 // Check that extension is NULL. |
| 895 __ ldr(temp, ContextOperand(current, Context::EXTENSION_INDEX)); |
| 896 __ tst(temp, temp); |
| 897 __ b(ne, slow); |
| 898 } |
| 899 // Load next context in chain. |
| 900 __ ldr(next, ContextOperand(current, Context::CLOSURE_INDEX)); |
| 901 __ ldr(next, FieldMemOperand(next, JSFunction::kContextOffset)); |
| 902 // Walk the rest of the chain using a single register without |
| 903 // clobbering cp. |
| 904 current = next; |
| 905 } |
| 906 // If no outer scope calls eval, we do not need to check more |
| 907 // context extensions. |
| 908 if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break; |
| 909 s = s->outer_scope(); |
| 910 } |
| 911 |
| 912 if (s->is_eval_scope()) { |
| 913 Label loop, fast; |
| 914 if (!current.is(next)) { |
| 915 __ Move(next, current); |
| 916 } |
| 917 __ bind(&loop); |
| 918 // Terminate at global context. |
| 919 __ ldr(temp, FieldMemOperand(next, HeapObject::kMapOffset)); |
| 920 __ LoadRoot(ip, Heap::kGlobalContextMapRootIndex); |
| 921 __ cmp(temp, ip); |
| 922 __ b(eq, &fast); |
| 923 // Check that extension is NULL. |
| 924 __ ldr(temp, ContextOperand(next, Context::EXTENSION_INDEX)); |
| 925 __ tst(temp, temp); |
| 926 __ b(ne, slow); |
| 927 // Load next context in chain. |
| 928 __ ldr(next, ContextOperand(next, Context::CLOSURE_INDEX)); |
| 929 __ ldr(next, FieldMemOperand(next, JSFunction::kContextOffset)); |
| 930 __ b(&loop); |
| 931 __ bind(&fast); |
| 932 } |
| 933 |
| 934 __ ldr(r0, CodeGenerator::GlobalObject()); |
| 935 __ mov(r2, Operand(slot->var()->name())); |
| 936 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) |
| 937 ? RelocInfo::CODE_TARGET |
| 938 : RelocInfo::CODE_TARGET_CONTEXT; |
| 939 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
| 940 __ Call(ic, mode); |
| 941 } |
| 942 |
| 943 |
884 void FullCodeGenerator::EmitVariableLoad(Variable* var, | 944 void FullCodeGenerator::EmitVariableLoad(Variable* var, |
885 Expression::Context context) { | 945 Expression::Context context) { |
886 // Four cases: non-this global variables, lookup slots, all other | 946 // Four cases: non-this global variables, lookup slots, all other |
887 // types of slots, and parameters that rewrite to explicit property | 947 // types of slots, and parameters that rewrite to explicit property |
888 // accesses on the arguments object. | 948 // accesses on the arguments object. |
889 Slot* slot = var->slot(); | 949 Slot* slot = var->slot(); |
890 Property* property = var->AsProperty(); | 950 Property* property = var->AsProperty(); |
891 | 951 |
892 if (var->is_global() && !var->is_this()) { | 952 if (var->is_global() && !var->is_this()) { |
893 Comment cmnt(masm_, "Global variable"); | 953 Comment cmnt(masm_, "Global variable"); |
894 // Use inline caching. Variable name is passed in r2 and the global | 954 // Use inline caching. Variable name is passed in r2 and the global |
895 // object (receiver) in r0. | 955 // object (receiver) in r0. |
896 __ ldr(r0, CodeGenerator::GlobalObject()); | 956 __ ldr(r0, CodeGenerator::GlobalObject()); |
897 __ mov(r2, Operand(var->name())); | 957 __ mov(r2, Operand(var->name())); |
898 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 958 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
899 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 959 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
900 Apply(context, r0); | 960 Apply(context, r0); |
901 | 961 |
902 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { | 962 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { |
| 963 Label done, slow; |
| 964 |
| 965 // Generate fast-case code for variables that might be shadowed by |
| 966 // eval-introduced variables. Eval is used a lot without |
| 967 // introducing variables. In those cases, we do not want to |
| 968 // perform a runtime call for all variables in the scope |
| 969 // containing the eval. |
| 970 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { |
| 971 EmitLoadGlobalSlotCheckExtensions(slot, NOT_INSIDE_TYPEOF, &slow); |
| 972 Apply(context, r0); |
| 973 __ jmp(&done); |
| 974 } |
| 975 |
| 976 __ bind(&slow); |
903 Comment cmnt(masm_, "Lookup slot"); | 977 Comment cmnt(masm_, "Lookup slot"); |
904 __ mov(r1, Operand(var->name())); | 978 __ mov(r1, Operand(var->name())); |
905 __ Push(cp, r1); // Context and name. | 979 __ Push(cp, r1); // Context and name. |
906 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 980 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
907 Apply(context, r0); | 981 Apply(context, r0); |
| 982 __ bind(&done); |
908 | 983 |
909 } else if (slot != NULL) { | 984 } else if (slot != NULL) { |
910 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) | 985 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) |
911 ? "Context slot" | 986 ? "Context slot" |
912 : "Stack slot"); | 987 : "Stack slot"); |
913 if (var->mode() == Variable::CONST) { | 988 if (var->mode() == Variable::CONST) { |
914 // Constants may be the hole value if they have not been initialized. | 989 // Constants may be the hole value if they have not been initialized. |
915 // Unhole them. | 990 // Unhole them. |
916 Label done; | 991 Label done; |
917 MemOperand slot_operand = EmitSlotSearch(slot, r0); | 992 MemOperand slot_operand = EmitSlotSearch(slot, r0); |
(...skipping 1539 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2457 __ Abort("Attempt to use undefined cache."); | 2532 __ Abort("Attempt to use undefined cache."); |
2458 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); | 2533 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); |
2459 Apply(context_, r0); | 2534 Apply(context_, r0); |
2460 return; | 2535 return; |
2461 } | 2536 } |
2462 | 2537 |
2463 VisitForValue(args->at(1), kAccumulator); | 2538 VisitForValue(args->at(1), kAccumulator); |
2464 | 2539 |
2465 Register key = r0; | 2540 Register key = r0; |
2466 Register cache = r1; | 2541 Register cache = r1; |
2467 __ ldr(cache, CodeGenerator::ContextOperand(cp, Context::GLOBAL_INDEX)); | 2542 __ ldr(cache, ContextOperand(cp, Context::GLOBAL_INDEX)); |
2468 __ ldr(cache, FieldMemOperand(cache, GlobalObject::kGlobalContextOffset)); | 2543 __ ldr(cache, FieldMemOperand(cache, GlobalObject::kGlobalContextOffset)); |
2469 __ ldr(cache, | 2544 __ ldr(cache, ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX)); |
2470 CodeGenerator::ContextOperand( | |
2471 cache, Context::JSFUNCTION_RESULT_CACHES_INDEX)); | |
2472 __ ldr(cache, | 2545 __ ldr(cache, |
2473 FieldMemOperand(cache, FixedArray::OffsetOfElementAt(cache_id))); | 2546 FieldMemOperand(cache, FixedArray::OffsetOfElementAt(cache_id))); |
2474 | 2547 |
2475 | 2548 |
2476 Label done, not_found; | 2549 Label done, not_found; |
2477 // tmp now holds finger offset as a smi. | 2550 // tmp now holds finger offset as a smi. |
2478 ASSERT(kSmiTag == 0 && kSmiTagSize == 1); | 2551 ASSERT(kSmiTag == 0 && kSmiTagSize == 1); |
2479 __ ldr(r2, FieldMemOperand(cache, JSFunctionResultCache::kFingerOffset)); | 2552 __ ldr(r2, FieldMemOperand(cache, JSFunctionResultCache::kFingerOffset)); |
2480 // r2 now holds finger offset as a smi. | 2553 // r2 now holds finger offset as a smi. |
2481 __ add(r3, cache, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | 2554 __ add(r3, cache, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
(...skipping 698 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3180 Register FullCodeGenerator::context_register() { return cp; } | 3253 Register FullCodeGenerator::context_register() { return cp; } |
3181 | 3254 |
3182 | 3255 |
3183 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { | 3256 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { |
3184 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset); | 3257 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset); |
3185 __ str(value, MemOperand(fp, frame_offset)); | 3258 __ str(value, MemOperand(fp, frame_offset)); |
3186 } | 3259 } |
3187 | 3260 |
3188 | 3261 |
3189 void FullCodeGenerator::LoadContextField(Register dst, int context_index) { | 3262 void FullCodeGenerator::LoadContextField(Register dst, int context_index) { |
3190 __ ldr(dst, CodeGenerator::ContextOperand(cp, context_index)); | 3263 __ ldr(dst, ContextOperand(cp, context_index)); |
3191 } | 3264 } |
3192 | 3265 |
3193 | 3266 |
3194 // ---------------------------------------------------------------------------- | 3267 // ---------------------------------------------------------------------------- |
3195 // Non-local control flow support. | 3268 // Non-local control flow support. |
3196 | 3269 |
3197 void FullCodeGenerator::EnterFinallyBlock() { | 3270 void FullCodeGenerator::EnterFinallyBlock() { |
3198 ASSERT(!result_register().is(r1)); | 3271 ASSERT(!result_register().is(r1)); |
3199 // Store result register while executing finally block. | 3272 // Store result register while executing finally block. |
3200 __ push(result_register()); | 3273 __ push(result_register()); |
(...skipping 16 matching lines...) Expand all Loading... |
3217 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value. | 3290 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value. |
3218 __ add(pc, r1, Operand(masm_->CodeObject())); | 3291 __ add(pc, r1, Operand(masm_->CodeObject())); |
3219 } | 3292 } |
3220 | 3293 |
3221 | 3294 |
3222 #undef __ | 3295 #undef __ |
3223 | 3296 |
3224 } } // namespace v8::internal | 3297 } } // namespace v8::internal |
3225 | 3298 |
3226 #endif // V8_TARGET_ARCH_ARM | 3299 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |