| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #if V8_TARGET_ARCH_X87 | 5 #if V8_TARGET_ARCH_X87 |
| 6 | 6 |
| 7 #include "src/full-codegen/full-codegen.h" | 7 #include "src/full-codegen/full-codegen.h" |
| 8 #include "src/ast/compile-time-value.h" | 8 #include "src/ast/compile-time-value.h" |
| 9 #include "src/ast/scopes.h" | 9 #include "src/ast/scopes.h" |
| 10 #include "src/code-factory.h" | 10 #include "src/code-factory.h" |
| (...skipping 735 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 746 if (variable->binding_needs_init()) { | 746 if (variable->binding_needs_init()) { |
| 747 Comment cmnt(masm_, "[ VariableDeclaration"); | 747 Comment cmnt(masm_, "[ VariableDeclaration"); |
| 748 EmitDebugCheckDeclarationContext(variable); | 748 EmitDebugCheckDeclarationContext(variable); |
| 749 __ mov(ContextOperand(esi, variable->index()), | 749 __ mov(ContextOperand(esi, variable->index()), |
| 750 Immediate(isolate()->factory()->the_hole_value())); | 750 Immediate(isolate()->factory()->the_hole_value())); |
| 751 // No write barrier since the hole value is in old space. | 751 // No write barrier since the hole value is in old space. |
| 752 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS); | 752 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS); |
| 753 } | 753 } |
| 754 break; | 754 break; |
| 755 | 755 |
| 756 case VariableLocation::LOOKUP: { | 756 case VariableLocation::LOOKUP: |
| 757 Comment cmnt(masm_, "[ VariableDeclaration"); | |
| 758 DCHECK_EQ(VAR, variable->mode()); | |
| 759 DCHECK(!variable->binding_needs_init()); | |
| 760 __ push(Immediate(variable->name())); | |
| 761 __ CallRuntime(Runtime::kDeclareEvalVar); | |
| 762 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS); | |
| 763 break; | |
| 764 } | |
| 765 | |
| 766 case VariableLocation::MODULE: | 757 case VariableLocation::MODULE: |
| 767 UNREACHABLE(); | 758 UNREACHABLE(); |
| 768 } | 759 } |
| 769 } | 760 } |
| 770 | 761 |
| 771 void FullCodeGenerator::VisitFunctionDeclaration( | 762 void FullCodeGenerator::VisitFunctionDeclaration( |
| 772 FunctionDeclaration* declaration) { | 763 FunctionDeclaration* declaration) { |
| 773 VariableProxy* proxy = declaration->proxy(); | 764 VariableProxy* proxy = declaration->proxy(); |
| 774 Variable* variable = proxy->var(); | 765 Variable* variable = proxy->var(); |
| 775 switch (variable->location()) { | 766 switch (variable->location()) { |
| (...skipping 24 matching lines...) Expand all Loading... |
| 800 VisitForAccumulatorValue(declaration->fun()); | 791 VisitForAccumulatorValue(declaration->fun()); |
| 801 __ mov(ContextOperand(esi, variable->index()), result_register()); | 792 __ mov(ContextOperand(esi, variable->index()), result_register()); |
| 802 // We know that we have written a function, which is not a smi. | 793 // We know that we have written a function, which is not a smi. |
| 803 __ RecordWriteContextSlot(esi, Context::SlotOffset(variable->index()), | 794 __ RecordWriteContextSlot(esi, Context::SlotOffset(variable->index()), |
| 804 result_register(), ecx, kDontSaveFPRegs, | 795 result_register(), ecx, kDontSaveFPRegs, |
| 805 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); | 796 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); |
| 806 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS); | 797 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS); |
| 807 break; | 798 break; |
| 808 } | 799 } |
| 809 | 800 |
| 810 case VariableLocation::LOOKUP: { | 801 case VariableLocation::LOOKUP: |
| 811 Comment cmnt(masm_, "[ FunctionDeclaration"); | |
| 812 PushOperand(variable->name()); | |
| 813 VisitForStackValue(declaration->fun()); | |
| 814 CallRuntimeWithOperands(Runtime::kDeclareEvalFunction); | |
| 815 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS); | |
| 816 break; | |
| 817 } | |
| 818 | |
| 819 case VariableLocation::MODULE: | 802 case VariableLocation::MODULE: |
| 820 UNREACHABLE(); | 803 UNREACHABLE(); |
| 821 } | 804 } |
| 822 } | 805 } |
| 823 | 806 |
| 824 | 807 |
| 825 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 808 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| 826 // Call the runtime to declare the globals. | 809 // Call the runtime to declare the globals. |
| 827 __ Push(pairs); | 810 __ Push(pairs); |
| 828 __ Push(Smi::FromInt(DeclareGlobalsFlags())); | 811 __ Push(Smi::FromInt(DeclareGlobalsFlags())); |
| (...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1094 | 1077 |
| 1095 void FullCodeGenerator::EmitSetHomeObjectAccumulator(Expression* initializer, | 1078 void FullCodeGenerator::EmitSetHomeObjectAccumulator(Expression* initializer, |
| 1096 int offset, | 1079 int offset, |
| 1097 FeedbackVectorSlot slot) { | 1080 FeedbackVectorSlot slot) { |
| 1098 DCHECK(NeedsHomeObject(initializer)); | 1081 DCHECK(NeedsHomeObject(initializer)); |
| 1099 __ mov(StoreDescriptor::ReceiverRegister(), eax); | 1082 __ mov(StoreDescriptor::ReceiverRegister(), eax); |
| 1100 __ mov(StoreDescriptor::ValueRegister(), Operand(esp, offset * kPointerSize)); | 1083 __ mov(StoreDescriptor::ValueRegister(), Operand(esp, offset * kPointerSize)); |
| 1101 CallStoreIC(slot, isolate()->factory()->home_object_symbol()); | 1084 CallStoreIC(slot, isolate()->factory()->home_object_symbol()); |
| 1102 } | 1085 } |
| 1103 | 1086 |
| 1104 | |
| 1105 void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy, | |
| 1106 TypeofMode typeof_mode, | |
| 1107 Label* slow) { | |
| 1108 Register context = esi; | |
| 1109 Register temp = edx; | |
| 1110 | |
| 1111 int to_check = scope()->ContextChainLengthUntilOutermostSloppyEval(); | |
| 1112 for (Scope* s = scope(); to_check > 0; s = s->outer_scope()) { | |
| 1113 if (!s->NeedsContext()) continue; | |
| 1114 if (s->calls_sloppy_eval()) { | |
| 1115 // Check that extension is "the hole". | |
| 1116 __ JumpIfNotRoot(ContextOperand(context, Context::EXTENSION_INDEX), | |
| 1117 Heap::kTheHoleValueRootIndex, slow); | |
| 1118 } | |
| 1119 // Load next context in chain. | |
| 1120 __ mov(temp, ContextOperand(context, Context::PREVIOUS_INDEX)); | |
| 1121 // Walk the rest of the chain without clobbering esi. | |
| 1122 context = temp; | |
| 1123 to_check--; | |
| 1124 } | |
| 1125 | |
| 1126 // All extension objects were empty and it is safe to use a normal global | |
| 1127 // load machinery. | |
| 1128 EmitGlobalVariableLoad(proxy, typeof_mode); | |
| 1129 } | |
| 1130 | |
| 1131 | |
| 1132 MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var, | |
| 1133 Label* slow) { | |
| 1134 DCHECK(var->IsContextSlot()); | |
| 1135 Register context = esi; | |
| 1136 Register temp = ebx; | |
| 1137 | |
| 1138 for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) { | |
| 1139 if (s->NeedsContext()) { | |
| 1140 if (s->calls_sloppy_eval()) { | |
| 1141 // Check that extension is "the hole". | |
| 1142 __ JumpIfNotRoot(ContextOperand(context, Context::EXTENSION_INDEX), | |
| 1143 Heap::kTheHoleValueRootIndex, slow); | |
| 1144 } | |
| 1145 __ mov(temp, ContextOperand(context, Context::PREVIOUS_INDEX)); | |
| 1146 // Walk the rest of the chain without clobbering esi. | |
| 1147 context = temp; | |
| 1148 } | |
| 1149 } | |
| 1150 // Check that last extension is "the hole". | |
| 1151 __ JumpIfNotRoot(ContextOperand(context, Context::EXTENSION_INDEX), | |
| 1152 Heap::kTheHoleValueRootIndex, slow); | |
| 1153 | |
| 1154 // This function is used only for loads, not stores, so it's safe to | |
| 1155 // return an esi-based operand (the write barrier cannot be allowed to | |
| 1156 // destroy the esi register). | |
| 1157 return ContextOperand(context, var->index()); | |
| 1158 } | |
| 1159 | |
| 1160 | |
| 1161 void FullCodeGenerator::EmitDynamicLookupFastCase(VariableProxy* proxy, | |
| 1162 TypeofMode typeof_mode, | |
| 1163 Label* slow, Label* done) { | |
| 1164 // Generate fast-case code for variables that might be shadowed by | |
| 1165 // eval-introduced variables. Eval is used a lot without | |
| 1166 // introducing variables. In those cases, we do not want to | |
| 1167 // perform a runtime call for all variables in the scope | |
| 1168 // containing the eval. | |
| 1169 Variable* var = proxy->var(); | |
| 1170 if (var->mode() == DYNAMIC_GLOBAL) { | |
| 1171 EmitLoadGlobalCheckExtensions(proxy, typeof_mode, slow); | |
| 1172 __ jmp(done); | |
| 1173 } else if (var->mode() == DYNAMIC_LOCAL) { | |
| 1174 Variable* local = var->local_if_not_shadowed(); | |
| 1175 __ mov(eax, ContextSlotOperandCheckExtensions(local, slow)); | |
| 1176 if (local->binding_needs_init()) { | |
| 1177 __ cmp(eax, isolate()->factory()->the_hole_value()); | |
| 1178 __ j(not_equal, done); | |
| 1179 __ push(Immediate(var->name())); | |
| 1180 __ CallRuntime(Runtime::kThrowReferenceError); | |
| 1181 } else { | |
| 1182 __ jmp(done); | |
| 1183 } | |
| 1184 } | |
| 1185 } | |
| 1186 | |
| 1187 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy, | 1087 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy, |
| 1188 TypeofMode typeof_mode) { | 1088 TypeofMode typeof_mode) { |
| 1189 SetExpressionPosition(proxy); | 1089 SetExpressionPosition(proxy); |
| 1190 PrepareForBailoutForId(proxy->BeforeId(), BailoutState::NO_REGISTERS); | 1090 PrepareForBailoutForId(proxy->BeforeId(), BailoutState::NO_REGISTERS); |
| 1191 Variable* var = proxy->var(); | 1091 Variable* var = proxy->var(); |
| 1192 | 1092 |
| 1193 // Three cases: global variables, lookup variables, and all other types of | 1093 // Two cases: global variables and all other types of variables. |
| 1194 // variables. | |
| 1195 switch (var->location()) { | 1094 switch (var->location()) { |
| 1196 case VariableLocation::UNALLOCATED: { | 1095 case VariableLocation::UNALLOCATED: { |
| 1197 Comment cmnt(masm_, "[ Global variable"); | 1096 Comment cmnt(masm_, "[ Global variable"); |
| 1198 EmitGlobalVariableLoad(proxy, typeof_mode); | 1097 EmitGlobalVariableLoad(proxy, typeof_mode); |
| 1199 context()->Plug(eax); | 1098 context()->Plug(eax); |
| 1200 break; | 1099 break; |
| 1201 } | 1100 } |
| 1202 | 1101 |
| 1203 case VariableLocation::PARAMETER: | 1102 case VariableLocation::PARAMETER: |
| 1204 case VariableLocation::LOCAL: | 1103 case VariableLocation::LOCAL: |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1217 __ push(Immediate(var->name())); | 1116 __ push(Immediate(var->name())); |
| 1218 __ CallRuntime(Runtime::kThrowReferenceError); | 1117 __ CallRuntime(Runtime::kThrowReferenceError); |
| 1219 __ bind(&done); | 1118 __ bind(&done); |
| 1220 context()->Plug(eax); | 1119 context()->Plug(eax); |
| 1221 break; | 1120 break; |
| 1222 } | 1121 } |
| 1223 context()->Plug(var); | 1122 context()->Plug(var); |
| 1224 break; | 1123 break; |
| 1225 } | 1124 } |
| 1226 | 1125 |
| 1227 case VariableLocation::LOOKUP: { | 1126 case VariableLocation::LOOKUP: |
| 1228 Comment cmnt(masm_, "[ Lookup variable"); | |
| 1229 Label done, slow; | |
| 1230 // Generate code for loading from variables potentially shadowed | |
| 1231 // by eval-introduced variables. | |
| 1232 EmitDynamicLookupFastCase(proxy, typeof_mode, &slow, &done); | |
| 1233 __ bind(&slow); | |
| 1234 __ push(Immediate(var->name())); | |
| 1235 Runtime::FunctionId function_id = | |
| 1236 typeof_mode == NOT_INSIDE_TYPEOF | |
| 1237 ? Runtime::kLoadLookupSlot | |
| 1238 : Runtime::kLoadLookupSlotInsideTypeof; | |
| 1239 __ CallRuntime(function_id); | |
| 1240 __ bind(&done); | |
| 1241 context()->Plug(eax); | |
| 1242 break; | |
| 1243 } | |
| 1244 | |
| 1245 case VariableLocation::MODULE: | 1127 case VariableLocation::MODULE: |
| 1246 UNREACHABLE(); | 1128 UNREACHABLE(); |
| 1247 } | 1129 } |
| 1248 } | 1130 } |
| 1249 | 1131 |
| 1250 | 1132 |
| 1251 void FullCodeGenerator::EmitAccessor(ObjectLiteralProperty* property) { | 1133 void FullCodeGenerator::EmitAccessor(ObjectLiteralProperty* property) { |
| 1252 Expression* expression = (property == NULL) ? NULL : property->value(); | 1134 Expression* expression = (property == NULL) ? NULL : property->value(); |
| 1253 if (expression == NULL) { | 1135 if (expression == NULL) { |
| 1254 PushOperand(isolate()->factory()->null_value()); | 1136 PushOperand(isolate()->factory()->null_value()); |
| (...skipping 737 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1992 __ mov(edx, location); | 1874 __ mov(edx, location); |
| 1993 __ cmp(edx, isolate()->factory()->the_hole_value()); | 1875 __ cmp(edx, isolate()->factory()->the_hole_value()); |
| 1994 __ j(equal, &uninitialized_this); | 1876 __ j(equal, &uninitialized_this); |
| 1995 __ push(Immediate(var->name())); | 1877 __ push(Immediate(var->name())); |
| 1996 __ CallRuntime(Runtime::kThrowReferenceError); | 1878 __ CallRuntime(Runtime::kThrowReferenceError); |
| 1997 __ bind(&uninitialized_this); | 1879 __ bind(&uninitialized_this); |
| 1998 EmitStoreToStackLocalOrContextSlot(var, location); | 1880 EmitStoreToStackLocalOrContextSlot(var, location); |
| 1999 | 1881 |
| 2000 } else { | 1882 } else { |
| 2001 DCHECK(var->mode() != CONST || op == Token::INIT); | 1883 DCHECK(var->mode() != CONST || op == Token::INIT); |
| 2002 if (var->IsLookupSlot()) { | 1884 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); |
| 2003 // Assignment to var. | 1885 DCHECK(!var->IsLookupSlot()); |
| 2004 __ Push(Immediate(var->name())); | 1886 // Assignment to var or initializing assignment to let/const in harmony |
| 2005 __ Push(eax); | 1887 // mode. |
| 2006 __ CallRuntime(is_strict(language_mode()) | 1888 MemOperand location = VarOperand(var, ecx); |
| 2007 ? Runtime::kStoreLookupSlot_Strict | 1889 if (FLAG_debug_code && var->mode() == LET && op == Token::INIT) { |
| 2008 : Runtime::kStoreLookupSlot_Sloppy); | 1890 // Check for an uninitialized let binding. |
| 2009 } else { | 1891 __ mov(edx, location); |
| 2010 // Assignment to var or initializing assignment to let/const in harmony | 1892 __ cmp(edx, isolate()->factory()->the_hole_value()); |
| 2011 // mode. | 1893 __ Check(equal, kLetBindingReInitialization); |
| 2012 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); | |
| 2013 MemOperand location = VarOperand(var, ecx); | |
| 2014 if (FLAG_debug_code && var->mode() == LET && op == Token::INIT) { | |
| 2015 // Check for an uninitialized let binding. | |
| 2016 __ mov(edx, location); | |
| 2017 __ cmp(edx, isolate()->factory()->the_hole_value()); | |
| 2018 __ Check(equal, kLetBindingReInitialization); | |
| 2019 } | |
| 2020 EmitStoreToStackLocalOrContextSlot(var, location); | |
| 2021 } | 1894 } |
| 1895 EmitStoreToStackLocalOrContextSlot(var, location); |
| 2022 } | 1896 } |
| 2023 } | 1897 } |
| 2024 | 1898 |
| 2025 | 1899 |
| 2026 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { | 1900 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { |
| 2027 // Assignment to a property, using a named store IC. | 1901 // Assignment to a property, using a named store IC. |
| 2028 // eax : value | 1902 // eax : value |
| 2029 // esp[0] : receiver | 1903 // esp[0] : receiver |
| 2030 Property* prop = expr->target()->AsProperty(); | 1904 Property* prop = expr->target()->AsProperty(); |
| 2031 DCHECK(prop != NULL); | 1905 DCHECK(prop != NULL); |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2231 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize)); | 2105 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize)); |
| 2232 __ Move(eax, Immediate(arg_count)); | 2106 __ Move(eax, Immediate(arg_count)); |
| 2233 CallIC(code); | 2107 CallIC(code); |
| 2234 OperandStackDepthDecrement(arg_count + 1); | 2108 OperandStackDepthDecrement(arg_count + 1); |
| 2235 | 2109 |
| 2236 RecordJSReturnSite(expr); | 2110 RecordJSReturnSite(expr); |
| 2237 RestoreContext(); | 2111 RestoreContext(); |
| 2238 context()->DropAndPlug(1, eax); | 2112 context()->DropAndPlug(1, eax); |
| 2239 } | 2113 } |
| 2240 | 2114 |
| 2241 void FullCodeGenerator::EmitResolvePossiblyDirectEval(Call* expr) { | |
| 2242 int arg_count = expr->arguments()->length(); | |
| 2243 // Push copy of the first argument or undefined if it doesn't exist. | |
| 2244 if (arg_count > 0) { | |
| 2245 __ push(Operand(esp, arg_count * kPointerSize)); | |
| 2246 } else { | |
| 2247 __ push(Immediate(isolate()->factory()->undefined_value())); | |
| 2248 } | |
| 2249 | |
| 2250 // Push the enclosing function. | |
| 2251 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); | |
| 2252 | |
| 2253 // Push the language mode. | |
| 2254 __ push(Immediate(Smi::FromInt(language_mode()))); | |
| 2255 | |
| 2256 // Push the start position of the scope the calls resides in. | |
| 2257 __ push(Immediate(Smi::FromInt(scope()->start_position()))); | |
| 2258 | |
| 2259 // Push the source position of the eval call. | |
| 2260 __ push(Immediate(Smi::FromInt(expr->position()))); | |
| 2261 | |
| 2262 // Do the runtime call. | |
| 2263 __ CallRuntime(Runtime::kResolvePossiblyDirectEval); | |
| 2264 } | |
| 2265 | |
| 2266 | |
| 2267 // See http://www.ecma-international.org/ecma-262/6.0/#sec-function-calls. | |
| 2268 void FullCodeGenerator::PushCalleeAndWithBaseObject(Call* expr) { | |
| 2269 VariableProxy* callee = expr->expression()->AsVariableProxy(); | |
| 2270 if (callee->var()->IsLookupSlot()) { | |
| 2271 Label slow, done; | |
| 2272 SetExpressionPosition(callee); | |
| 2273 // Generate code for loading from variables potentially shadowed by | |
| 2274 // eval-introduced variables. | |
| 2275 EmitDynamicLookupFastCase(callee, NOT_INSIDE_TYPEOF, &slow, &done); | |
| 2276 | |
| 2277 __ bind(&slow); | |
| 2278 // Call the runtime to find the function to call (returned in eax) and | |
| 2279 // the object holding it (returned in edx). | |
| 2280 __ Push(callee->name()); | |
| 2281 __ CallRuntime(Runtime::kLoadLookupSlotForCall); | |
| 2282 PushOperand(eax); // Function. | |
| 2283 PushOperand(edx); // Receiver. | |
| 2284 PrepareForBailoutForId(expr->LookupId(), BailoutState::NO_REGISTERS); | |
| 2285 | |
| 2286 // If fast case code has been generated, emit code to push the function | |
| 2287 // and receiver and have the slow path jump around this code. | |
| 2288 if (done.is_linked()) { | |
| 2289 Label call; | |
| 2290 __ jmp(&call, Label::kNear); | |
| 2291 __ bind(&done); | |
| 2292 // Push function. | |
| 2293 __ push(eax); | |
| 2294 // The receiver is implicitly the global receiver. Indicate this by | |
| 2295 // passing the hole to the call function stub. | |
| 2296 __ push(Immediate(isolate()->factory()->undefined_value())); | |
| 2297 __ bind(&call); | |
| 2298 } | |
| 2299 } else { | |
| 2300 VisitForStackValue(callee); | |
| 2301 // refEnv.WithBaseObject() | |
| 2302 PushOperand(isolate()->factory()->undefined_value()); | |
| 2303 } | |
| 2304 } | |
| 2305 | |
| 2306 | |
| 2307 void FullCodeGenerator::EmitPossiblyEvalCall(Call* expr) { | |
| 2308 // In a call to eval, we first call Runtime_ResolvePossiblyDirectEval | |
| 2309 // to resolve the function we need to call. Then we call the resolved | |
| 2310 // function using the given arguments. | |
| 2311 ZoneList<Expression*>* args = expr->arguments(); | |
| 2312 int arg_count = args->length(); | |
| 2313 | |
| 2314 PushCalleeAndWithBaseObject(expr); | |
| 2315 | |
| 2316 // Push the arguments. | |
| 2317 for (int i = 0; i < arg_count; i++) { | |
| 2318 VisitForStackValue(args->at(i)); | |
| 2319 } | |
| 2320 | |
| 2321 // Push a copy of the function (found below the arguments) and | |
| 2322 // resolve eval. | |
| 2323 __ push(Operand(esp, (arg_count + 1) * kPointerSize)); | |
| 2324 EmitResolvePossiblyDirectEval(expr); | |
| 2325 | |
| 2326 // Touch up the stack with the resolved function. | |
| 2327 __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax); | |
| 2328 | |
| 2329 PrepareForBailoutForId(expr->EvalId(), BailoutState::NO_REGISTERS); | |
| 2330 | |
| 2331 SetCallPosition(expr); | |
| 2332 Handle<Code> code = CodeFactory::CallIC(isolate(), ConvertReceiverMode::kAny, | |
| 2333 expr->tail_call_mode()) | |
| 2334 .code(); | |
| 2335 __ Move(edx, Immediate(SmiFromSlot(expr->CallFeedbackICSlot()))); | |
| 2336 __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize)); | |
| 2337 __ Move(eax, Immediate(arg_count)); | |
| 2338 __ call(code, RelocInfo::CODE_TARGET); | |
| 2339 OperandStackDepthDecrement(arg_count + 1); | |
| 2340 RecordJSReturnSite(expr); | |
| 2341 RestoreContext(); | |
| 2342 context()->DropAndPlug(1, eax); | |
| 2343 } | |
| 2344 | |
| 2345 | |
| 2346 void FullCodeGenerator::VisitCallNew(CallNew* expr) { | 2115 void FullCodeGenerator::VisitCallNew(CallNew* expr) { |
| 2347 Comment cmnt(masm_, "[ CallNew"); | 2116 Comment cmnt(masm_, "[ CallNew"); |
| 2348 // According to ECMA-262, section 11.2.2, page 44, the function | 2117 // According to ECMA-262, section 11.2.2, page 44, the function |
| 2349 // expression in new calls must be evaluated before the | 2118 // expression in new calls must be evaluated before the |
| 2350 // arguments. | 2119 // arguments. |
| 2351 | 2120 |
| 2352 // Push constructor on the stack. If it's not a function it's used as | 2121 // Push constructor on the stack. If it's not a function it's used as |
| 2353 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is | 2122 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is |
| 2354 // ignored. | 2123 // ignored. |
| 2355 DCHECK(!expr->expression()->IsSuperPropertyReference()); | 2124 DCHECK(!expr->expression()->IsSuperPropertyReference()); |
| (...skipping 403 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2759 // Delete of an unqualified identifier is disallowed in strict mode but | 2528 // Delete of an unqualified identifier is disallowed in strict mode but |
| 2760 // "delete this" is allowed. | 2529 // "delete this" is allowed. |
| 2761 bool is_this = var->is_this(); | 2530 bool is_this = var->is_this(); |
| 2762 DCHECK(is_sloppy(language_mode()) || is_this); | 2531 DCHECK(is_sloppy(language_mode()) || is_this); |
| 2763 if (var->IsUnallocated()) { | 2532 if (var->IsUnallocated()) { |
| 2764 __ mov(eax, NativeContextOperand()); | 2533 __ mov(eax, NativeContextOperand()); |
| 2765 __ push(ContextOperand(eax, Context::EXTENSION_INDEX)); | 2534 __ push(ContextOperand(eax, Context::EXTENSION_INDEX)); |
| 2766 __ push(Immediate(var->name())); | 2535 __ push(Immediate(var->name())); |
| 2767 __ CallRuntime(Runtime::kDeleteProperty_Sloppy); | 2536 __ CallRuntime(Runtime::kDeleteProperty_Sloppy); |
| 2768 context()->Plug(eax); | 2537 context()->Plug(eax); |
| 2769 } else if (var->IsStackAllocated() || var->IsContextSlot()) { | 2538 } else { |
| 2539 DCHECK(!var->IsLookupSlot()); |
| 2540 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); |
| 2770 // Result of deleting non-global variables is false. 'this' is | 2541 // Result of deleting non-global variables is false. 'this' is |
| 2771 // not really a variable, though we implement it as one. The | 2542 // not really a variable, though we implement it as one. The |
| 2772 // subexpression does not have side effects. | 2543 // subexpression does not have side effects. |
| 2773 context()->Plug(is_this); | 2544 context()->Plug(is_this); |
| 2774 } else { | |
| 2775 // Non-global variable. Call the runtime to try to delete from the | |
| 2776 // context where the variable was introduced. | |
| 2777 __ Push(var->name()); | |
| 2778 __ CallRuntime(Runtime::kDeleteLookupSlot); | |
| 2779 context()->Plug(eax); | |
| 2780 } | 2545 } |
| 2781 } else { | 2546 } else { |
| 2782 // Result of deleting non-property, non-variable reference is true. | 2547 // Result of deleting non-property, non-variable reference is true. |
| 2783 // The subexpression may have side effects. | 2548 // The subexpression may have side effects. |
| 2784 VisitForEffect(expr->expression()); | 2549 VisitForEffect(expr->expression()); |
| 2785 context()->Plug(true); | 2550 context()->Plug(true); |
| 2786 } | 2551 } |
| 2787 break; | 2552 break; |
| 2788 } | 2553 } |
| 2789 | 2554 |
| (...skipping 679 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3469 isolate->builtins()->OnStackReplacement()->entry(), | 3234 isolate->builtins()->OnStackReplacement()->entry(), |
| 3470 Assembler::target_address_at(call_target_address, unoptimized_code)); | 3235 Assembler::target_address_at(call_target_address, unoptimized_code)); |
| 3471 return ON_STACK_REPLACEMENT; | 3236 return ON_STACK_REPLACEMENT; |
| 3472 } | 3237 } |
| 3473 | 3238 |
| 3474 | 3239 |
| 3475 } // namespace internal | 3240 } // namespace internal |
| 3476 } // namespace v8 | 3241 } // namespace v8 |
| 3477 | 3242 |
| 3478 #endif // V8_TARGET_ARCH_X87 | 3243 #endif // V8_TARGET_ARCH_X87 |
| OLD | NEW |