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