| 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 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 199 // The stub will rewrite receiver and parameter count if the previous | 199 // The stub will rewrite receiver and parameter count if the previous |
| 200 // stack frame was an arguments adapter frame. | 200 // stack frame was an arguments adapter frame. |
| 201 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); | 201 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); |
| 202 __ CallStub(&stub); | 202 __ CallStub(&stub); |
| 203 __ mov(ecx, eax); // Duplicate result. | 203 __ mov(ecx, eax); // Duplicate result. |
| 204 Move(arguments->AsSlot(), eax, ebx, edx); | 204 Move(arguments->AsSlot(), eax, ebx, edx); |
| 205 Slot* dot_arguments_slot = scope()->arguments_shadow()->AsSlot(); | 205 Slot* dot_arguments_slot = scope()->arguments_shadow()->AsSlot(); |
| 206 Move(dot_arguments_slot, ecx, ebx, edx); | 206 Move(dot_arguments_slot, ecx, ebx, edx); |
| 207 } | 207 } |
| 208 | 208 |
| 209 { Comment cmnt(masm_, "[ Declarations"); | |
| 210 // For named function expressions, declare the function name as a | |
| 211 // constant. | |
| 212 if (scope()->is_function_scope() && scope()->function() != NULL) { | |
| 213 EmitDeclaration(scope()->function(), Variable::CONST, NULL); | |
| 214 } | |
| 215 // Visit all the explicit declarations unless there is an illegal | |
| 216 // redeclaration. | |
| 217 if (scope()->HasIllegalRedeclaration()) { | |
| 218 scope()->VisitIllegalRedeclaration(this); | |
| 219 } else { | |
| 220 VisitDeclarations(scope()->declarations()); | |
| 221 } | |
| 222 } | |
| 223 | |
| 224 if (FLAG_trace) { | 209 if (FLAG_trace) { |
| 225 __ CallRuntime(Runtime::kTraceEnter, 0); | 210 __ CallRuntime(Runtime::kTraceEnter, 0); |
| 226 } | 211 } |
| 227 | 212 |
| 228 { Comment cmnt(masm_, "[ Stack check"); | 213 // Visit the declarations and body unless there is an illegal |
| 229 PrepareForBailout(info->function(), NO_REGISTERS); | 214 // redeclaration. |
| 230 NearLabel ok; | 215 if (scope()->HasIllegalRedeclaration()) { |
| 231 ExternalReference stack_limit = | 216 Comment cmnt(masm_, "[ Declarations"); |
| 232 ExternalReference::address_of_stack_limit(); | 217 scope()->VisitIllegalRedeclaration(this); |
| 233 __ cmp(esp, Operand::StaticVariable(stack_limit)); | 218 |
| 234 __ j(above_equal, &ok, taken); | 219 } else { |
| 235 StackCheckStub stub; | 220 { Comment cmnt(masm_, "[ Declarations"); |
| 236 __ CallStub(&stub); | 221 // For named function expressions, declare the function name as a |
| 237 __ bind(&ok); | 222 // constant. |
| 223 if (scope()->is_function_scope() && scope()->function() != NULL) { |
| 224 EmitDeclaration(scope()->function(), Variable::CONST, NULL); |
| 225 } |
| 226 VisitDeclarations(scope()->declarations()); |
| 227 } |
| 228 |
| 229 { Comment cmnt(masm_, "[ Stack check"); |
| 230 PrepareForBailout(info->function(), NO_REGISTERS); |
| 231 NearLabel ok; |
| 232 ExternalReference stack_limit = |
| 233 ExternalReference::address_of_stack_limit(); |
| 234 __ cmp(esp, Operand::StaticVariable(stack_limit)); |
| 235 __ j(above_equal, &ok, taken); |
| 236 StackCheckStub stub; |
| 237 __ CallStub(&stub); |
| 238 __ bind(&ok); |
| 239 } |
| 240 |
| 241 { Comment cmnt(masm_, "[ Body"); |
| 242 ASSERT(loop_depth() == 0); |
| 243 VisitStatements(function()->body()); |
| 244 ASSERT(loop_depth() == 0); |
| 245 } |
| 238 } | 246 } |
| 239 | 247 |
| 240 { Comment cmnt(masm_, "[ Body"); | 248 // Always emit a 'return undefined' in case control fell off the end of |
| 241 ASSERT(loop_depth() == 0); | 249 // the body. |
| 242 VisitStatements(function()->body()); | |
| 243 ASSERT(loop_depth() == 0); | |
| 244 } | |
| 245 | |
| 246 { Comment cmnt(masm_, "[ return <undefined>;"); | 250 { Comment cmnt(masm_, "[ return <undefined>;"); |
| 247 // Emit a 'return undefined' in case control fell off the end of the body. | |
| 248 __ mov(eax, isolate()->factory()->undefined_value()); | 251 __ mov(eax, isolate()->factory()->undefined_value()); |
| 249 EmitReturnSequence(); | 252 EmitReturnSequence(); |
| 250 } | 253 } |
| 251 } | 254 } |
| 252 | 255 |
| 253 | 256 |
| 254 void FullCodeGenerator::ClearAccumulator() { | 257 void FullCodeGenerator::ClearAccumulator() { |
| 255 __ Set(eax, Immediate(Smi::FromInt(0))); | 258 __ Set(eax, Immediate(Smi::FromInt(0))); |
| 256 } | 259 } |
| 257 | 260 |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 300 // Add a label for checking the size of the code used for returning. | 303 // Add a label for checking the size of the code used for returning. |
| 301 Label check_exit_codesize; | 304 Label check_exit_codesize; |
| 302 masm_->bind(&check_exit_codesize); | 305 masm_->bind(&check_exit_codesize); |
| 303 #endif | 306 #endif |
| 304 SetSourcePosition(function()->end_position() - 1); | 307 SetSourcePosition(function()->end_position() - 1); |
| 305 __ RecordJSReturn(); | 308 __ RecordJSReturn(); |
| 306 // Do not use the leave instruction here because it is too short to | 309 // Do not use the leave instruction here because it is too short to |
| 307 // patch with the code required by the debugger. | 310 // patch with the code required by the debugger. |
| 308 __ mov(esp, ebp); | 311 __ mov(esp, ebp); |
| 309 __ pop(ebp); | 312 __ pop(ebp); |
| 310 __ ret((scope()->num_parameters() + 1) * kPointerSize); | 313 |
| 314 int arguments_bytes = (scope()->num_parameters() + 1) * kPointerSize; |
| 315 __ Ret(arguments_bytes, ecx); |
| 311 #ifdef ENABLE_DEBUGGER_SUPPORT | 316 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 312 // Check that the size of the code used for returning matches what is | 317 // Check that the size of the code used for returning is large enough |
| 313 // expected by the debugger. | 318 // for the debugger's requirements. |
| 314 ASSERT_EQ(Assembler::kJSReturnSequenceLength, | 319 ASSERT(Assembler::kJSReturnSequenceLength <= |
| 315 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); | 320 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); |
| 316 #endif | 321 #endif |
| 317 } | 322 } |
| 318 } | 323 } |
| 319 | 324 |
| 320 | 325 |
| 321 FullCodeGenerator::ConstantOperand FullCodeGenerator::GetConstantOperand( | 326 FullCodeGenerator::ConstantOperand FullCodeGenerator::GetConstantOperand( |
| 322 Token::Value op, Expression* left, Expression* right) { | 327 Token::Value op, Expression* left, Expression* right) { |
| 323 ASSERT(ShouldInlineSmiCase(op)); | 328 ASSERT(ShouldInlineSmiCase(op)); |
| 324 if (op == Token::DIV || op == Token::MOD || op == Token::MUL) { | 329 if (op == Token::DIV || op == Token::MOD || op == Token::MUL) { |
| 325 // We never generate inlined constant smi operations for these. | 330 // We never generate inlined constant smi operations for these. |
| (...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 605 void FullCodeGenerator::Move(Slot* dst, | 610 void FullCodeGenerator::Move(Slot* dst, |
| 606 Register src, | 611 Register src, |
| 607 Register scratch1, | 612 Register scratch1, |
| 608 Register scratch2) { | 613 Register scratch2) { |
| 609 ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented. | 614 ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented. |
| 610 ASSERT(!scratch1.is(src) && !scratch2.is(src)); | 615 ASSERT(!scratch1.is(src) && !scratch2.is(src)); |
| 611 MemOperand location = EmitSlotSearch(dst, scratch1); | 616 MemOperand location = EmitSlotSearch(dst, scratch1); |
| 612 __ mov(location, src); | 617 __ mov(location, src); |
| 613 // Emit the write barrier code if the location is in the heap. | 618 // Emit the write barrier code if the location is in the heap. |
| 614 if (dst->type() == Slot::CONTEXT) { | 619 if (dst->type() == Slot::CONTEXT) { |
| 615 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize; | 620 int offset = Context::SlotOffset(dst->index()); |
| 616 __ RecordWrite(scratch1, offset, src, scratch2); | 621 __ RecordWrite(scratch1, offset, src, scratch2); |
| 617 } | 622 } |
| 618 } | 623 } |
| 619 | 624 |
| 620 | 625 |
| 621 void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state, | 626 void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state, |
| 622 bool should_normalize, | 627 bool should_normalize, |
| 623 Label* if_true, | 628 Label* if_true, |
| 624 Label* if_false) { | 629 Label* if_false) { |
| 625 // Only prepare for bailouts before splits if we're in a test | 630 // 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... |
| 661 } else if (function != NULL) { | 666 } else if (function != NULL) { |
| 662 VisitForAccumulatorValue(function); | 667 VisitForAccumulatorValue(function); |
| 663 __ mov(Operand(ebp, SlotOffset(slot)), result_register()); | 668 __ mov(Operand(ebp, SlotOffset(slot)), result_register()); |
| 664 } | 669 } |
| 665 break; | 670 break; |
| 666 | 671 |
| 667 case Slot::CONTEXT: | 672 case Slot::CONTEXT: |
| 668 // We bypass the general EmitSlotSearch because we know more about | 673 // We bypass the general EmitSlotSearch because we know more about |
| 669 // this specific context. | 674 // this specific context. |
| 670 | 675 |
| 671 // The variable in the decl always resides in the current context. | 676 // The variable in the decl always resides in the current function |
| 677 // context. |
| 672 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); | 678 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); |
| 673 if (FLAG_debug_code) { | 679 if (FLAG_debug_code) { |
| 674 // Check if we have the correct context pointer. | 680 // Check that we're not inside a 'with'. |
| 675 __ mov(ebx, ContextOperand(esi, Context::FCONTEXT_INDEX)); | 681 __ mov(ebx, ContextOperand(esi, Context::FCONTEXT_INDEX)); |
| 676 __ cmp(ebx, Operand(esi)); | 682 __ cmp(ebx, Operand(esi)); |
| 677 __ Check(equal, "Unexpected declaration in current context."); | 683 __ Check(equal, "Unexpected declaration in current context."); |
| 678 } | 684 } |
| 679 if (mode == Variable::CONST) { | 685 if (mode == Variable::CONST) { |
| 680 __ mov(ContextOperand(esi, slot->index()), | 686 __ mov(ContextOperand(esi, slot->index()), |
| 681 Immediate(isolate()->factory()->the_hole_value())); | 687 Immediate(isolate()->factory()->the_hole_value())); |
| 682 // No write barrier since the hole value is in old space. | 688 // No write barrier since the hole value is in old space. |
| 683 } else if (function != NULL) { | 689 } else if (function != NULL) { |
| 684 VisitForAccumulatorValue(function); | 690 VisitForAccumulatorValue(function); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 708 __ push(Immediate(Smi::FromInt(0))); // No initial value! | 714 __ push(Immediate(Smi::FromInt(0))); // No initial value! |
| 709 } | 715 } |
| 710 __ CallRuntime(Runtime::kDeclareContextSlot, 4); | 716 __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
| 711 break; | 717 break; |
| 712 } | 718 } |
| 713 } | 719 } |
| 714 | 720 |
| 715 } else if (prop != NULL) { | 721 } else if (prop != NULL) { |
| 716 if (function != NULL || mode == Variable::CONST) { | 722 if (function != NULL || mode == Variable::CONST) { |
| 717 // We are declaring a function or constant that rewrites to a | 723 // We are declaring a function or constant that rewrites to a |
| 718 // property. Use (keyed) IC to set the initial value. | 724 // property. Use (keyed) IC to set the initial value. We cannot |
| 719 VisitForStackValue(prop->obj()); | 725 // visit the rewrite because it's shared and we risk recording |
| 726 // duplicate AST IDs for bailouts from optimized code. |
| 727 ASSERT(prop->obj()->AsVariableProxy() != NULL); |
| 728 { AccumulatorValueContext for_object(this); |
| 729 EmitVariableLoad(prop->obj()->AsVariableProxy()->var()); |
| 730 } |
| 731 |
| 720 if (function != NULL) { | 732 if (function != NULL) { |
| 721 VisitForStackValue(prop->key()); | 733 __ push(eax); |
| 722 VisitForAccumulatorValue(function); | 734 VisitForAccumulatorValue(function); |
| 723 __ pop(ecx); | 735 __ pop(edx); |
| 724 } else { | 736 } else { |
| 725 VisitForAccumulatorValue(prop->key()); | 737 __ mov(edx, eax); |
| 726 __ mov(ecx, result_register()); | 738 __ mov(eax, isolate()->factory()->the_hole_value()); |
| 727 __ mov(result_register(), isolate()->factory()->the_hole_value()); | |
| 728 } | 739 } |
| 729 __ pop(edx); | 740 ASSERT(prop->key()->AsLiteral() != NULL && |
| 741 prop->key()->AsLiteral()->handle()->IsSmi()); |
| 742 __ Set(ecx, Immediate(prop->key()->AsLiteral()->handle())); |
| 730 | 743 |
| 731 Handle<Code> ic(isolate()->builtins()->builtin( | 744 Handle<Code> ic(isolate()->builtins()->builtin( |
| 732 Builtins::KeyedStoreIC_Initialize)); | 745 Builtins::KeyedStoreIC_Initialize)); |
| 733 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 746 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 734 } | 747 } |
| 735 } | 748 } |
| 736 } | 749 } |
| 737 | 750 |
| 738 | 751 |
| 739 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { | 752 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { |
| (...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1122 } | 1135 } |
| 1123 __ mov(temp, ContextOperand(context, Context::CLOSURE_INDEX)); | 1136 __ mov(temp, ContextOperand(context, Context::CLOSURE_INDEX)); |
| 1124 __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset)); | 1137 __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset)); |
| 1125 // Walk the rest of the chain without clobbering esi. | 1138 // Walk the rest of the chain without clobbering esi. |
| 1126 context = temp; | 1139 context = temp; |
| 1127 } | 1140 } |
| 1128 } | 1141 } |
| 1129 // Check that last extension is NULL. | 1142 // Check that last extension is NULL. |
| 1130 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0)); | 1143 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0)); |
| 1131 __ j(not_equal, slow); | 1144 __ j(not_equal, slow); |
| 1132 __ mov(temp, ContextOperand(context, Context::FCONTEXT_INDEX)); | 1145 |
| 1133 return ContextOperand(temp, slot->index()); | 1146 // This function is used only for loads, not stores, so it's safe to |
| 1147 // return an esi-based operand (the write barrier cannot be allowed to |
| 1148 // destroy the esi register). |
| 1149 return ContextOperand(context, slot->index()); |
| 1134 } | 1150 } |
| 1135 | 1151 |
| 1136 | 1152 |
| 1137 void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase( | 1153 void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase( |
| 1138 Slot* slot, | 1154 Slot* slot, |
| 1139 TypeofState typeof_state, | 1155 TypeofState typeof_state, |
| 1140 Label* slow, | 1156 Label* slow, |
| 1141 Label* done) { | 1157 Label* done) { |
| 1142 // Generate fast-case code for variables that might be shadowed by | 1158 // Generate fast-case code for variables that might be shadowed by |
| 1143 // eval-introduced variables. Eval is used a lot without | 1159 // eval-introduced variables. Eval is used a lot without |
| (...skipping 864 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2008 ASSERT(!var->is_this()); | 2024 ASSERT(!var->is_this()); |
| 2009 // Assignment to a global variable. Use inline caching for the | 2025 // Assignment to a global variable. Use inline caching for the |
| 2010 // assignment. Right-hand-side value is passed in eax, variable name in | 2026 // assignment. Right-hand-side value is passed in eax, variable name in |
| 2011 // ecx, and the global object on the stack. | 2027 // ecx, and the global object on the stack. |
| 2012 __ mov(ecx, var->name()); | 2028 __ mov(ecx, var->name()); |
| 2013 __ mov(edx, GlobalObjectOperand()); | 2029 __ mov(edx, GlobalObjectOperand()); |
| 2014 Handle<Code> ic(isolate()->builtins()->builtin( | 2030 Handle<Code> ic(isolate()->builtins()->builtin( |
| 2015 Builtins::StoreIC_Initialize)); | 2031 Builtins::StoreIC_Initialize)); |
| 2016 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 2032 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 2017 | 2033 |
| 2018 } else if (var->mode() != Variable::CONST || op == Token::INIT_CONST) { | 2034 } else if (op == Token::INIT_CONST) { |
| 2019 // Perform the assignment for non-const variables and for initialization | 2035 // Like var declarations, const declarations are hoisted to function |
| 2020 // of const variables. Const assignments are simply skipped. | 2036 // scope. However, unlike var initializers, const initializers are able |
| 2021 Label done; | 2037 // to drill a hole to that function context, even from inside a 'with' |
| 2038 // context. We thus bypass the normal static scope lookup. |
| 2039 Slot* slot = var->AsSlot(); |
| 2040 Label skip; |
| 2041 switch (slot->type()) { |
| 2042 case Slot::PARAMETER: |
| 2043 // No const parameters. |
| 2044 UNREACHABLE(); |
| 2045 break; |
| 2046 case Slot::LOCAL: |
| 2047 __ mov(edx, Operand(ebp, SlotOffset(slot))); |
| 2048 __ cmp(edx, isolate()->factory()->the_hole_value()); |
| 2049 __ j(not_equal, &skip); |
| 2050 __ mov(Operand(ebp, SlotOffset(slot)), eax); |
| 2051 break; |
| 2052 case Slot::CONTEXT: { |
| 2053 __ mov(ecx, ContextOperand(esi, Context::FCONTEXT_INDEX)); |
| 2054 __ mov(edx, ContextOperand(ecx, slot->index())); |
| 2055 __ cmp(edx, isolate()->factory()->the_hole_value()); |
| 2056 __ j(not_equal, &skip); |
| 2057 __ mov(ContextOperand(ecx, slot->index()), eax); |
| 2058 int offset = Context::SlotOffset(slot->index()); |
| 2059 __ mov(edx, eax); // Preserve the stored value in eax. |
| 2060 __ RecordWrite(ecx, offset, edx, ebx); |
| 2061 break; |
| 2062 } |
| 2063 case Slot::LOOKUP: |
| 2064 __ push(eax); |
| 2065 __ push(esi); |
| 2066 __ push(Immediate(var->name())); |
| 2067 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
| 2068 break; |
| 2069 } |
| 2070 __ bind(&skip); |
| 2071 |
| 2072 } else if (var->mode() != Variable::CONST) { |
| 2073 // Perform the assignment for non-const variables. Const assignments |
| 2074 // are simply skipped. |
| 2022 Slot* slot = var->AsSlot(); | 2075 Slot* slot = var->AsSlot(); |
| 2023 switch (slot->type()) { | 2076 switch (slot->type()) { |
| 2024 case Slot::PARAMETER: | 2077 case Slot::PARAMETER: |
| 2025 case Slot::LOCAL: | 2078 case Slot::LOCAL: |
| 2026 if (op == Token::INIT_CONST) { | |
| 2027 // Detect const reinitialization by checking for the hole value. | |
| 2028 __ mov(edx, Operand(ebp, SlotOffset(slot))); | |
| 2029 __ cmp(edx, isolate()->factory()->the_hole_value()); | |
| 2030 __ j(not_equal, &done); | |
| 2031 } | |
| 2032 // Perform the assignment. | 2079 // Perform the assignment. |
| 2033 __ mov(Operand(ebp, SlotOffset(slot)), eax); | 2080 __ mov(Operand(ebp, SlotOffset(slot)), eax); |
| 2034 break; | 2081 break; |
| 2035 | 2082 |
| 2036 case Slot::CONTEXT: { | 2083 case Slot::CONTEXT: { |
| 2037 MemOperand target = EmitSlotSearch(slot, ecx); | 2084 MemOperand target = EmitSlotSearch(slot, ecx); |
| 2038 if (op == Token::INIT_CONST) { | |
| 2039 // Detect const reinitialization by checking for the hole value. | |
| 2040 __ mov(edx, target); | |
| 2041 __ cmp(edx, isolate()->factory()->the_hole_value()); | |
| 2042 __ j(not_equal, &done); | |
| 2043 } | |
| 2044 // Perform the assignment and issue the write barrier. | 2085 // Perform the assignment and issue the write barrier. |
| 2045 __ mov(target, eax); | 2086 __ mov(target, eax); |
| 2046 // The value of the assignment is in eax. RecordWrite clobbers its | 2087 // The value of the assignment is in eax. RecordWrite clobbers its |
| 2047 // register arguments. | 2088 // register arguments. |
| 2048 __ mov(edx, eax); | 2089 __ mov(edx, eax); |
| 2049 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | 2090 int offset = Context::SlotOffset(slot->index()); |
| 2050 __ RecordWrite(ecx, offset, edx, ebx); | 2091 __ RecordWrite(ecx, offset, edx, ebx); |
| 2051 break; | 2092 break; |
| 2052 } | 2093 } |
| 2053 | 2094 |
| 2054 case Slot::LOOKUP: | 2095 case Slot::LOOKUP: |
| 2055 // Call the runtime for the assignment. The runtime will ignore | 2096 // Call the runtime for the assignment. |
| 2056 // const reinitialization. | |
| 2057 __ push(eax); // Value. | 2097 __ push(eax); // Value. |
| 2058 __ push(esi); // Context. | 2098 __ push(esi); // Context. |
| 2059 __ push(Immediate(var->name())); | 2099 __ push(Immediate(var->name())); |
| 2060 if (op == Token::INIT_CONST) { | 2100 __ CallRuntime(Runtime::kStoreContextSlot, 3); |
| 2061 // The runtime will ignore const redeclaration. | |
| 2062 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); | |
| 2063 } else { | |
| 2064 __ CallRuntime(Runtime::kStoreContextSlot, 3); | |
| 2065 } | |
| 2066 break; | 2101 break; |
| 2067 } | 2102 } |
| 2068 __ bind(&done); | |
| 2069 } | 2103 } |
| 2070 } | 2104 } |
| 2071 | 2105 |
| 2072 | 2106 |
| 2073 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { | 2107 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { |
| 2074 // Assignment to a property, using a named store IC. | 2108 // Assignment to a property, using a named store IC. |
| 2075 Property* prop = expr->target()->AsProperty(); | 2109 Property* prop = expr->target()->AsProperty(); |
| 2076 ASSERT(prop != NULL); | 2110 ASSERT(prop != NULL); |
| 2077 ASSERT(prop->key()->AsLiteral() != NULL); | 2111 ASSERT(prop->key()->AsLiteral() != NULL); |
| 2078 | 2112 |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2282 | 2316 |
| 2283 // Push copy of the first argument or undefined if it doesn't exist. | 2317 // Push copy of the first argument or undefined if it doesn't exist. |
| 2284 if (arg_count > 0) { | 2318 if (arg_count > 0) { |
| 2285 __ push(Operand(esp, arg_count * kPointerSize)); | 2319 __ push(Operand(esp, arg_count * kPointerSize)); |
| 2286 } else { | 2320 } else { |
| 2287 __ push(Immediate(isolate()->factory()->undefined_value())); | 2321 __ push(Immediate(isolate()->factory()->undefined_value())); |
| 2288 } | 2322 } |
| 2289 | 2323 |
| 2290 // Push the receiver of the enclosing function and do runtime call. | 2324 // Push the receiver of the enclosing function and do runtime call. |
| 2291 __ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize)); | 2325 __ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize)); |
| 2292 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3); | 2326 // Push the strict mode flag. |
| 2327 __ push(Immediate(Smi::FromInt(strict_mode_flag()))); |
| 2328 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 4); |
| 2293 | 2329 |
| 2294 // The runtime call returns a pair of values in eax (function) and | 2330 // The runtime call returns a pair of values in eax (function) and |
| 2295 // edx (receiver). Touch up the stack with the right values. | 2331 // edx (receiver). Touch up the stack with the right values. |
| 2296 __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx); | 2332 __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx); |
| 2297 __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax); | 2333 __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax); |
| 2298 } | 2334 } |
| 2299 // Record source position for debugger. | 2335 // Record source position for debugger. |
| 2300 SetSourcePosition(expr->position()); | 2336 SetSourcePosition(expr->position()); |
| 2301 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 2337 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 2302 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); | 2338 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); |
| (...skipping 1460 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3763 context()->Plug(eax); | 3799 context()->Plug(eax); |
| 3764 break; | 3800 break; |
| 3765 } | 3801 } |
| 3766 | 3802 |
| 3767 case Token::ADD: { | 3803 case Token::ADD: { |
| 3768 Comment cmt(masm_, "[ UnaryOperation (ADD)"); | 3804 Comment cmt(masm_, "[ UnaryOperation (ADD)"); |
| 3769 VisitForAccumulatorValue(expr->expression()); | 3805 VisitForAccumulatorValue(expr->expression()); |
| 3770 Label no_conversion; | 3806 Label no_conversion; |
| 3771 __ test(result_register(), Immediate(kSmiTagMask)); | 3807 __ test(result_register(), Immediate(kSmiTagMask)); |
| 3772 __ j(zero, &no_conversion); | 3808 __ j(zero, &no_conversion); |
| 3773 __ push(result_register()); | 3809 ToNumberStub convert_stub; |
| 3774 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); | 3810 __ CallStub(&convert_stub); |
| 3775 __ bind(&no_conversion); | 3811 __ bind(&no_conversion); |
| 3776 context()->Plug(result_register()); | 3812 context()->Plug(result_register()); |
| 3777 break; | 3813 break; |
| 3778 } | 3814 } |
| 3779 | 3815 |
| 3780 case Token::SUB: { | 3816 case Token::SUB: { |
| 3781 Comment cmt(masm_, "[ UnaryOperation (SUB)"); | 3817 Comment cmt(masm_, "[ UnaryOperation (SUB)"); |
| 3782 bool can_overwrite = expr->expression()->ResultOverwriteAllowed(); | 3818 bool can_overwrite = expr->expression()->ResultOverwriteAllowed(); |
| 3783 UnaryOverwriteMode overwrite = | 3819 UnaryOverwriteMode overwrite = |
| 3784 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE; | 3820 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE; |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3884 // We need a second deoptimization point after loading the value | 3920 // We need a second deoptimization point after loading the value |
| 3885 // in case evaluating the property load my have a side effect. | 3921 // in case evaluating the property load my have a side effect. |
| 3886 PrepareForBailout(expr->increment(), TOS_REG); | 3922 PrepareForBailout(expr->increment(), TOS_REG); |
| 3887 | 3923 |
| 3888 // Call ToNumber only if operand is not a smi. | 3924 // Call ToNumber only if operand is not a smi. |
| 3889 NearLabel no_conversion; | 3925 NearLabel no_conversion; |
| 3890 if (ShouldInlineSmiCase(expr->op())) { | 3926 if (ShouldInlineSmiCase(expr->op())) { |
| 3891 __ test(eax, Immediate(kSmiTagMask)); | 3927 __ test(eax, Immediate(kSmiTagMask)); |
| 3892 __ j(zero, &no_conversion); | 3928 __ j(zero, &no_conversion); |
| 3893 } | 3929 } |
| 3894 __ push(eax); | 3930 ToNumberStub convert_stub; |
| 3895 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); | 3931 __ CallStub(&convert_stub); |
| 3896 __ bind(&no_conversion); | 3932 __ bind(&no_conversion); |
| 3897 | 3933 |
| 3898 // Save result for postfix expressions. | 3934 // Save result for postfix expressions. |
| 3899 if (expr->is_postfix()) { | 3935 if (expr->is_postfix()) { |
| 3900 if (!context()->IsEffect()) { | 3936 if (!context()->IsEffect()) { |
| 3901 // Save the result on the stack. If we have a named or keyed property | 3937 // Save the result on the stack. If we have a named or keyed property |
| 3902 // we store the result under the receiver that is currently on top | 3938 // we store the result under the receiver that is currently on top |
| 3903 // of the stack. | 3939 // of the stack. |
| 3904 switch (assign_type) { | 3940 switch (assign_type) { |
| 3905 case VARIABLE: | 3941 case VARIABLE: |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3938 __ add(Operand(eax), Immediate(Smi::FromInt(1))); | 3974 __ add(Operand(eax), Immediate(Smi::FromInt(1))); |
| 3939 } | 3975 } |
| 3940 } | 3976 } |
| 3941 | 3977 |
| 3942 // Record position before stub call. | 3978 // Record position before stub call. |
| 3943 SetSourcePosition(expr->position()); | 3979 SetSourcePosition(expr->position()); |
| 3944 | 3980 |
| 3945 // Call stub for +1/-1. | 3981 // Call stub for +1/-1. |
| 3946 __ mov(edx, eax); | 3982 __ mov(edx, eax); |
| 3947 __ mov(eax, Immediate(Smi::FromInt(1))); | 3983 __ mov(eax, Immediate(Smi::FromInt(1))); |
| 3948 TypeRecordingBinaryOpStub stub(expr->binary_op(), | 3984 TypeRecordingBinaryOpStub stub(expr->binary_op(), NO_OVERWRITE); |
| 3949 NO_OVERWRITE); | |
| 3950 EmitCallIC(stub.GetCode(), &patch_site); | 3985 EmitCallIC(stub.GetCode(), &patch_site); |
| 3951 __ bind(&done); | 3986 __ bind(&done); |
| 3952 | 3987 |
| 3953 // Store the value returned in eax. | 3988 // Store the value returned in eax. |
| 3954 switch (assign_type) { | 3989 switch (assign_type) { |
| 3955 case VARIABLE: | 3990 case VARIABLE: |
| 3956 if (expr->is_postfix()) { | 3991 if (expr->is_postfix()) { |
| 3957 // Perform the assignment as if via '='. | 3992 // Perform the assignment as if via '='. |
| 3958 { EffectContext context(this); | 3993 { EffectContext context(this); |
| 3959 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 3994 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| (...skipping 432 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4392 // And return. | 4427 // And return. |
| 4393 __ ret(0); | 4428 __ ret(0); |
| 4394 } | 4429 } |
| 4395 | 4430 |
| 4396 | 4431 |
| 4397 #undef __ | 4432 #undef __ |
| 4398 | 4433 |
| 4399 } } // namespace v8::internal | 4434 } } // namespace v8::internal |
| 4400 | 4435 |
| 4401 #endif // V8_TARGET_ARCH_IA32 | 4436 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |