| 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_X64 | 5 #if V8_TARGET_ARCH_X64 |
| 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 752 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 763 if (variable->binding_needs_init()) { | 763 if (variable->binding_needs_init()) { |
| 764 Comment cmnt(masm_, "[ VariableDeclaration"); | 764 Comment cmnt(masm_, "[ VariableDeclaration"); |
| 765 EmitDebugCheckDeclarationContext(variable); | 765 EmitDebugCheckDeclarationContext(variable); |
| 766 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); | 766 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); |
| 767 __ movp(ContextOperand(rsi, variable->index()), kScratchRegister); | 767 __ movp(ContextOperand(rsi, variable->index()), kScratchRegister); |
| 768 // No write barrier since the hole value is in old space. | 768 // No write barrier since the hole value is in old space. |
| 769 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS); | 769 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS); |
| 770 } | 770 } |
| 771 break; | 771 break; |
| 772 | 772 |
| 773 case VariableLocation::LOOKUP: { | 773 case VariableLocation::LOOKUP: |
| 774 Comment cmnt(masm_, "[ VariableDeclaration"); | |
| 775 DCHECK_EQ(VAR, variable->mode()); | |
| 776 DCHECK(!variable->binding_needs_init()); | |
| 777 __ Push(variable->name()); | |
| 778 __ CallRuntime(Runtime::kDeclareEvalVar); | |
| 779 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS); | |
| 780 break; | |
| 781 } | |
| 782 | |
| 783 case VariableLocation::MODULE: | 774 case VariableLocation::MODULE: |
| 784 UNREACHABLE(); | 775 UNREACHABLE(); |
| 785 } | 776 } |
| 786 } | 777 } |
| 787 | 778 |
| 788 | 779 |
| 789 void FullCodeGenerator::VisitFunctionDeclaration( | 780 void FullCodeGenerator::VisitFunctionDeclaration( |
| 790 FunctionDeclaration* declaration) { | 781 FunctionDeclaration* declaration) { |
| 791 VariableProxy* proxy = declaration->proxy(); | 782 VariableProxy* proxy = declaration->proxy(); |
| 792 Variable* variable = proxy->var(); | 783 Variable* variable = proxy->var(); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 823 offset, | 814 offset, |
| 824 result_register(), | 815 result_register(), |
| 825 rcx, | 816 rcx, |
| 826 kDontSaveFPRegs, | 817 kDontSaveFPRegs, |
| 827 EMIT_REMEMBERED_SET, | 818 EMIT_REMEMBERED_SET, |
| 828 OMIT_SMI_CHECK); | 819 OMIT_SMI_CHECK); |
| 829 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS); | 820 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS); |
| 830 break; | 821 break; |
| 831 } | 822 } |
| 832 | 823 |
| 833 case VariableLocation::LOOKUP: { | 824 case VariableLocation::LOOKUP: |
| 834 Comment cmnt(masm_, "[ FunctionDeclaration"); | |
| 835 PushOperand(variable->name()); | |
| 836 VisitForStackValue(declaration->fun()); | |
| 837 CallRuntimeWithOperands(Runtime::kDeclareEvalFunction); | |
| 838 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS); | |
| 839 break; | |
| 840 } | |
| 841 | |
| 842 case VariableLocation::MODULE: | 825 case VariableLocation::MODULE: |
| 843 UNREACHABLE(); | 826 UNREACHABLE(); |
| 844 } | 827 } |
| 845 } | 828 } |
| 846 | 829 |
| 847 | 830 |
| 848 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 831 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| 849 // Call the runtime to declare the globals. | 832 // Call the runtime to declare the globals. |
| 850 __ Push(pairs); | 833 __ Push(pairs); |
| 851 __ Push(Smi::FromInt(DeclareGlobalsFlags())); | 834 __ Push(Smi::FromInt(DeclareGlobalsFlags())); |
| (...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1131 void FullCodeGenerator::EmitSetHomeObjectAccumulator(Expression* initializer, | 1114 void FullCodeGenerator::EmitSetHomeObjectAccumulator(Expression* initializer, |
| 1132 int offset, | 1115 int offset, |
| 1133 FeedbackVectorSlot slot) { | 1116 FeedbackVectorSlot slot) { |
| 1134 DCHECK(NeedsHomeObject(initializer)); | 1117 DCHECK(NeedsHomeObject(initializer)); |
| 1135 __ movp(StoreDescriptor::ReceiverRegister(), rax); | 1118 __ movp(StoreDescriptor::ReceiverRegister(), rax); |
| 1136 __ movp(StoreDescriptor::ValueRegister(), | 1119 __ movp(StoreDescriptor::ValueRegister(), |
| 1137 Operand(rsp, offset * kPointerSize)); | 1120 Operand(rsp, offset * kPointerSize)); |
| 1138 CallStoreIC(slot, isolate()->factory()->home_object_symbol()); | 1121 CallStoreIC(slot, isolate()->factory()->home_object_symbol()); |
| 1139 } | 1122 } |
| 1140 | 1123 |
| 1141 | |
| 1142 void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy, | |
| 1143 TypeofMode typeof_mode, | |
| 1144 Label* slow) { | |
| 1145 Register context = rsi; | |
| 1146 Register temp = rdx; | |
| 1147 | |
| 1148 int to_check = scope()->ContextChainLengthUntilOutermostSloppyEval(); | |
| 1149 for (Scope* s = scope(); to_check > 0; s = s->outer_scope()) { | |
| 1150 if (!s->NeedsContext()) continue; | |
| 1151 if (s->calls_sloppy_eval()) { | |
| 1152 // Check that extension is "the hole". | |
| 1153 __ JumpIfNotRoot(ContextOperand(context, Context::EXTENSION_INDEX), | |
| 1154 Heap::kTheHoleValueRootIndex, slow); | |
| 1155 } | |
| 1156 // Load next context in chain. | |
| 1157 __ movp(temp, ContextOperand(context, Context::PREVIOUS_INDEX)); | |
| 1158 // Walk the rest of the chain without clobbering rsi. | |
| 1159 context = temp; | |
| 1160 to_check--; | |
| 1161 } | |
| 1162 | |
| 1163 // All extension objects were empty and it is safe to use a normal global | |
| 1164 // load machinery. | |
| 1165 EmitGlobalVariableLoad(proxy, typeof_mode); | |
| 1166 } | |
| 1167 | |
| 1168 | |
| 1169 MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var, | |
| 1170 Label* slow) { | |
| 1171 DCHECK(var->IsContextSlot()); | |
| 1172 Register context = rsi; | |
| 1173 Register temp = rbx; | |
| 1174 | |
| 1175 for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) { | |
| 1176 if (s->NeedsContext()) { | |
| 1177 if (s->calls_sloppy_eval()) { | |
| 1178 // Check that extension is "the hole". | |
| 1179 __ JumpIfNotRoot(ContextOperand(context, Context::EXTENSION_INDEX), | |
| 1180 Heap::kTheHoleValueRootIndex, slow); | |
| 1181 } | |
| 1182 __ movp(temp, ContextOperand(context, Context::PREVIOUS_INDEX)); | |
| 1183 // Walk the rest of the chain without clobbering rsi. | |
| 1184 context = temp; | |
| 1185 } | |
| 1186 } | |
| 1187 // Check that last extension is "the hole". | |
| 1188 __ JumpIfNotRoot(ContextOperand(context, Context::EXTENSION_INDEX), | |
| 1189 Heap::kTheHoleValueRootIndex, slow); | |
| 1190 | |
| 1191 // This function is used only for loads, not stores, so it's safe to | |
| 1192 // return an rsi-based operand (the write barrier cannot be allowed to | |
| 1193 // destroy the rsi register). | |
| 1194 return ContextOperand(context, var->index()); | |
| 1195 } | |
| 1196 | |
| 1197 | |
| 1198 void FullCodeGenerator::EmitDynamicLookupFastCase(VariableProxy* proxy, | |
| 1199 TypeofMode typeof_mode, | |
| 1200 Label* slow, Label* done) { | |
| 1201 // Generate fast-case code for variables that might be shadowed by | |
| 1202 // eval-introduced variables. Eval is used a lot without | |
| 1203 // introducing variables. In those cases, we do not want to | |
| 1204 // perform a runtime call for all variables in the scope | |
| 1205 // containing the eval. | |
| 1206 Variable* var = proxy->var(); | |
| 1207 if (var->mode() == DYNAMIC_GLOBAL) { | |
| 1208 EmitLoadGlobalCheckExtensions(proxy, typeof_mode, slow); | |
| 1209 __ jmp(done); | |
| 1210 } else if (var->mode() == DYNAMIC_LOCAL) { | |
| 1211 Variable* local = var->local_if_not_shadowed(); | |
| 1212 __ movp(rax, ContextSlotOperandCheckExtensions(local, slow)); | |
| 1213 if (local->binding_needs_init()) { | |
| 1214 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); | |
| 1215 __ j(not_equal, done); | |
| 1216 __ Push(var->name()); | |
| 1217 __ CallRuntime(Runtime::kThrowReferenceError); | |
| 1218 } else { | |
| 1219 __ jmp(done); | |
| 1220 } | |
| 1221 } | |
| 1222 } | |
| 1223 | |
| 1224 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy, | 1124 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy, |
| 1225 TypeofMode typeof_mode) { | 1125 TypeofMode typeof_mode) { |
| 1226 // Record position before possible IC call. | 1126 // Record position before possible IC call. |
| 1227 SetExpressionPosition(proxy); | 1127 SetExpressionPosition(proxy); |
| 1228 PrepareForBailoutForId(proxy->BeforeId(), BailoutState::NO_REGISTERS); | 1128 PrepareForBailoutForId(proxy->BeforeId(), BailoutState::NO_REGISTERS); |
| 1229 Variable* var = proxy->var(); | 1129 Variable* var = proxy->var(); |
| 1230 | 1130 |
| 1231 // Three cases: global variables, lookup variables, and all other types of | 1131 // Two cases: global variable, and all other types of variables. |
| 1232 // variables. | |
| 1233 switch (var->location()) { | 1132 switch (var->location()) { |
| 1234 case VariableLocation::UNALLOCATED: { | 1133 case VariableLocation::UNALLOCATED: { |
| 1235 Comment cmnt(masm_, "[ Global variable"); | 1134 Comment cmnt(masm_, "[ Global variable"); |
| 1236 EmitGlobalVariableLoad(proxy, typeof_mode); | 1135 EmitGlobalVariableLoad(proxy, typeof_mode); |
| 1237 context()->Plug(rax); | 1136 context()->Plug(rax); |
| 1238 break; | 1137 break; |
| 1239 } | 1138 } |
| 1240 | 1139 |
| 1241 case VariableLocation::PARAMETER: | 1140 case VariableLocation::PARAMETER: |
| 1242 case VariableLocation::LOCAL: | 1141 case VariableLocation::LOCAL: |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1255 __ Push(var->name()); | 1154 __ Push(var->name()); |
| 1256 __ CallRuntime(Runtime::kThrowReferenceError); | 1155 __ CallRuntime(Runtime::kThrowReferenceError); |
| 1257 __ bind(&done); | 1156 __ bind(&done); |
| 1258 context()->Plug(rax); | 1157 context()->Plug(rax); |
| 1259 break; | 1158 break; |
| 1260 } | 1159 } |
| 1261 context()->Plug(var); | 1160 context()->Plug(var); |
| 1262 break; | 1161 break; |
| 1263 } | 1162 } |
| 1264 | 1163 |
| 1265 case VariableLocation::LOOKUP: { | 1164 case VariableLocation::LOOKUP: |
| 1266 Comment cmnt(masm_, "[ Lookup slot"); | |
| 1267 Label done, slow; | |
| 1268 // Generate code for loading from variables potentially shadowed | |
| 1269 // by eval-introduced variables. | |
| 1270 EmitDynamicLookupFastCase(proxy, typeof_mode, &slow, &done); | |
| 1271 __ bind(&slow); | |
| 1272 __ Push(var->name()); | |
| 1273 Runtime::FunctionId function_id = | |
| 1274 typeof_mode == NOT_INSIDE_TYPEOF | |
| 1275 ? Runtime::kLoadLookupSlot | |
| 1276 : Runtime::kLoadLookupSlotInsideTypeof; | |
| 1277 __ CallRuntime(function_id); | |
| 1278 __ bind(&done); | |
| 1279 context()->Plug(rax); | |
| 1280 break; | |
| 1281 } | |
| 1282 | |
| 1283 case VariableLocation::MODULE: | 1165 case VariableLocation::MODULE: |
| 1284 UNREACHABLE(); | 1166 UNREACHABLE(); |
| 1285 } | 1167 } |
| 1286 } | 1168 } |
| 1287 | 1169 |
| 1288 | 1170 |
| 1289 void FullCodeGenerator::EmitAccessor(ObjectLiteralProperty* property) { | 1171 void FullCodeGenerator::EmitAccessor(ObjectLiteralProperty* property) { |
| 1290 Expression* expression = (property == NULL) ? NULL : property->value(); | 1172 Expression* expression = (property == NULL) ? NULL : property->value(); |
| 1291 if (expression == NULL) { | 1173 if (expression == NULL) { |
| 1292 OperandStackDepthIncrement(1); | 1174 OperandStackDepthIncrement(1); |
| (...skipping 696 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1989 __ movp(rdx, location); | 1871 __ movp(rdx, location); |
| 1990 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); | 1872 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); |
| 1991 __ j(equal, &uninitialized_this); | 1873 __ j(equal, &uninitialized_this); |
| 1992 __ Push(var->name()); | 1874 __ Push(var->name()); |
| 1993 __ CallRuntime(Runtime::kThrowReferenceError); | 1875 __ CallRuntime(Runtime::kThrowReferenceError); |
| 1994 __ bind(&uninitialized_this); | 1876 __ bind(&uninitialized_this); |
| 1995 EmitStoreToStackLocalOrContextSlot(var, location); | 1877 EmitStoreToStackLocalOrContextSlot(var, location); |
| 1996 | 1878 |
| 1997 } else { | 1879 } else { |
| 1998 DCHECK(var->mode() != CONST || op == Token::INIT); | 1880 DCHECK(var->mode() != CONST || op == Token::INIT); |
| 1999 if (var->IsLookupSlot()) { | 1881 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); |
| 2000 // Assignment to var. | 1882 DCHECK(!var->IsLookupSlot()); |
| 2001 __ Push(var->name()); | 1883 // Assignment to var or initializing assignment to let/const in harmony |
| 2002 __ Push(rax); | 1884 // mode. |
| 2003 __ CallRuntime(is_strict(language_mode()) | 1885 MemOperand location = VarOperand(var, rcx); |
| 2004 ? Runtime::kStoreLookupSlot_Strict | 1886 if (FLAG_debug_code && var->mode() == LET && op == Token::INIT) { |
| 2005 : Runtime::kStoreLookupSlot_Sloppy); | 1887 // Check for an uninitialized let binding. |
| 2006 } else { | 1888 __ movp(rdx, location); |
| 2007 // Assignment to var or initializing assignment to let/const in harmony | 1889 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); |
| 2008 // mode. | 1890 __ Check(equal, kLetBindingReInitialization); |
| 2009 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); | |
| 2010 MemOperand location = VarOperand(var, rcx); | |
| 2011 if (FLAG_debug_code && var->mode() == LET && op == Token::INIT) { | |
| 2012 // Check for an uninitialized let binding. | |
| 2013 __ movp(rdx, location); | |
| 2014 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); | |
| 2015 __ Check(equal, kLetBindingReInitialization); | |
| 2016 } | |
| 2017 EmitStoreToStackLocalOrContextSlot(var, location); | |
| 2018 } | 1891 } |
| 1892 EmitStoreToStackLocalOrContextSlot(var, location); |
| 2019 } | 1893 } |
| 2020 } | 1894 } |
| 2021 | 1895 |
| 2022 | 1896 |
| 2023 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { | 1897 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { |
| 2024 // Assignment to a property, using a named store IC. | 1898 // Assignment to a property, using a named store IC. |
| 2025 Property* prop = expr->target()->AsProperty(); | 1899 Property* prop = expr->target()->AsProperty(); |
| 2026 DCHECK(prop != NULL); | 1900 DCHECK(prop != NULL); |
| 2027 DCHECK(prop->key()->IsLiteral()); | 1901 DCHECK(prop->key()->IsLiteral()); |
| 2028 | 1902 |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2228 __ Set(rax, arg_count); | 2102 __ Set(rax, arg_count); |
| 2229 CallIC(code); | 2103 CallIC(code); |
| 2230 OperandStackDepthDecrement(arg_count + 1); | 2104 OperandStackDepthDecrement(arg_count + 1); |
| 2231 | 2105 |
| 2232 RecordJSReturnSite(expr); | 2106 RecordJSReturnSite(expr); |
| 2233 RestoreContext(); | 2107 RestoreContext(); |
| 2234 // Discard the function left on TOS. | 2108 // Discard the function left on TOS. |
| 2235 context()->DropAndPlug(1, rax); | 2109 context()->DropAndPlug(1, rax); |
| 2236 } | 2110 } |
| 2237 | 2111 |
| 2238 void FullCodeGenerator::EmitResolvePossiblyDirectEval(Call* expr) { | |
| 2239 int arg_count = expr->arguments()->length(); | |
| 2240 // Push copy of the first argument or undefined if it doesn't exist. | |
| 2241 if (arg_count > 0) { | |
| 2242 __ Push(Operand(rsp, arg_count * kPointerSize)); | |
| 2243 } else { | |
| 2244 __ PushRoot(Heap::kUndefinedValueRootIndex); | |
| 2245 } | |
| 2246 | |
| 2247 // Push the enclosing function. | |
| 2248 __ Push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | |
| 2249 | |
| 2250 // Push the language mode. | |
| 2251 __ Push(Smi::FromInt(language_mode())); | |
| 2252 | |
| 2253 // Push the start position of the scope the calls resides in. | |
| 2254 __ Push(Smi::FromInt(scope()->start_position())); | |
| 2255 | |
| 2256 // Push the source position of the eval call. | |
| 2257 __ Push(Smi::FromInt(expr->position())); | |
| 2258 | |
| 2259 // Do the runtime call. | |
| 2260 __ CallRuntime(Runtime::kResolvePossiblyDirectEval); | |
| 2261 } | |
| 2262 | |
| 2263 | |
| 2264 // See http://www.ecma-international.org/ecma-262/6.0/#sec-function-calls. | |
| 2265 void FullCodeGenerator::PushCalleeAndWithBaseObject(Call* expr) { | |
| 2266 VariableProxy* callee = expr->expression()->AsVariableProxy(); | |
| 2267 if (callee->var()->IsLookupSlot()) { | |
| 2268 Label slow, done; | |
| 2269 SetExpressionPosition(callee); | |
| 2270 // Generate code for loading from variables potentially shadowed by | |
| 2271 // eval-introduced variables. | |
| 2272 EmitDynamicLookupFastCase(callee, NOT_INSIDE_TYPEOF, &slow, &done); | |
| 2273 __ bind(&slow); | |
| 2274 // Call the runtime to find the function to call (returned in rax) and | |
| 2275 // the object holding it (returned in rdx). | |
| 2276 __ Push(callee->name()); | |
| 2277 __ CallRuntime(Runtime::kLoadLookupSlotForCall); | |
| 2278 PushOperand(rax); // Function. | |
| 2279 PushOperand(rdx); // Receiver. | |
| 2280 PrepareForBailoutForId(expr->LookupId(), BailoutState::NO_REGISTERS); | |
| 2281 | |
| 2282 // If fast case code has been generated, emit code to push the function | |
| 2283 // and receiver and have the slow path jump around this code. | |
| 2284 if (done.is_linked()) { | |
| 2285 Label call; | |
| 2286 __ jmp(&call, Label::kNear); | |
| 2287 __ bind(&done); | |
| 2288 // Push function. | |
| 2289 __ Push(rax); | |
| 2290 // Pass undefined as the receiver, which is the WithBaseObject of a | |
| 2291 // non-object environment record. If the callee is sloppy, it will patch | |
| 2292 // it up to be the global receiver. | |
| 2293 __ PushRoot(Heap::kUndefinedValueRootIndex); | |
| 2294 __ bind(&call); | |
| 2295 } | |
| 2296 } else { | |
| 2297 VisitForStackValue(callee); | |
| 2298 // refEnv.WithBaseObject() | |
| 2299 OperandStackDepthIncrement(1); | |
| 2300 __ PushRoot(Heap::kUndefinedValueRootIndex); | |
| 2301 } | |
| 2302 } | |
| 2303 | |
| 2304 | |
| 2305 void FullCodeGenerator::EmitPossiblyEvalCall(Call* expr) { | |
| 2306 // In a call to eval, we first call Runtime_ResolvePossiblyDirectEval | |
| 2307 // to resolve the function we need to call. Then we call the resolved | |
| 2308 // function using the given arguments. | |
| 2309 ZoneList<Expression*>* args = expr->arguments(); | |
| 2310 int arg_count = args->length(); | |
| 2311 PushCalleeAndWithBaseObject(expr); | |
| 2312 | |
| 2313 // Push the arguments. | |
| 2314 for (int i = 0; i < arg_count; i++) { | |
| 2315 VisitForStackValue(args->at(i)); | |
| 2316 } | |
| 2317 | |
| 2318 // Push a copy of the function (found below the arguments) and resolve | |
| 2319 // eval. | |
| 2320 __ Push(Operand(rsp, (arg_count + 1) * kPointerSize)); | |
| 2321 EmitResolvePossiblyDirectEval(expr); | |
| 2322 | |
| 2323 // Touch up the callee. | |
| 2324 __ movp(Operand(rsp, (arg_count + 1) * kPointerSize), rax); | |
| 2325 | |
| 2326 PrepareForBailoutForId(expr->EvalId(), BailoutState::NO_REGISTERS); | |
| 2327 | |
| 2328 SetCallPosition(expr); | |
| 2329 Handle<Code> code = CodeFactory::CallIC(isolate(), ConvertReceiverMode::kAny, | |
| 2330 expr->tail_call_mode()) | |
| 2331 .code(); | |
| 2332 __ Move(rdx, SmiFromSlot(expr->CallFeedbackICSlot())); | |
| 2333 __ movp(rdi, Operand(rsp, (arg_count + 1) * kPointerSize)); | |
| 2334 __ Set(rax, arg_count); | |
| 2335 __ call(code, RelocInfo::CODE_TARGET); | |
| 2336 OperandStackDepthDecrement(arg_count + 1); | |
| 2337 RecordJSReturnSite(expr); | |
| 2338 RestoreContext(); | |
| 2339 context()->DropAndPlug(1, rax); | |
| 2340 } | |
| 2341 | |
| 2342 | |
| 2343 void FullCodeGenerator::VisitCallNew(CallNew* expr) { | 2112 void FullCodeGenerator::VisitCallNew(CallNew* expr) { |
| 2344 Comment cmnt(masm_, "[ CallNew"); | 2113 Comment cmnt(masm_, "[ CallNew"); |
| 2345 // According to ECMA-262, section 11.2.2, page 44, the function | 2114 // According to ECMA-262, section 11.2.2, page 44, the function |
| 2346 // expression in new calls must be evaluated before the | 2115 // expression in new calls must be evaluated before the |
| 2347 // arguments. | 2116 // arguments. |
| 2348 | 2117 |
| 2349 // Push constructor on the stack. If it's not a function it's used as | 2118 // Push constructor on the stack. If it's not a function it's used as |
| 2350 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is | 2119 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is |
| 2351 // ignored. | 2120 // ignored. |
| 2352 DCHECK(!expr->expression()->IsSuperPropertyReference()); | 2121 DCHECK(!expr->expression()->IsSuperPropertyReference()); |
| (...skipping 404 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2757 // Delete of an unqualified identifier is disallowed in strict mode but | 2526 // Delete of an unqualified identifier is disallowed in strict mode but |
| 2758 // "delete this" is allowed. | 2527 // "delete this" is allowed. |
| 2759 bool is_this = var->is_this(); | 2528 bool is_this = var->is_this(); |
| 2760 DCHECK(is_sloppy(language_mode()) || is_this); | 2529 DCHECK(is_sloppy(language_mode()) || is_this); |
| 2761 if (var->IsUnallocated()) { | 2530 if (var->IsUnallocated()) { |
| 2762 __ movp(rax, NativeContextOperand()); | 2531 __ movp(rax, NativeContextOperand()); |
| 2763 __ Push(ContextOperand(rax, Context::EXTENSION_INDEX)); | 2532 __ Push(ContextOperand(rax, Context::EXTENSION_INDEX)); |
| 2764 __ Push(var->name()); | 2533 __ Push(var->name()); |
| 2765 __ CallRuntime(Runtime::kDeleteProperty_Sloppy); | 2534 __ CallRuntime(Runtime::kDeleteProperty_Sloppy); |
| 2766 context()->Plug(rax); | 2535 context()->Plug(rax); |
| 2767 } else if (var->IsStackAllocated() || var->IsContextSlot()) { | 2536 } else { |
| 2537 DCHECK(!var->IsLookupSlot()); |
| 2538 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); |
| 2768 // Result of deleting non-global variables is false. 'this' is | 2539 // Result of deleting non-global variables is false. 'this' is |
| 2769 // not really a variable, though we implement it as one. The | 2540 // not really a variable, though we implement it as one. The |
| 2770 // subexpression does not have side effects. | 2541 // subexpression does not have side effects. |
| 2771 context()->Plug(is_this); | 2542 context()->Plug(is_this); |
| 2772 } else { | |
| 2773 // Non-global variable. Call the runtime to try to delete from the | |
| 2774 // context where the variable was introduced. | |
| 2775 __ Push(var->name()); | |
| 2776 __ CallRuntime(Runtime::kDeleteLookupSlot); | |
| 2777 context()->Plug(rax); | |
| 2778 } | 2543 } |
| 2779 } else { | 2544 } else { |
| 2780 // Result of deleting non-property, non-variable reference is true. | 2545 // Result of deleting non-property, non-variable reference is true. |
| 2781 // The subexpression may have side effects. | 2546 // The subexpression may have side effects. |
| 2782 VisitForEffect(expr->expression()); | 2547 VisitForEffect(expr->expression()); |
| 2783 context()->Plug(true); | 2548 context()->Plug(true); |
| 2784 } | 2549 } |
| 2785 break; | 2550 break; |
| 2786 } | 2551 } |
| 2787 | 2552 |
| (...skipping 676 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3464 DCHECK_EQ( | 3229 DCHECK_EQ( |
| 3465 isolate->builtins()->OnStackReplacement()->entry(), | 3230 isolate->builtins()->OnStackReplacement()->entry(), |
| 3466 Assembler::target_address_at(call_target_address, unoptimized_code)); | 3231 Assembler::target_address_at(call_target_address, unoptimized_code)); |
| 3467 return ON_STACK_REPLACEMENT; | 3232 return ON_STACK_REPLACEMENT; |
| 3468 } | 3233 } |
| 3469 | 3234 |
| 3470 } // namespace internal | 3235 } // namespace internal |
| 3471 } // namespace v8 | 3236 } // namespace v8 |
| 3472 | 3237 |
| 3473 #endif // V8_TARGET_ARCH_X64 | 3238 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |