OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 592 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
603 void FullCodeGenerator::Move(Slot* dst, | 603 void FullCodeGenerator::Move(Slot* dst, |
604 Register src, | 604 Register src, |
605 Register scratch1, | 605 Register scratch1, |
606 Register scratch2) { | 606 Register scratch2) { |
607 ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented. | 607 ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented. |
608 ASSERT(!scratch1.is(src) && !scratch2.is(src)); | 608 ASSERT(!scratch1.is(src) && !scratch2.is(src)); |
609 MemOperand location = EmitSlotSearch(dst, scratch1); | 609 MemOperand location = EmitSlotSearch(dst, scratch1); |
610 __ mov(location, src); | 610 __ mov(location, src); |
611 // Emit the write barrier code if the location is in the heap. | 611 // Emit the write barrier code if the location is in the heap. |
612 if (dst->type() == Slot::CONTEXT) { | 612 if (dst->type() == Slot::CONTEXT) { |
613 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize; | 613 int offset = Context::SlotOffset(dst->index()); |
614 __ RecordWrite(scratch1, offset, src, scratch2); | 614 __ RecordWrite(scratch1, offset, src, scratch2); |
615 } | 615 } |
616 } | 616 } |
617 | 617 |
618 | 618 |
619 void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state, | 619 void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state, |
620 bool should_normalize, | 620 bool should_normalize, |
621 Label* if_true, | 621 Label* if_true, |
622 Label* if_false) { | 622 Label* if_false) { |
623 // Only prepare for bailouts before splits if we're in a test | 623 // Only prepare for bailouts before splits if we're in a test |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
659 } else if (function != NULL) { | 659 } else if (function != NULL) { |
660 VisitForAccumulatorValue(function); | 660 VisitForAccumulatorValue(function); |
661 __ mov(Operand(ebp, SlotOffset(slot)), result_register()); | 661 __ mov(Operand(ebp, SlotOffset(slot)), result_register()); |
662 } | 662 } |
663 break; | 663 break; |
664 | 664 |
665 case Slot::CONTEXT: | 665 case Slot::CONTEXT: |
666 // We bypass the general EmitSlotSearch because we know more about | 666 // We bypass the general EmitSlotSearch because we know more about |
667 // this specific context. | 667 // this specific context. |
668 | 668 |
669 // The variable in the decl always resides in the current context. | 669 // The variable in the decl always resides in the current function |
| 670 // context. |
670 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); | 671 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); |
671 if (FLAG_debug_code) { | 672 if (FLAG_debug_code) { |
672 // Check if we have the correct context pointer. | 673 // Check that we're not inside a 'with'. |
673 __ mov(ebx, ContextOperand(esi, Context::FCONTEXT_INDEX)); | 674 __ mov(ebx, ContextOperand(esi, Context::FCONTEXT_INDEX)); |
674 __ cmp(ebx, Operand(esi)); | 675 __ cmp(ebx, Operand(esi)); |
675 __ Check(equal, "Unexpected declaration in current context."); | 676 __ Check(equal, "Unexpected declaration in current context."); |
676 } | 677 } |
677 if (mode == Variable::CONST) { | 678 if (mode == Variable::CONST) { |
678 __ mov(ContextOperand(esi, slot->index()), | 679 __ mov(ContextOperand(esi, slot->index()), |
679 Immediate(Factory::the_hole_value())); | 680 Immediate(Factory::the_hole_value())); |
680 // No write barrier since the hole value is in old space. | 681 // No write barrier since the hole value is in old space. |
681 } else if (function != NULL) { | 682 } else if (function != NULL) { |
682 VisitForAccumulatorValue(function); | 683 VisitForAccumulatorValue(function); |
(...skipping 434 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1117 } | 1118 } |
1118 __ mov(temp, ContextOperand(context, Context::CLOSURE_INDEX)); | 1119 __ mov(temp, ContextOperand(context, Context::CLOSURE_INDEX)); |
1119 __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset)); | 1120 __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset)); |
1120 // Walk the rest of the chain without clobbering esi. | 1121 // Walk the rest of the chain without clobbering esi. |
1121 context = temp; | 1122 context = temp; |
1122 } | 1123 } |
1123 } | 1124 } |
1124 // Check that last extension is NULL. | 1125 // Check that last extension is NULL. |
1125 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0)); | 1126 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0)); |
1126 __ j(not_equal, slow); | 1127 __ j(not_equal, slow); |
1127 __ mov(temp, ContextOperand(context, Context::FCONTEXT_INDEX)); | 1128 |
1128 return ContextOperand(temp, slot->index()); | 1129 // This function is used only for loads, not stores, so it's safe to |
| 1130 // return an esi-based operand (the write barrier cannot be allowed to |
| 1131 // destroy the esi register). |
| 1132 return ContextOperand(context, slot->index()); |
1129 } | 1133 } |
1130 | 1134 |
1131 | 1135 |
1132 void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase( | 1136 void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase( |
1133 Slot* slot, | 1137 Slot* slot, |
1134 TypeofState typeof_state, | 1138 TypeofState typeof_state, |
1135 Label* slow, | 1139 Label* slow, |
1136 Label* done) { | 1140 Label* done) { |
1137 // Generate fast-case code for variables that might be shadowed by | 1141 // Generate fast-case code for variables that might be shadowed by |
1138 // eval-introduced variables. Eval is used a lot without | 1142 // eval-introduced variables. Eval is used a lot without |
(...skipping 854 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1993 if (var->is_global()) { | 1997 if (var->is_global()) { |
1994 ASSERT(!var->is_this()); | 1998 ASSERT(!var->is_this()); |
1995 // Assignment to a global variable. Use inline caching for the | 1999 // Assignment to a global variable. Use inline caching for the |
1996 // assignment. Right-hand-side value is passed in eax, variable name in | 2000 // assignment. Right-hand-side value is passed in eax, variable name in |
1997 // ecx, and the global object on the stack. | 2001 // ecx, and the global object on the stack. |
1998 __ mov(ecx, var->name()); | 2002 __ mov(ecx, var->name()); |
1999 __ mov(edx, GlobalObjectOperand()); | 2003 __ mov(edx, GlobalObjectOperand()); |
2000 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 2004 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
2001 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 2005 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
2002 | 2006 |
2003 } else if (var->mode() != Variable::CONST || op == Token::INIT_CONST) { | 2007 } else if (op == Token::INIT_CONST) { |
2004 // Perform the assignment for non-const variables and for initialization | 2008 // Like var declarations, const declarations are hoisted to function |
2005 // of const variables. Const assignments are simply skipped. | 2009 // scope. However, unlike var initializers, const initializers are able |
2006 Label done; | 2010 // to drill a hole to that function context, even from inside a 'with' |
| 2011 // context. We thus bypass the normal static scope lookup. |
| 2012 Slot* slot = var->AsSlot(); |
| 2013 Label skip; |
| 2014 switch (slot->type()) { |
| 2015 case Slot::PARAMETER: |
| 2016 // No const parameters. |
| 2017 UNREACHABLE(); |
| 2018 break; |
| 2019 case Slot::LOCAL: |
| 2020 __ mov(edx, Operand(ebp, SlotOffset(slot))); |
| 2021 __ cmp(edx, Factory::the_hole_value()); |
| 2022 __ j(not_equal, &skip); |
| 2023 __ mov(Operand(ebp, SlotOffset(slot)), eax); |
| 2024 break; |
| 2025 case Slot::CONTEXT: { |
| 2026 __ mov(ecx, ContextOperand(esi, Context::FCONTEXT_INDEX)); |
| 2027 __ mov(edx, ContextOperand(ecx, slot->index())); |
| 2028 __ cmp(edx, Factory::the_hole_value()); |
| 2029 __ j(not_equal, &skip); |
| 2030 __ mov(ContextOperand(ecx, slot->index()), eax); |
| 2031 int offset = Context::SlotOffset(slot->index()); |
| 2032 __ mov(edx, eax); // Preserve the stored value in eax. |
| 2033 __ RecordWrite(ecx, offset, edx, ebx); |
| 2034 break; |
| 2035 } |
| 2036 case Slot::LOOKUP: |
| 2037 __ push(eax); |
| 2038 __ push(esi); |
| 2039 __ push(Immediate(var->name())); |
| 2040 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
| 2041 break; |
| 2042 } |
| 2043 __ bind(&skip); |
| 2044 |
| 2045 } else if (var->mode() != Variable::CONST) { |
| 2046 // Perform the assignment for non-const variables. Const assignments |
| 2047 // are simply skipped. |
2007 Slot* slot = var->AsSlot(); | 2048 Slot* slot = var->AsSlot(); |
2008 switch (slot->type()) { | 2049 switch (slot->type()) { |
2009 case Slot::PARAMETER: | 2050 case Slot::PARAMETER: |
2010 case Slot::LOCAL: | 2051 case Slot::LOCAL: |
2011 if (op == Token::INIT_CONST) { | |
2012 // Detect const reinitialization by checking for the hole value. | |
2013 __ mov(edx, Operand(ebp, SlotOffset(slot))); | |
2014 __ cmp(edx, Factory::the_hole_value()); | |
2015 __ j(not_equal, &done); | |
2016 } | |
2017 // Perform the assignment. | 2052 // Perform the assignment. |
2018 __ mov(Operand(ebp, SlotOffset(slot)), eax); | 2053 __ mov(Operand(ebp, SlotOffset(slot)), eax); |
2019 break; | 2054 break; |
2020 | 2055 |
2021 case Slot::CONTEXT: { | 2056 case Slot::CONTEXT: { |
2022 MemOperand target = EmitSlotSearch(slot, ecx); | 2057 MemOperand target = EmitSlotSearch(slot, ecx); |
2023 if (op == Token::INIT_CONST) { | |
2024 // Detect const reinitialization by checking for the hole value. | |
2025 __ mov(edx, target); | |
2026 __ cmp(edx, Factory::the_hole_value()); | |
2027 __ j(not_equal, &done); | |
2028 } | |
2029 // Perform the assignment and issue the write barrier. | 2058 // Perform the assignment and issue the write barrier. |
2030 __ mov(target, eax); | 2059 __ mov(target, eax); |
2031 // The value of the assignment is in eax. RecordWrite clobbers its | 2060 // The value of the assignment is in eax. RecordWrite clobbers its |
2032 // register arguments. | 2061 // register arguments. |
2033 __ mov(edx, eax); | 2062 __ mov(edx, eax); |
2034 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | 2063 int offset = Context::SlotOffset(slot->index()); |
2035 __ RecordWrite(ecx, offset, edx, ebx); | 2064 __ RecordWrite(ecx, offset, edx, ebx); |
2036 break; | 2065 break; |
2037 } | 2066 } |
2038 | 2067 |
2039 case Slot::LOOKUP: | 2068 case Slot::LOOKUP: |
2040 // Call the runtime for the assignment. The runtime will ignore | 2069 // Call the runtime for the assignment. |
2041 // const reinitialization. | |
2042 __ push(eax); // Value. | 2070 __ push(eax); // Value. |
2043 __ push(esi); // Context. | 2071 __ push(esi); // Context. |
2044 __ push(Immediate(var->name())); | 2072 __ push(Immediate(var->name())); |
2045 if (op == Token::INIT_CONST) { | 2073 __ CallRuntime(Runtime::kStoreContextSlot, 3); |
2046 // The runtime will ignore const redeclaration. | |
2047 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); | |
2048 } else { | |
2049 __ CallRuntime(Runtime::kStoreContextSlot, 3); | |
2050 } | |
2051 break; | 2074 break; |
2052 } | 2075 } |
2053 __ bind(&done); | |
2054 } | 2076 } |
2055 } | 2077 } |
2056 | 2078 |
2057 | 2079 |
2058 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { | 2080 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { |
2059 // Assignment to a property, using a named store IC. | 2081 // Assignment to a property, using a named store IC. |
2060 Property* prop = expr->target()->AsProperty(); | 2082 Property* prop = expr->target()->AsProperty(); |
2061 ASSERT(prop != NULL); | 2083 ASSERT(prop != NULL); |
2062 ASSERT(prop->key()->AsLiteral() != NULL); | 2084 ASSERT(prop->key()->AsLiteral() != NULL); |
2063 | 2085 |
(...skipping 2302 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4366 // And return. | 4388 // And return. |
4367 __ ret(0); | 4389 __ ret(0); |
4368 } | 4390 } |
4369 | 4391 |
4370 | 4392 |
4371 #undef __ | 4393 #undef __ |
4372 | 4394 |
4373 } } // namespace v8::internal | 4395 } } // namespace v8::internal |
4374 | 4396 |
4375 #endif // V8_TARGET_ARCH_IA32 | 4397 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |