OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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_ARM64 | 5 #if V8_TARGET_ARCH_ARM64 |
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 785 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
796 if (variable->binding_needs_init()) { | 796 if (variable->binding_needs_init()) { |
797 Comment cmnt(masm_, "[ VariableDeclaration"); | 797 Comment cmnt(masm_, "[ VariableDeclaration"); |
798 EmitDebugCheckDeclarationContext(variable); | 798 EmitDebugCheckDeclarationContext(variable); |
799 __ LoadRoot(x10, Heap::kTheHoleValueRootIndex); | 799 __ LoadRoot(x10, Heap::kTheHoleValueRootIndex); |
800 __ Str(x10, ContextMemOperand(cp, variable->index())); | 800 __ Str(x10, ContextMemOperand(cp, variable->index())); |
801 // No write barrier since the_hole_value is in old space. | 801 // No write barrier since the_hole_value is in old space. |
802 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS); | 802 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS); |
803 } | 803 } |
804 break; | 804 break; |
805 | 805 |
806 case VariableLocation::LOOKUP: { | 806 case VariableLocation::LOOKUP: |
807 Comment cmnt(masm_, "[ VariableDeclaration"); | |
808 DCHECK_EQ(VAR, variable->mode()); | |
809 DCHECK(!variable->binding_needs_init()); | |
810 __ Mov(x2, Operand(variable->name())); | |
811 __ Push(x2); | |
812 __ CallRuntime(Runtime::kDeclareEvalVar); | |
813 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS); | |
814 break; | |
815 } | |
816 | |
817 case VariableLocation::MODULE: | 807 case VariableLocation::MODULE: |
818 UNREACHABLE(); | 808 UNREACHABLE(); |
819 } | 809 } |
820 } | 810 } |
821 | 811 |
822 | 812 |
823 void FullCodeGenerator::VisitFunctionDeclaration( | 813 void FullCodeGenerator::VisitFunctionDeclaration( |
824 FunctionDeclaration* declaration) { | 814 FunctionDeclaration* declaration) { |
825 VariableProxy* proxy = declaration->proxy(); | 815 VariableProxy* proxy = declaration->proxy(); |
826 Variable* variable = proxy->var(); | 816 Variable* variable = proxy->var(); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
858 result_register(), | 848 result_register(), |
859 x2, | 849 x2, |
860 kLRHasBeenSaved, | 850 kLRHasBeenSaved, |
861 kDontSaveFPRegs, | 851 kDontSaveFPRegs, |
862 EMIT_REMEMBERED_SET, | 852 EMIT_REMEMBERED_SET, |
863 OMIT_SMI_CHECK); | 853 OMIT_SMI_CHECK); |
864 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS); | 854 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS); |
865 break; | 855 break; |
866 } | 856 } |
867 | 857 |
868 case VariableLocation::LOOKUP: { | 858 case VariableLocation::LOOKUP: |
869 Comment cmnt(masm_, "[ Function Declaration"); | |
870 __ Mov(x2, Operand(variable->name())); | |
871 PushOperand(x2); | |
872 // Push initial value for function declaration. | |
873 VisitForStackValue(declaration->fun()); | |
874 CallRuntimeWithOperands(Runtime::kDeclareEvalFunction); | |
875 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS); | |
876 break; | |
877 } | |
878 | |
879 case VariableLocation::MODULE: | 859 case VariableLocation::MODULE: |
880 UNREACHABLE(); | 860 UNREACHABLE(); |
881 } | 861 } |
882 } | 862 } |
883 | 863 |
884 | 864 |
885 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 865 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
886 // Call the runtime to declare the globals. | 866 // Call the runtime to declare the globals. |
887 __ Mov(x11, Operand(pairs)); | 867 __ Mov(x11, Operand(pairs)); |
888 Register flags = xzr; | 868 Register flags = xzr; |
(...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1164 | 1144 |
1165 void FullCodeGenerator::EmitSetHomeObjectAccumulator(Expression* initializer, | 1145 void FullCodeGenerator::EmitSetHomeObjectAccumulator(Expression* initializer, |
1166 int offset, | 1146 int offset, |
1167 FeedbackVectorSlot slot) { | 1147 FeedbackVectorSlot slot) { |
1168 DCHECK(NeedsHomeObject(initializer)); | 1148 DCHECK(NeedsHomeObject(initializer)); |
1169 __ Move(StoreDescriptor::ReceiverRegister(), x0); | 1149 __ Move(StoreDescriptor::ReceiverRegister(), x0); |
1170 __ Peek(StoreDescriptor::ValueRegister(), offset * kPointerSize); | 1150 __ Peek(StoreDescriptor::ValueRegister(), offset * kPointerSize); |
1171 CallStoreIC(slot, isolate()->factory()->home_object_symbol()); | 1151 CallStoreIC(slot, isolate()->factory()->home_object_symbol()); |
1172 } | 1152 } |
1173 | 1153 |
1174 | |
1175 void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy, | |
1176 TypeofMode typeof_mode, | |
1177 Label* slow) { | |
1178 Register current = cp; | |
1179 Register next = x10; | |
1180 Register temp = x11; | |
1181 | |
1182 int to_check = scope()->ContextChainLengthUntilOutermostSloppyEval(); | |
1183 for (Scope* s = scope(); to_check > 0; s = s->outer_scope()) { | |
1184 if (!s->NeedsContext()) continue; | |
1185 if (s->calls_sloppy_eval()) { | |
1186 // Check that extension is "the hole". | |
1187 __ Ldr(temp, ContextMemOperand(current, Context::EXTENSION_INDEX)); | |
1188 __ JumpIfNotRoot(temp, Heap::kTheHoleValueRootIndex, slow); | |
1189 } | |
1190 // Load next context in chain. | |
1191 __ Ldr(next, ContextMemOperand(current, Context::PREVIOUS_INDEX)); | |
1192 // Walk the rest of the chain without clobbering cp. | |
1193 current = next; | |
1194 to_check--; | |
1195 } | |
1196 | |
1197 // All extension objects were empty and it is safe to use a normal global | |
1198 // load machinery. | |
1199 EmitGlobalVariableLoad(proxy, typeof_mode); | |
1200 } | |
1201 | |
1202 | |
1203 MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var, | |
1204 Label* slow) { | |
1205 DCHECK(var->IsContextSlot()); | |
1206 Register context = cp; | |
1207 Register next = x10; | |
1208 Register temp = x11; | |
1209 | |
1210 for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) { | |
1211 if (s->NeedsContext()) { | |
1212 if (s->calls_sloppy_eval()) { | |
1213 // Check that extension is "the hole". | |
1214 __ Ldr(temp, ContextMemOperand(context, Context::EXTENSION_INDEX)); | |
1215 __ JumpIfNotRoot(temp, Heap::kTheHoleValueRootIndex, slow); | |
1216 } | |
1217 __ Ldr(next, ContextMemOperand(context, Context::PREVIOUS_INDEX)); | |
1218 // Walk the rest of the chain without clobbering cp. | |
1219 context = next; | |
1220 } | |
1221 } | |
1222 // Check that last extension is "the hole". | |
1223 __ Ldr(temp, ContextMemOperand(context, Context::EXTENSION_INDEX)); | |
1224 __ JumpIfNotRoot(temp, Heap::kTheHoleValueRootIndex, slow); | |
1225 | |
1226 // This function is used only for loads, not stores, so it's safe to | |
1227 // return an cp-based operand (the write barrier cannot be allowed to | |
1228 // destroy the cp register). | |
1229 return ContextMemOperand(context, var->index()); | |
1230 } | |
1231 | |
1232 | |
1233 void FullCodeGenerator::EmitDynamicLookupFastCase(VariableProxy* proxy, | |
1234 TypeofMode typeof_mode, | |
1235 Label* slow, Label* done) { | |
1236 // Generate fast-case code for variables that might be shadowed by | |
1237 // eval-introduced variables. Eval is used a lot without | |
1238 // introducing variables. In those cases, we do not want to | |
1239 // perform a runtime call for all variables in the scope | |
1240 // containing the eval. | |
1241 Variable* var = proxy->var(); | |
1242 if (var->mode() == DYNAMIC_GLOBAL) { | |
1243 EmitLoadGlobalCheckExtensions(proxy, typeof_mode, slow); | |
1244 __ B(done); | |
1245 } else if (var->mode() == DYNAMIC_LOCAL) { | |
1246 Variable* local = var->local_if_not_shadowed(); | |
1247 __ Ldr(x0, ContextSlotOperandCheckExtensions(local, slow)); | |
1248 if (local->binding_needs_init()) { | |
1249 __ JumpIfNotRoot(x0, Heap::kTheHoleValueRootIndex, done); | |
1250 __ Mov(x0, Operand(var->name())); | |
1251 __ Push(x0); | |
1252 __ CallRuntime(Runtime::kThrowReferenceError); | |
1253 } else { | |
1254 __ B(done); | |
1255 } | |
1256 } | |
1257 } | |
1258 | |
1259 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy, | 1154 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy, |
1260 TypeofMode typeof_mode) { | 1155 TypeofMode typeof_mode) { |
1261 // Record position before possible IC call. | 1156 // Record position before possible IC call. |
1262 SetExpressionPosition(proxy); | 1157 SetExpressionPosition(proxy); |
1263 PrepareForBailoutForId(proxy->BeforeId(), BailoutState::NO_REGISTERS); | 1158 PrepareForBailoutForId(proxy->BeforeId(), BailoutState::NO_REGISTERS); |
1264 Variable* var = proxy->var(); | 1159 Variable* var = proxy->var(); |
1265 | 1160 |
1266 // Three cases: global variables, lookup variables, and all other types of | 1161 // Two cases: global variables and all other types of variables. |
1267 // variables. | |
1268 switch (var->location()) { | 1162 switch (var->location()) { |
1269 case VariableLocation::UNALLOCATED: { | 1163 case VariableLocation::UNALLOCATED: { |
1270 Comment cmnt(masm_, "Global variable"); | 1164 Comment cmnt(masm_, "Global variable"); |
1271 EmitGlobalVariableLoad(proxy, typeof_mode); | 1165 EmitGlobalVariableLoad(proxy, typeof_mode); |
1272 context()->Plug(x0); | 1166 context()->Plug(x0); |
1273 break; | 1167 break; |
1274 } | 1168 } |
1275 | 1169 |
1276 case VariableLocation::PARAMETER: | 1170 case VariableLocation::PARAMETER: |
1277 case VariableLocation::LOCAL: | 1171 case VariableLocation::LOCAL: |
(...skipping 12 matching lines...) Expand all Loading... |
1290 __ Push(x0); | 1184 __ Push(x0); |
1291 __ CallRuntime(Runtime::kThrowReferenceError); | 1185 __ CallRuntime(Runtime::kThrowReferenceError); |
1292 __ Bind(&done); | 1186 __ Bind(&done); |
1293 context()->Plug(x0); | 1187 context()->Plug(x0); |
1294 break; | 1188 break; |
1295 } | 1189 } |
1296 context()->Plug(var); | 1190 context()->Plug(var); |
1297 break; | 1191 break; |
1298 } | 1192 } |
1299 | 1193 |
1300 case VariableLocation::LOOKUP: { | 1194 case VariableLocation::LOOKUP: |
1301 Label done, slow; | |
1302 // Generate code for loading from variables potentially shadowed by | |
1303 // eval-introduced variables. | |
1304 EmitDynamicLookupFastCase(proxy, typeof_mode, &slow, &done); | |
1305 __ Bind(&slow); | |
1306 Comment cmnt(masm_, "Lookup variable"); | |
1307 __ Push(var->name()); | |
1308 Runtime::FunctionId function_id = | |
1309 typeof_mode == NOT_INSIDE_TYPEOF | |
1310 ? Runtime::kLoadLookupSlot | |
1311 : Runtime::kLoadLookupSlotInsideTypeof; | |
1312 __ CallRuntime(function_id); | |
1313 __ Bind(&done); | |
1314 context()->Plug(x0); | |
1315 break; | |
1316 } | |
1317 | |
1318 case VariableLocation::MODULE: | 1195 case VariableLocation::MODULE: |
1319 UNREACHABLE(); | 1196 UNREACHABLE(); |
1320 } | 1197 } |
1321 } | 1198 } |
1322 | 1199 |
1323 | 1200 |
1324 void FullCodeGenerator::EmitAccessor(ObjectLiteralProperty* property) { | 1201 void FullCodeGenerator::EmitAccessor(ObjectLiteralProperty* property) { |
1325 Expression* expression = (property == NULL) ? NULL : property->value(); | 1202 Expression* expression = (property == NULL) ? NULL : property->value(); |
1326 if (expression == NULL) { | 1203 if (expression == NULL) { |
1327 __ LoadRoot(x10, Heap::kNullValueRootIndex); | 1204 __ LoadRoot(x10, Heap::kNullValueRootIndex); |
(...skipping 703 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2031 __ Ldr(x10, location); | 1908 __ Ldr(x10, location); |
2032 __ JumpIfRoot(x10, Heap::kTheHoleValueRootIndex, &uninitialized_this); | 1909 __ JumpIfRoot(x10, Heap::kTheHoleValueRootIndex, &uninitialized_this); |
2033 __ Mov(x0, Operand(var->name())); | 1910 __ Mov(x0, Operand(var->name())); |
2034 __ Push(x0); | 1911 __ Push(x0); |
2035 __ CallRuntime(Runtime::kThrowReferenceError); | 1912 __ CallRuntime(Runtime::kThrowReferenceError); |
2036 __ bind(&uninitialized_this); | 1913 __ bind(&uninitialized_this); |
2037 EmitStoreToStackLocalOrContextSlot(var, location); | 1914 EmitStoreToStackLocalOrContextSlot(var, location); |
2038 | 1915 |
2039 } else { | 1916 } else { |
2040 DCHECK(var->mode() != CONST || op == Token::INIT); | 1917 DCHECK(var->mode() != CONST || op == Token::INIT); |
2041 if (var->IsLookupSlot()) { | 1918 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); |
2042 // Assignment to var. | 1919 DCHECK(!var->IsLookupSlot()); |
2043 __ Push(var->name()); | 1920 // Assignment to var or initializing assignment to let/const in harmony |
2044 __ Push(x0); | 1921 // mode. |
2045 __ CallRuntime(is_strict(language_mode()) | 1922 MemOperand location = VarOperand(var, x1); |
2046 ? Runtime::kStoreLookupSlot_Strict | 1923 if (FLAG_debug_code && var->mode() == LET && op == Token::INIT) { |
2047 : Runtime::kStoreLookupSlot_Sloppy); | 1924 __ Ldr(x10, location); |
2048 } else { | 1925 __ CompareRoot(x10, Heap::kTheHoleValueRootIndex); |
2049 // Assignment to var or initializing assignment to let/const in harmony | 1926 __ Check(eq, kLetBindingReInitialization); |
2050 // mode. | |
2051 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); | |
2052 MemOperand location = VarOperand(var, x1); | |
2053 if (FLAG_debug_code && var->mode() == LET && op == Token::INIT) { | |
2054 __ Ldr(x10, location); | |
2055 __ CompareRoot(x10, Heap::kTheHoleValueRootIndex); | |
2056 __ Check(eq, kLetBindingReInitialization); | |
2057 } | |
2058 EmitStoreToStackLocalOrContextSlot(var, location); | |
2059 } | 1927 } |
| 1928 EmitStoreToStackLocalOrContextSlot(var, location); |
2060 } | 1929 } |
2061 } | 1930 } |
2062 | 1931 |
2063 | 1932 |
2064 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { | 1933 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { |
2065 ASM_LOCATION("FullCodeGenerator::EmitNamedPropertyAssignment"); | 1934 ASM_LOCATION("FullCodeGenerator::EmitNamedPropertyAssignment"); |
2066 // Assignment to a property, using a named store IC. | 1935 // Assignment to a property, using a named store IC. |
2067 Property* prop = expr->target()->AsProperty(); | 1936 Property* prop = expr->target()->AsProperty(); |
2068 DCHECK(prop != NULL); | 1937 DCHECK(prop != NULL); |
2069 DCHECK(prop->key()->IsLiteral()); | 1938 DCHECK(prop->key()->IsLiteral()); |
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2288 __ Peek(x1, (arg_count + 1) * kXRegSize); | 2157 __ Peek(x1, (arg_count + 1) * kXRegSize); |
2289 __ Mov(x0, arg_count); | 2158 __ Mov(x0, arg_count); |
2290 CallIC(code); | 2159 CallIC(code); |
2291 OperandStackDepthDecrement(arg_count + 1); | 2160 OperandStackDepthDecrement(arg_count + 1); |
2292 | 2161 |
2293 RecordJSReturnSite(expr); | 2162 RecordJSReturnSite(expr); |
2294 RestoreContext(); | 2163 RestoreContext(); |
2295 context()->DropAndPlug(1, x0); | 2164 context()->DropAndPlug(1, x0); |
2296 } | 2165 } |
2297 | 2166 |
2298 void FullCodeGenerator::EmitResolvePossiblyDirectEval(Call* expr) { | |
2299 int arg_count = expr->arguments()->length(); | |
2300 ASM_LOCATION("FullCodeGenerator::EmitResolvePossiblyDirectEval"); | |
2301 // Prepare to push a copy of the first argument or undefined if it doesn't | |
2302 // exist. | |
2303 if (arg_count > 0) { | |
2304 __ Peek(x9, arg_count * kXRegSize); | |
2305 } else { | |
2306 __ LoadRoot(x9, Heap::kUndefinedValueRootIndex); | |
2307 } | |
2308 | |
2309 __ Ldr(x10, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); | |
2310 | |
2311 // Prepare to push the language mode. | |
2312 __ Mov(x11, Smi::FromInt(language_mode())); | |
2313 // Prepare to push the start position of the scope the calls resides in. | |
2314 __ Mov(x12, Smi::FromInt(scope()->start_position())); | |
2315 // Prepare to push the source position of the eval call. | |
2316 __ Mov(x13, Smi::FromInt(expr->position())); | |
2317 | |
2318 // Push. | |
2319 __ Push(x9, x10, x11, x12, x13); | |
2320 | |
2321 // Do the runtime call. | |
2322 __ CallRuntime(Runtime::kResolvePossiblyDirectEval); | |
2323 } | |
2324 | |
2325 | |
2326 // See http://www.ecma-international.org/ecma-262/6.0/#sec-function-calls. | |
2327 void FullCodeGenerator::PushCalleeAndWithBaseObject(Call* expr) { | |
2328 VariableProxy* callee = expr->expression()->AsVariableProxy(); | |
2329 if (callee->var()->IsLookupSlot()) { | |
2330 Label slow, done; | |
2331 SetExpressionPosition(callee); | |
2332 // Generate code for loading from variables potentially shadowed | |
2333 // by eval-introduced variables. | |
2334 EmitDynamicLookupFastCase(callee, NOT_INSIDE_TYPEOF, &slow, &done); | |
2335 | |
2336 __ Bind(&slow); | |
2337 // Call the runtime to find the function to call (returned in x0) | |
2338 // and the object holding it (returned in x1). | |
2339 __ Push(callee->name()); | |
2340 __ CallRuntime(Runtime::kLoadLookupSlotForCall); | |
2341 PushOperands(x0, x1); // Receiver, function. | |
2342 PrepareForBailoutForId(expr->LookupId(), BailoutState::NO_REGISTERS); | |
2343 | |
2344 // If fast case code has been generated, emit code to push the | |
2345 // function and receiver and have the slow path jump around this | |
2346 // code. | |
2347 if (done.is_linked()) { | |
2348 Label call; | |
2349 __ B(&call); | |
2350 __ Bind(&done); | |
2351 // Push function. | |
2352 // The receiver is implicitly the global receiver. Indicate this | |
2353 // by passing the undefined to the call function stub. | |
2354 __ LoadRoot(x1, Heap::kUndefinedValueRootIndex); | |
2355 __ Push(x0, x1); | |
2356 __ Bind(&call); | |
2357 } | |
2358 } else { | |
2359 VisitForStackValue(callee); | |
2360 // refEnv.WithBaseObject() | |
2361 __ LoadRoot(x10, Heap::kUndefinedValueRootIndex); | |
2362 PushOperand(x10); // Reserved receiver slot. | |
2363 } | |
2364 } | |
2365 | |
2366 | |
2367 void FullCodeGenerator::EmitPossiblyEvalCall(Call* expr) { | |
2368 ASM_LOCATION("FullCodeGenerator::EmitPossiblyEvalCall"); | |
2369 // In a call to eval, we first call Runtime_ResolvePossiblyDirectEval | |
2370 // to resolve the function we need to call. Then we call the resolved | |
2371 // function using the given arguments. | |
2372 ZoneList<Expression*>* args = expr->arguments(); | |
2373 int arg_count = args->length(); | |
2374 | |
2375 PushCalleeAndWithBaseObject(expr); | |
2376 | |
2377 // Push the arguments. | |
2378 for (int i = 0; i < arg_count; i++) { | |
2379 VisitForStackValue(args->at(i)); | |
2380 } | |
2381 | |
2382 // Push a copy of the function (found below the arguments) and | |
2383 // resolve eval. | |
2384 __ Peek(x10, (arg_count + 1) * kPointerSize); | |
2385 __ Push(x10); | |
2386 EmitResolvePossiblyDirectEval(expr); | |
2387 | |
2388 // Touch up the stack with the resolved function. | |
2389 __ Poke(x0, (arg_count + 1) * kPointerSize); | |
2390 | |
2391 PrepareForBailoutForId(expr->EvalId(), BailoutState::NO_REGISTERS); | |
2392 | |
2393 // Record source position for debugger. | |
2394 SetCallPosition(expr); | |
2395 | |
2396 // Call the evaluated function. | |
2397 Handle<Code> code = CodeFactory::CallIC(isolate(), ConvertReceiverMode::kAny, | |
2398 expr->tail_call_mode()) | |
2399 .code(); | |
2400 __ Mov(x3, SmiFromSlot(expr->CallFeedbackICSlot())); | |
2401 __ Peek(x1, (arg_count + 1) * kXRegSize); | |
2402 __ Mov(x0, arg_count); | |
2403 __ Call(code, RelocInfo::CODE_TARGET); | |
2404 OperandStackDepthDecrement(arg_count + 1); | |
2405 RecordJSReturnSite(expr); | |
2406 RestoreContext(); | |
2407 context()->DropAndPlug(1, x0); | |
2408 } | |
2409 | |
2410 | |
2411 void FullCodeGenerator::VisitCallNew(CallNew* expr) { | 2167 void FullCodeGenerator::VisitCallNew(CallNew* expr) { |
2412 Comment cmnt(masm_, "[ CallNew"); | 2168 Comment cmnt(masm_, "[ CallNew"); |
2413 // According to ECMA-262, section 11.2.2, page 44, the function | 2169 // According to ECMA-262, section 11.2.2, page 44, the function |
2414 // expression in new calls must be evaluated before the | 2170 // expression in new calls must be evaluated before the |
2415 // arguments. | 2171 // arguments. |
2416 | 2172 |
2417 // Push constructor on the stack. If it's not a function it's used as | 2173 // Push constructor on the stack. If it's not a function it's used as |
2418 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is | 2174 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is |
2419 // ignored. | 2175 // ignored. |
2420 DCHECK(!expr->expression()->IsSuperPropertyReference()); | 2176 DCHECK(!expr->expression()->IsSuperPropertyReference()); |
(...skipping 423 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2844 // Delete of an unqualified identifier is disallowed in strict mode but | 2600 // Delete of an unqualified identifier is disallowed in strict mode but |
2845 // "delete this" is allowed. | 2601 // "delete this" is allowed. |
2846 bool is_this = var->is_this(); | 2602 bool is_this = var->is_this(); |
2847 DCHECK(is_sloppy(language_mode()) || is_this); | 2603 DCHECK(is_sloppy(language_mode()) || is_this); |
2848 if (var->IsUnallocated()) { | 2604 if (var->IsUnallocated()) { |
2849 __ LoadGlobalObject(x12); | 2605 __ LoadGlobalObject(x12); |
2850 __ Mov(x11, Operand(var->name())); | 2606 __ Mov(x11, Operand(var->name())); |
2851 __ Push(x12, x11); | 2607 __ Push(x12, x11); |
2852 __ CallRuntime(Runtime::kDeleteProperty_Sloppy); | 2608 __ CallRuntime(Runtime::kDeleteProperty_Sloppy); |
2853 context()->Plug(x0); | 2609 context()->Plug(x0); |
2854 } else if (var->IsStackAllocated() || var->IsContextSlot()) { | 2610 } else { |
| 2611 DCHECK(!var->IsLookupSlot()); |
| 2612 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); |
2855 // Result of deleting non-global, non-dynamic variables is false. | 2613 // Result of deleting non-global, non-dynamic variables is false. |
2856 // The subexpression does not have side effects. | 2614 // The subexpression does not have side effects. |
2857 context()->Plug(is_this); | 2615 context()->Plug(is_this); |
2858 } else { | |
2859 // Non-global variable. Call the runtime to try to delete from the | |
2860 // context where the variable was introduced. | |
2861 __ Push(var->name()); | |
2862 __ CallRuntime(Runtime::kDeleteLookupSlot); | |
2863 context()->Plug(x0); | |
2864 } | 2616 } |
2865 } else { | 2617 } else { |
2866 // Result of deleting non-property, non-variable reference is true. | 2618 // Result of deleting non-property, non-variable reference is true. |
2867 // The subexpression may have side effects. | 2619 // The subexpression may have side effects. |
2868 VisitForEffect(expr->expression()); | 2620 VisitForEffect(expr->expression()); |
2869 context()->Plug(true); | 2621 context()->Plug(true); |
2870 } | 2622 } |
2871 break; | 2623 break; |
2872 break; | 2624 break; |
2873 } | 2625 } |
(...skipping 770 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3644 } | 3396 } |
3645 | 3397 |
3646 return INTERRUPT; | 3398 return INTERRUPT; |
3647 } | 3399 } |
3648 | 3400 |
3649 | 3401 |
3650 } // namespace internal | 3402 } // namespace internal |
3651 } // namespace v8 | 3403 } // namespace v8 |
3652 | 3404 |
3653 #endif // V8_TARGET_ARCH_ARM64 | 3405 #endif // V8_TARGET_ARCH_ARM64 |
OLD | NEW |