Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(210)

Side by Side Diff: src/ia32/full-codegen-ia32.cc

Issue 6384020: Remove the redundant load on every context lookup. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge/build/ia32
Patch Set: Addressed review comments. Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | src/ia32/lithium-codegen-ia32.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | src/ia32/lithium-codegen-ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698